• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 13524247616

25 Feb 2025 03:00PM UTC coverage: 50.292% (-0.07%) from 50.362%
13524247616

Pull #1737

github

web-flow
Merge 8cbf07576 into 73dd50d9b
Pull Request #1737: Fix testCheats when running standalone

22360 of 44460 relevant lines covered (50.29%)

35116.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

3.77
/libs/s25main/TerrainRenderer.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "TerrainRenderer.h"
6
#include "Loader.h"
7
#include "RttrForeachPt.h"
8
#include "Settings.h"
9
#include "drivers/VideoDriverWrapper.h"
10
#include "helpers/EnumArray.h"
11
#include "helpers/Range.h"
12
#include "helpers/containerUtils.h"
13
#include "network/GameClient.h"
14
#include "ogl/glArchivItem_Bitmap.h"
15
#include "world/GameWorldBase.h"
16
#include "world/GameWorldViewer.h"
17
#include "world/MapGeometry.h"
18
#include "gameData/MapConsts.h"
19
#include "gameData/TerrainDesc.h"
20
#include "libsiedler2/Archiv.h"
21
#include "libsiedler2/ArchivItem_PaletteAnimation.h"
22
#include "s25util/Log.h"
23
#include <glad/glad.h>
24
#include <boost/pointer_cast.hpp>
25
#include <boost/range/adaptor/indexed.hpp>
26
#include <cstdlib>
27
#include <set>
28

29
/* Terrain rendering works like that:
30
 * Every point is associated with 2 triangles:
31
 *    x____
32
 *   /0\ 1/
33
 *  /___\/
34
 *
35
 * So each point in Vertex-Array stores:
36
 *      its coordinates, the 2 textures, the color (shade) and border information (TODO: What are they?)
37
 *
38
 * For OGL we have one entry per triangle in:
39
 *  - gl_vertices: Vertex (position) (All 3 coordinates of a triangle)
40
 *  - gl_texCoords: Texture coordinates for the triangle
41
 *  - gl_colors: Color (shade) at each point of the triangle
42
 *
43
 * Drawing then binds a texture and draws all adjacent vertices with the same texture in one call by
44
 * providing an index and a count into the above arrays.
45
 */
46

47
glArchivItem_Bitmap* new_clone(const glArchivItem_Bitmap& bmp)
×
48
{
49
    return dynamic_cast<glArchivItem_Bitmap*>(bmp.clone());
×
50
}
51

52
TerrainRenderer::TerrainRenderer() : size_(0, 0) {}
22✔
53
TerrainRenderer::~TerrainRenderer() = default;
22✔
54

55
static constexpr unsigned getFlatIndex(DescIdx<LandscapeDesc> ls, LandRoadType road)
×
56
{
57
    return ls.value * helpers::NumEnumValues_v<LandRoadType> + rttr::enum_cast(road);
×
58
}
59

60
PointF TerrainRenderer::GetNeighbourVertexPos(MapPoint pt, const Direction dir) const
×
61
{
62
    // Note: We want the real neighbour point which might be outside of the map to get the offset right
63
    Position ptNb = ::GetNeighbour(Position(pt), dir);
×
64

65
    Position offset;
×
66
    MapPoint t = ConvertCoords(ptNb, &offset);
×
67

68
    return GetVertexPos(t) + PointF(offset);
×
69
}
70

71
PointF TerrainRenderer::GetNeighbourBorderPos(const MapPoint pt, const unsigned char triangle,
×
72
                                              const Direction dir) const
73
{
74
    // Note: We want the real neighbour point which might be outside of the map to get the offset right
75
    Position ptNb = ::GetNeighbour(Position(pt), dir);
×
76

77
    Position offset;
×
78
    MapPoint t = ConvertCoords(ptNb, &offset);
×
79

80
    return GetBorderPos(t, triangle) + PointF(offset);
×
81
}
82

83
void TerrainRenderer::LoadTextures(const WorldDescription& desc)
×
84
{
85
    terrainTextures.clear();
×
86
    edgeTextures.clear();
×
87
    roadTextures.clear();
×
88

89
    std::set<DescIdx<LandscapeDesc>> usedLandscapes;
×
90
    std::set<DescIdx<TerrainDesc>> usedTerrains;
×
91
    std::set<DescIdx<EdgeDesc>> usedEdges;
×
92
    using TerrainPair = std::array<DescIdx<TerrainDesc>, 2>;
93
    for(const TerrainPair& ts : terrain)
×
94
    {
95
        for(const DescIdx<TerrainDesc>& tIdx : ts)
×
96
        {
97
            if(!helpers::contains(usedTerrains, tIdx))
×
98
            {
99
                usedTerrains.insert(tIdx);
×
100
                DescIdx<EdgeDesc> edge = desc.get(tIdx).edgeType;
×
101
                if(!!edge)
×
102
                    usedEdges.insert(edge);
×
103
                DescIdx<LandscapeDesc> lt = desc.get(tIdx).landscape;
×
104
                if(!!lt)
×
105
                    usedLandscapes.insert(lt);
×
106
            }
107
        }
108
    }
109
    terrainTextures.resize(usedTerrains.rbegin()->value + 1);
×
110
    edgeTextures.resize(usedEdges.rbegin()->value + 1);
×
111
    roadTextures.resize((usedLandscapes.rbegin()->value + 1) * helpers::NumEnumValues_v<LandRoadType>);
×
112

113
    for(DescIdx<TerrainDesc> curIdx : usedTerrains)
×
114
    {
115
        const TerrainDesc& cur = desc.get(curIdx);
×
116
        const auto textureName = ResourceId::make(bfs::path(cur.texturePath));
×
117
        glArchivItem_Bitmap* texBmp = LOADER.GetImageN(textureName, 0);
×
118
        if(!texBmp)
×
119
            throw std::runtime_error("Invalid texture '" + cur.texturePath + "' for terrain '" + cur.name + "'");
×
120
        if(cur.palAnimIdx >= 0)
×
121
        {
122
            libsiedler2::ArchivItem* animItem = LOADER.GetArchive(textureName)[cur.palAnimIdx];
×
123
            if(!texBmp->getPalette() || !animItem || animItem->getBobType() != libsiedler2::BobType::PaletteAnim)
×
124
            {
125
                LOG.write("Invalid palette animation '%1%' for '%2%'") % unsigned(cur.palAnimIdx) % cur.name;
×
126
                terrainTextures[curIdx].textures.push_back(LOADER.ExtractTexture(*texBmp, cur.posInTexture));
×
127
            } else
128
            {
129
                auto& anim = static_cast<libsiedler2::ArchivItem_PaletteAnimation&>(*animItem);
×
130
                std::unique_ptr<libsiedler2::Archiv> textures = LOADER.ExtractAnimatedTexture(
×
131
                  *texBmp, cur.posInTexture, anim.firstClr, anim.lastClr - anim.firstClr + 1);
×
132
                for(unsigned i = 0; i < textures->size(); i++)
×
133
                {
134
                    terrainTextures[curIdx].textures.push_back(
×
135
                      boost::dynamic_pointer_cast<glArchivItem_Bitmap>(textures->release(i)));
×
136
                }
137
            }
138
        } else
139
        {
140
            terrainTextures[curIdx].textures.push_back(LOADER.ExtractTexture(*texBmp, cur.posInTexture));
×
141
        }
142
        // Initialize OpenGL textures
143
        for(glArchivItem_Bitmap& bmp : terrainTextures[curIdx].textures)
×
144
            bmp.GetTexture();
×
145
        TerrainDesc::Triangle trianglePos = cur.GetRSUTriangle();
×
146
        Position texOrigin = cur.posInTexture.getOrigin();
×
147
        const glArchivItem_Bitmap& texture = terrainTextures[curIdx].textures[0];
×
148
        Triangle& rsuCoord = terrainTextures[curIdx].rsuCoords;
×
149
        PointF texSize(texture.GetTexSize());
×
150
        rsuCoord[0] = PointF(trianglePos.tip - texOrigin);
×
151
        rsuCoord[1] = PointF(trianglePos.left - texOrigin);
×
152
        rsuCoord[2] = PointF(trianglePos.right - texOrigin);
×
153
        // Normalize to texture size
154
        for(unsigned i = 0; i < 3; i++)
×
155
            rsuCoord[i] /= texSize;
×
156

157
        Triangle& usdCoord = terrainTextures[curIdx].usdCoords;
×
158
        trianglePos = cur.GetUSDTriangle();
×
159
        usdCoord[0] = PointF(trianglePos.left - texOrigin);
×
160
        usdCoord[1] = PointF(trianglePos.tip - texOrigin);
×
161
        usdCoord[2] = PointF(trianglePos.right - texOrigin);
×
162
        // Normalize to texture size
163
        for(unsigned i = 0; i < 3; i++)
×
164
            usdCoord[i] /= texSize;
×
165
    }
166
    for(DescIdx<EdgeDesc> curIdx : usedEdges)
×
167
    {
168
        const EdgeDesc& cur = desc.get(curIdx);
×
169
        const auto textureName = ResourceId::make(bfs::path(cur.texturePath));
×
170
        glArchivItem_Bitmap* texBmp = LOADER.GetImageN(textureName, 0);
×
171
        if(!texBmp)
×
172
            throw std::runtime_error("Invalid texture '" + cur.texturePath + "' for edge '" + cur.name + "'");
×
173
        edgeTextures[curIdx] = LOADER.ExtractTexture(*texBmp, cur.posInTexture);
×
174
        edgeTextures[curIdx]->GetTexture(); // Init texture
×
175
    }
176
    for(DescIdx<LandscapeDesc> curIdx : usedLandscapes)
×
177
    {
178
        const LandscapeDesc& cur = desc.get(curIdx);
×
179
        for(const auto i : helpers::enumRange<LandRoadType>())
×
180
        {
181
            const auto textureName = ResourceId::make(bfs::path(cur.roadTexDesc[i].texturePath));
×
182
            glArchivItem_Bitmap* texBmp = LOADER.GetImageN(textureName, 0);
×
183
            if(!texBmp)
×
184
                throw std::runtime_error("Invalid texture '" + cur.roadTexDesc[i].texturePath
×
185
                                         + "' for road in landscape '" + cur.name + "'");
×
186
            roadTextures[getFlatIndex(curIdx, i)] = LOADER.ExtractTexture(*texBmp, cur.roadTexDesc[i].posInTexture);
×
187
            roadTextures[getFlatIndex(curIdx, i)]->GetTexture(); // Init texture
×
188
        }
189
    }
190
}
×
191

192
void TerrainRenderer::GenerateVertices(const GameWorldViewer& gwv)
×
193
{
194
    // Terrain generieren
195
    RTTR_FOREACH_PT(MapPoint, size_)
×
196
    {
197
        UpdateVertexPos(pt, gwv);
×
198
        UpdateVertexColor(pt, gwv);
×
199
        LoadVertexTerrain(pt, gwv);
×
200
    }
201

202
    // Ränder generieren
203
    RTTR_FOREACH_PT(MapPoint, size_)
×
204
        UpdateBorderVertex(pt);
×
205
}
×
206

207
void TerrainRenderer::UpdateVertexPos(const MapPoint pt, const GameWorldViewer& gwv)
×
208
{
209
    GetVertex(pt).pos = PointF(gwv.GetWorld().GetNodePos(pt));
×
210
}
×
211

212
void TerrainRenderer::UpdateVertexColor(const MapPoint pt, const GameWorldViewer& gwv)
×
213
{
214
    auto shadow = static_cast<float>(gwv.GetNode(pt).shadow);
×
215
    float clr = -1.f / (256.f * 256.f) * shadow * shadow + 1.f / 90.f * shadow + 0.38f;
×
216
    switch(gwv.GetVisibility(pt))
×
217
    {
218
        case Visibility::Invisible:
×
219
            // Unsichtbar -> schwarz
220
            GetVertex(pt).color = 0.0f;
×
221
            break;
×
222
        case Visibility::FogOfWar:
×
223
            // Fog of War -> abgedunkelt
224
            GetVertex(pt).color = clr / 4.f;
×
225
            break;
×
226
        case Visibility::Visible:
×
227
            // Normal sichtbar
228
            GetVertex(pt).color = clr / 2.f;
×
229
            break;
×
230
    }
231
}
×
232

233
void TerrainRenderer::LoadVertexTerrain(const MapPoint pt, const GameWorldViewer& gwv)
×
234
{
235
    const MapNode& node = gwv.GetNode(pt);
×
236
    terrain[GetVertexIdx(pt)][0] = node.t1;
×
237
    terrain[GetVertexIdx(pt)][1] = node.t2;
×
238
}
×
239

240
void TerrainRenderer::UpdateBorderVertex(const MapPoint pt)
×
241
{
242
    Vertex& vertex = GetVertex(pt);
×
243
    vertex.borderPos[0] = (GetNeighbourVertexPos(pt, Direction::SouthWest) + GetVertexPos(pt)
×
244
                           + GetNeighbourVertexPos(pt, Direction::SouthEast))
×
245
                          / 3.0f;
×
246
    vertex.borderColor[0] = (GetColor(GetNeighbour(pt, Direction::SouthWest)) + GetColor(pt)
×
247
                             + GetColor(GetNeighbour(pt, Direction::SouthEast)))
×
248
                            / 3.0f;
×
249

250
    vertex.borderPos[1] =
×
251
      (GetNeighbourVertexPos(pt, Direction::East) + GetVertexPos(pt) + GetNeighbourVertexPos(pt, Direction::SouthEast))
×
252
      / 3.0f;
×
253
    vertex.borderColor[1] =
×
254
      (GetColor(GetNeighbour(pt, Direction::East)) + GetColor(pt) + GetColor(GetNeighbour(pt, Direction::SouthEast)))
×
255
      / 3.0f;
×
256
}
×
257

258
void TerrainRenderer::Init(const MapExtent& size)
1✔
259
{
260
    size_ = size;
1✔
261
    // Clear first, so they are default-initialized
262
    vertices.clear();
1✔
263
    terrain.clear();
1✔
264
    borders.clear();
1✔
265
    vertices.resize(size_.x * size_.y);
1✔
266
    terrain.resize(vertices.size());
1✔
267
    borders.resize(size_.x * size_.y);
1✔
268

269
    gl_vertices.clear();
1✔
270
    gl_texcoords.clear();
1✔
271
    gl_colors.clear();
1✔
272
    // We have 2 triangles per map point
273
    gl_vertices.resize(vertices.size() * 2);
1✔
274
    gl_texcoords.resize(gl_vertices.size());
1✔
275
    gl_colors.resize(gl_vertices.size());
1✔
276
}
1✔
277

278
/// Get the edge type description index that t1 draws over t2. If none a falsy index is returned
279
static DescIdx<EdgeDesc> GetEdgeType(const TerrainDesc& t1, const TerrainDesc& t2)
×
280
{
281
    if(!t1.edgeType || t1.edgePriority <= t2.edgePriority)
×
282
        return {};
×
283
    else
284
        return t1.edgeType;
×
285
}
286

287
/**
288
 *  erzeugt die OpenGL-Vertices.
289
 */
290
void TerrainRenderer::GenerateOpenGL(const GameWorldViewer& gwv)
×
291
{
292
    const GameWorldBase& world = gwv.GetWorld();
×
293
    Init(world.GetSize());
×
294

295
    GenerateVertices(gwv);
×
296
    const WorldDescription& desc = world.GetDescription();
×
297
    LoadTextures(desc);
×
298

299
    // Add extra vertices for borders
300
    unsigned numTriangles = gl_vertices.size();
×
301
    RTTR_FOREACH_PT(MapPoint, size_)
×
302
    {
303
        const unsigned pos = GetVertexIdx(pt);
×
304
        const TerrainDesc& t1 = desc.get(terrain[pos][0]);
×
305
        const TerrainDesc& t2 = desc.get(terrain[pos][1]);
×
306
        const TerrainDesc& t3 = desc.get(terrain[GetVertexIdx(GetNeighbour(pt, Direction::East))][0]);
×
307
        const TerrainDesc& t4 = desc.get(terrain[GetVertexIdx(GetNeighbour(pt, Direction::SouthWest))][1]);
×
308

309
        if((borders[pos].left_right[0] = GetEdgeType(t2, t1)))
×
310
            borders[pos].left_right_offset[0] = numTriangles++;
×
311
        if((borders[pos].left_right[1] = GetEdgeType(t1, t2)))
×
312
            borders[pos].left_right_offset[1] = numTriangles++;
×
313

314
        if((borders[pos].right_left[0] = GetEdgeType(t3, t2)))
×
315
            borders[pos].right_left_offset[0] = numTriangles++;
×
316
        if((borders[pos].right_left[1] = GetEdgeType(t2, t3)))
×
317
            borders[pos].right_left_offset[1] = numTriangles++;
×
318

319
        if((borders[pos].top_down[0] = GetEdgeType(t4, t1)))
×
320
            borders[pos].top_down_offset[0] = numTriangles++;
×
321
        if((borders[pos].top_down[1] = GetEdgeType(t1, t4)))
×
322
            borders[pos].top_down_offset[1] = numTriangles++;
×
323
    }
324

325
    gl_vertices.resize(numTriangles);
×
326
    gl_texcoords.resize(numTriangles);
×
327
    gl_colors.resize(numTriangles);
×
328

329
    // Normales Terrain erzeugen
330
    RTTR_FOREACH_PT(MapPoint, size_)
×
331
    {
332
        UpdateTrianglePos(pt, false);
×
333
        UpdateTriangleColor(pt, false);
×
334
        UpdateTriangleTerrain(pt, false);
×
335
    }
336

337
    // Ränder erzeugen
338
    RTTR_FOREACH_PT(MapPoint, size_)
×
339
    {
340
        UpdateBorderTrianglePos(pt, false);
×
341
        UpdateBorderTriangleColor(pt, false);
×
342
        UpdateBorderTriangleTerrain(pt, false);
×
343
    }
344

345
    if(SETTINGS.video.vbo)
×
346
    {
347
        // Create and fill the 3 VBOs for vertices, texCoords and colors
348
        vbo_vertices = ogl::VBO<Triangle>(ogl::Target::Array);
×
349
        vbo_vertices.fill(gl_vertices, ogl::Usage::Static);
×
350

351
        vbo_texcoords = ogl::VBO<Triangle>(ogl::Target::Array);
×
352
        vbo_texcoords.fill(gl_texcoords, ogl::Usage::Static);
×
353

354
        vbo_colors = ogl::VBO<ColorTriangle>(ogl::Target::Array);
×
355
        vbo_colors.fill(gl_colors, ogl::Usage::Static);
×
356

357
        // Unbind VBO to not interfere with other program parts
358
        vbo_colors.unbind();
×
359
    }
360
}
×
361

362
void TerrainRenderer::UpdateTrianglePos(const MapPoint pt, bool updateVBO)
×
363
{
364
    unsigned pos = GetTriangleIdx(pt);
×
365

366
    gl_vertices[pos][0] = GetVertexPos(pt);
×
367
    gl_vertices[pos][1] = GetNeighbourVertexPos(pt, Direction::SouthWest);
×
368
    gl_vertices[pos][2] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
369

370
    ++pos;
×
371

372
    gl_vertices[pos][0] = GetVertexPos(pt);
×
373
    gl_vertices[pos][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
374
    gl_vertices[pos][2] = GetNeighbourVertexPos(pt, Direction::East);
×
375

376
    if(updateVBO && vbo_vertices.isValid())
×
377
    {
378
        vbo_vertices.update(&gl_vertices[pos - 1], 2, pos - 1);
×
379
        vbo_vertices.unbind();
×
380
    }
381
}
×
382

383
void TerrainRenderer::UpdateTriangleColor(const MapPoint pt, bool updateVBO)
×
384
{
385
    unsigned pos = GetTriangleIdx(pt);
×
386

387
    Color& clr0 = gl_colors[pos][0];
×
388
    Color& clr1 = gl_colors[pos][1];
×
389
    Color& clr2 = gl_colors[pos][2];
×
390
    clr0.r = clr0.g = clr0.b = GetColor(pt);
×
391
    clr1.r = clr1.g = clr1.b = GetColor(GetNeighbour(pt, Direction::SouthWest));
×
392
    clr2.r = clr2.g = clr2.b = GetColor(GetNeighbour(pt, Direction::SouthEast));
×
393

394
    ++pos;
×
395

396
    Color& clr3 = gl_colors[pos][0];
×
397
    Color& clr4 = gl_colors[pos][1];
×
398
    Color& clr5 = gl_colors[pos][2];
×
399
    clr3.r = clr3.g = clr3.b = GetColor(pt);
×
400
    clr4.r = clr4.g = clr4.b = GetColor(GetNeighbour(pt, Direction::SouthEast));
×
401
    clr5.r = clr5.g = clr5.b = GetColor(GetNeighbour(pt, Direction::East));
×
402

403
    if(updateVBO && vbo_colors.isValid())
×
404
    {
405
        vbo_colors.update(&gl_colors[pos - 1], 2, pos - 1);
×
406
        vbo_colors.unbind();
×
407
    }
408
}
×
409

410
void TerrainRenderer::UpdateTriangleTerrain(const MapPoint pt, bool updateVBO)
×
411
{
412
    const unsigned nodeIdx = GetVertexIdx(pt);
×
413
    const DescIdx<TerrainDesc> t1 = terrain[nodeIdx][0];
×
414
    const DescIdx<TerrainDesc> t2 = terrain[nodeIdx][1];
×
415

416
    const unsigned triangleIdx = GetTriangleIdx(pt);
×
417
    gl_texcoords[triangleIdx] = terrainTextures[t1].rsuCoords;
×
418
    gl_texcoords[triangleIdx + 1] = terrainTextures[t2].usdCoords;
×
419

420
    if(updateVBO && vbo_texcoords.isValid())
×
421
    {
422
        vbo_texcoords.update(&gl_texcoords[triangleIdx - 1], 2, triangleIdx - 1);
×
423
        vbo_texcoords.unbind();
×
424
    }
425
}
×
426

427
/// Erzeugt die Dreiecke für die Ränder
428
void TerrainRenderer::UpdateBorderTrianglePos(const MapPoint pt, bool updateVBO)
×
429
{
430
    unsigned pos = GetVertexIdx(pt);
×
431

432
    // Für VBO-Aktualisierung:
433
    // Erzeugte Ränder zählen
434
    unsigned count_borders = 0;
×
435
    // Erstes Offset merken
436
    unsigned first_offset = 0;
×
437

438
    // Rand links - rechts
439
    for(unsigned char i = 0; i < 2; ++i)
×
440
    {
441
        if(!borders[pos].left_right[i])
×
442
            continue;
×
443
        unsigned offset = borders[pos].left_right_offset[i];
×
444

445
        if(!first_offset)
×
446
            first_offset = offset;
×
447

448
        gl_vertices[offset][i ? 0 : 2] = GetVertexPos(pt);
×
449
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
450
        gl_vertices[offset][i ? 2 : 0] = GetBorderPos(pt, i);
×
451

452
        ++count_borders;
×
453
    }
454

455
    // Rand rechts - links
456
    for(unsigned char i = 0; i < 2; ++i)
×
457
    {
458
        if(!borders[pos].right_left[i])
×
459
            continue;
×
460
        unsigned offset = borders[pos].right_left_offset[i];
×
461

462
        if(!first_offset)
×
463
            first_offset = offset;
×
464

465
        gl_vertices[offset][i ? 2 : 0] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
466
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::East);
×
467

468
        if(i == 0)
×
469
            gl_vertices[offset][2] = GetBorderPos(pt, 1);
×
470
        else
471
            gl_vertices[offset][0] = GetNeighbourBorderPos(pt, 0, Direction::East);
×
472

473
        ++count_borders;
×
474
    }
475

476
    // Rand oben - unten
477
    for(unsigned char i = 0; i < 2; ++i)
×
478
    {
479
        if(!borders[pos].top_down[i])
×
480
            continue;
×
481
        unsigned offset = borders[pos].top_down_offset[i];
×
482

483
        if(!first_offset)
×
484
            first_offset = offset;
×
485

486
        gl_vertices[offset][i ? 2 : 0] = GetNeighbourVertexPos(pt, Direction::SouthWest);
×
487
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
488

489
        if(i == 0)
×
490
            gl_vertices[offset][2] = GetBorderPos(pt, i);
×
491
        else
492
            gl_vertices[offset][0] = GetNeighbourBorderPos(pt, i, Direction::SouthWest);
×
493

494
        ++count_borders;
×
495
    }
496

497
    if(updateVBO && vbo_vertices.isValid())
×
498
    {
499
        vbo_vertices.update(&gl_vertices[first_offset], count_borders, first_offset);
×
500
        vbo_vertices.unbind();
×
501
    }
502
}
×
503

504
void TerrainRenderer::UpdateBorderTriangleColor(const MapPoint pt, bool updateVBO)
×
505
{
506
    unsigned pos = GetVertexIdx(pt);
×
507

508
    // Für VBO-Aktualisierung:
509
    // Erzeugte Ränder zählen
510
    unsigned count_borders = 0;
×
511
    // Erstes Offset merken
512
    unsigned first_offset = 0;
×
513

514
    // Rand links - rechts
515
    for(unsigned char i = 0; i < 2; ++i)
×
516
    {
517
        if(!borders[pos].left_right[i])
×
518
            continue;
×
519
        unsigned offset = borders[pos].left_right_offset[i];
×
520

521
        if(!first_offset)
×
522
            first_offset = offset;
×
523

524
        gl_colors[offset][i ? 0 : 2].r = gl_colors[offset][i ? 0 : 2].g = gl_colors[offset][i ? 0 : 2].b =
×
525
          GetColor(pt); //-V807
×
526
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
527
          GetColor(GetNeighbour(pt, Direction::SouthEast)); //-V807
×
528
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
529
          GetBorderColor(pt, i); //-V807
×
530

531
        ++count_borders;
×
532
    }
533

534
    // Rand rechts - links
535
    for(unsigned char i = 0; i < 2; ++i)
×
536
    {
537
        if(!borders[pos].right_left[i])
×
538
            continue;
×
539
        unsigned offset = borders[pos].right_left_offset[i];
×
540

541
        if(!first_offset)
×
542
            first_offset = offset;
×
543

544
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
545
          GetColor(GetNeighbour(pt, Direction::SouthEast));
×
546
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
547
          GetColor(GetNeighbour(pt, Direction::East));
×
548
        MapPoint pt2(pt.x + i, pt.y);
×
549
        if(pt2.x >= size_.x)
×
550
            pt2.x -= size_.x;
×
551
        gl_colors[offset][i ? 0 : 2].r = gl_colors[offset][i ? 0 : 2].g = gl_colors[offset][i ? 0 : 2].b =
×
552
          GetBorderColor(pt2, i ? 0 : 1);
×
553

554
        ++count_borders;
×
555
    }
556

557
    // Rand oben - unten
558
    for(unsigned char i = 0; i < 2; ++i)
×
559
    {
560
        if(!borders[pos].top_down[i])
×
561
            continue;
×
562
        unsigned offset = borders[pos].top_down_offset[i];
×
563

564
        if(!first_offset)
×
565
            first_offset = offset;
×
566

567
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
568
          GetColor(GetNeighbour(pt, Direction::SouthWest));
×
569
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
570
          GetColor(GetNeighbour(pt, Direction::SouthEast));
×
571

572
        if(i == 0)
×
573
            gl_colors[offset][2].r = gl_colors[offset][2].g = gl_colors[offset][2].b = GetBorderColor(pt, i); //-V807
×
574
        else
575
            gl_colors[offset][0].r = gl_colors[offset][0].g = gl_colors[offset][0].b =
×
576
              GetBorderColor(GetNeighbour(pt, Direction::SouthWest), i); //-V807
×
577

578
        ++count_borders;
×
579
    }
580

581
    if(updateVBO && vbo_colors.isValid())
×
582
    {
583
        vbo_colors.update(&gl_colors[first_offset], count_borders, first_offset);
×
584
        vbo_colors.unbind();
×
585
    }
586
}
×
587

588
void TerrainRenderer::UpdateBorderTriangleTerrain(const MapPoint pt, bool updateVBO)
×
589
{
590
    unsigned pos = GetVertexIdx(pt);
×
591

592
    // For updating the VBO count created borders and first offset
593
    unsigned count_borders = 0;
×
594
    unsigned first_offset = 0;
×
595

596
    // left to right border
597
    for(unsigned char i = 0; i < 2; ++i)
×
598
    {
599
        if(borders[pos].left_right[i])
×
600
        {
601
            unsigned offset = borders[pos].left_right_offset[i];
×
602

603
            if(!first_offset)
×
604
                first_offset = offset;
×
605

606
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].left_right[i]];
×
607
            Extent bmpSize = texture.GetSize();
×
608
            PointF texSize(texture.GetTexSize());
×
609

610
            gl_texcoords[offset][i ? 0 : 2] = PointF(0.0f, 0.0f);
×
611
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
612
            gl_texcoords[offset][i ? 2 : 0] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
613

614
            ++count_borders;
×
615
        }
616
    }
617

618
    // right to left border
619
    for(unsigned char i = 0; i < 2; ++i)
×
620
    {
621
        if(borders[pos].right_left[i])
×
622
        {
623
            unsigned offset = borders[pos].right_left_offset[i];
×
624

625
            if(!first_offset)
×
626
                first_offset = offset;
×
627

628
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].right_left[i]];
×
629
            Extent bmpSize = texture.GetSize();
×
630
            PointF texSize(texture.GetTexSize());
×
631

632
            gl_texcoords[offset][i ? 2 : 0] = PointF(0.0f, 0.0f);
×
633
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
634
            gl_texcoords[offset][i ? 0 : 2] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
635

636
            ++count_borders;
×
637
        }
638
    }
639

640
    // top to bottom border
641
    for(unsigned char i = 0; i < 2; ++i)
×
642
    {
643
        if(borders[pos].top_down[i])
×
644
        {
645
            unsigned offset = borders[pos].top_down_offset[i];
×
646

647
            if(!first_offset)
×
648
                first_offset = offset;
×
649

650
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].top_down[i]];
×
651
            Extent bmpSize = texture.GetSize();
×
652
            PointF texSize(texture.GetTexSize());
×
653

654
            gl_texcoords[offset][i ? 2 : 0] = PointF(0.0f, 0.0f);
×
655
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
656
            gl_texcoords[offset][i ? 0 : 2] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
657

658
            ++count_borders;
×
659
        }
660
    }
661

662
    if(updateVBO && vbo_texcoords.isValid())
×
663
    {
664
        vbo_texcoords.update(&gl_texcoords[first_offset], count_borders, first_offset);
×
665
        vbo_texcoords.unbind();
×
666
    }
667
}
×
668

669
void TerrainRenderer::Draw(const Position& firstPt, const Position& lastPt, const GameWorldViewer& gwv,
×
670
                           unsigned* water) const
671
{
672
    RTTR_Assert(!gl_vertices.empty());
×
673
    RTTR_Assert(!borders.empty());
×
674

675
    // Sort textures into lists by type
676
    DescriptionVector<std::vector<MapTile>, TerrainDesc> sorted_textures(terrainTextures.size());
×
677
    DescriptionVector<std::vector<BorderTile>, EdgeDesc> sorted_borders(edgeTextures.size());
×
678
    PreparedRoads sorted_roads(roadTextures.size());
×
679

680
    Position lastOffset(0, 0);
×
681

682
    // Only draw visible area
683
    for(auto const y : helpers::range(firstPt.y, lastPt.y + 1))
×
684
    {
685
        DescIdx<TerrainDesc> lastTerrain;
×
686
        DescIdx<EdgeDesc> lastBorder;
×
687

688
        for(auto const x : helpers::range(firstPt.x, lastPt.x + 1))
×
689
        {
690
            Position posOffset;
×
691
            MapPoint tP = ConvertCoords(Position(x, y), &posOffset);
×
692

693
            auto t = terrain[GetVertexIdx(tP)][0];
×
694
            if(posOffset != lastOffset)
×
695
                lastTerrain = DescIdx<TerrainDesc>();
×
696

697
            if(t == lastTerrain && tP != MapPoint(0, 0))
×
698
                ++sorted_textures[t].back().count;
×
699
            else
700
            {
701
                MapTile tmp(GetTriangleIdx(tP), posOffset);
×
702
                sorted_textures[t].push_back(tmp);
×
703
                lastTerrain = t;
×
704
            }
705

706
            t = terrain[GetVertexIdx(tP)][1];
×
707

708
            if(t == lastTerrain)
×
709
                ++sorted_textures[t].back().count;
×
710
            else
711
            {
712
                MapTile tmp(GetTriangleIdx(tP) + 1, posOffset);
×
713
                sorted_textures[t].push_back(tmp);
×
714
            }
715

716
            lastTerrain = t;
×
717

718
            const Borders& curBorders = borders[GetVertexIdx(tP)];
×
719
            helpers::EnumArray<DescIdx<EdgeDesc>, Direction> tiles = {
720
              {curBorders.left_right[0], curBorders.left_right[1], curBorders.right_left[0], curBorders.right_left[1],
×
721
               curBorders.top_down[0], curBorders.top_down[1]}};
×
722

723
            // Offsets into gl_* arrays
724
            helpers::EnumArray<unsigned, Direction> offsets = {
725
              {curBorders.left_right_offset[0], curBorders.left_right_offset[1], curBorders.right_left_offset[0],
×
726
               curBorders.right_left_offset[1], curBorders.top_down_offset[0], curBorders.top_down_offset[1]}};
×
727

728
            for(const auto dir : helpers::EnumRange<Direction>{})
×
729
            {
730
                if(!tiles[dir])
×
731
                    continue;
×
732
                if(tiles[dir] == lastBorder)
×
733
                {
734
                    BorderTile& curTile = sorted_borders[lastBorder].back();
×
735
                    // Check that we did not wrap around the map and the expected offset matches
736
                    if(curTile.tileOffset + curTile.count == offsets[dir])
×
737
                    {
738
                        ++curTile.count;
×
739
                        continue;
×
740
                    }
741
                }
742
                lastBorder = tiles[dir];
×
743
                BorderTile tmp(offsets[dir], posOffset);
×
744
                sorted_borders[lastBorder].push_back(tmp);
×
745
            }
746

747
            PrepareWaysPoint(sorted_roads, gwv, tP, posOffset);
×
748

749
            lastOffset = posOffset;
×
750
        }
751
    }
752

753
    if(water)
×
754
    {
755
        const WorldDescription& desc = gwv.GetWorld().GetDescription();
×
756
        unsigned water_count = 0;
×
757
        for(const auto t : sorted_textures.indices())
×
758
        {
759
            if(desc.get(t).kind == TerrainKind::Water)
×
760
            {
761
                for(const MapTile& tile : sorted_textures[t])
×
762
                    water_count += tile.count;
×
763
            }
764
        }
765

766
        Position diff =
767
          lastPt - firstPt + Position(1, 1); // Number of points checked in X and Y, including(!) the last one
×
768
        // For each point there are 2 tiles added (USD, RSU) so we have 2 times the tiles as the number of points.
769
        // Calculate the percentage of water tiles
770
        *water = 100 * water_count / (2 * prodOfComponents(diff));
×
771
    }
772

773
    lastOffset = Position(0, 0);
×
774

775
    glEnableClientState(GL_COLOR_ARRAY);
×
776

777
    if(vbo_vertices.isValid())
×
778
    {
779
        vbo_vertices.bind();
×
780
        glVertexPointer(2, GL_FLOAT, 0, nullptr);
×
781

782
        vbo_texcoords.bind();
×
783
        glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
×
784

785
        vbo_colors.bind();
×
786
        glColorPointer(3, GL_FLOAT, 0, nullptr);
×
787
    } else
788
    {
789
        glVertexPointer(2, GL_FLOAT, 0, &gl_vertices.front());
×
790
        glTexCoordPointer(2, GL_FLOAT, 0, &gl_texcoords.front());
×
791
        glColorPointer(3, GL_FLOAT, 0, &gl_colors.front());
×
792
    }
793

794
    // Modulate2x
795
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
×
796
    glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f);
×
797

798
    // Disable alpha blending
799
    glDisable(GL_BLEND);
×
800

801
    glPushMatrix();
×
802
    for(const auto t : sorted_textures.indices())
×
803
    {
804
        if(sorted_textures[t].empty())
×
805
            continue;
×
806
        unsigned animationFrame;
807
        const unsigned numFrames = terrainTextures[t].textures.size();
×
808
        if(numFrames > 1)
×
809
            animationFrame = GAMECLIENT.GetGlobalAnimation(numFrames, 5 * numFrames, 16, 0); // We have 5/16 per frame
×
810
        else
811
            animationFrame = 0;
×
812

813
        VIDEODRIVER.BindTexture(terrainTextures[t].textures[animationFrame].GetTextureNoCreate());
×
814

815
        for(const auto& texture : sorted_textures[t])
×
816
        {
817
            if(texture.posOffset != lastOffset)
×
818
            {
819
                Position trans = texture.posOffset - lastOffset;
×
820
                glTranslatef(float(trans.x), float(trans.y), 0.0f);
×
821
                lastOffset = texture.posOffset;
×
822
            }
823

824
            RTTR_Assert(texture.tileOffset + texture.count <= size_.x * size_.y * 2u);
×
825
            glDrawArrays(GL_TRIANGLES, texture.tileOffset * 3,
×
826
                         texture.count * 3); // Arguments are in Elements. 1 triangle has 3 values
×
827
        }
828
    }
829
    glPopMatrix();
×
830

831
    glEnable(GL_BLEND);
×
832

833
    lastOffset = Position(0, 0);
×
834
    glPushMatrix();
×
835
    for(const auto i : sorted_borders.indices())
×
836
    {
837
        if(sorted_borders[i].empty())
×
838
            continue;
×
839
        VIDEODRIVER.BindTexture(edgeTextures[i]->GetTextureNoCreate());
×
840

841
        for(const auto& texture : sorted_borders[i])
×
842
        {
843
            if(texture.posOffset != lastOffset)
×
844
            {
845
                Position trans = texture.posOffset - lastOffset;
×
846
                glTranslatef(float(trans.x), float(trans.y), 0.0f);
×
847
                lastOffset = texture.posOffset;
×
848
            }
849
            RTTR_Assert(texture.tileOffset + texture.count <= gl_vertices.size());
×
850
            glDrawArrays(GL_TRIANGLES, texture.tileOffset * 3,
×
851
                         texture.count * 3); // Arguments are in elements. 1 triangle has 3 values
×
852
        }
853
    }
854
    glPopMatrix();
×
855

856
    // unbind VBO
857
    if(vbo_vertices.isValid())
×
858
        vbo_vertices.unbind();
×
859

860
    DrawWays(sorted_roads);
×
861

862
    glDisableClientState(GL_COLOR_ARRAY);
×
863
    // Switch back to modulation
864
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
×
865
}
×
866

867
MapPoint TerrainRenderer::ConvertCoords(const Position pt, Position* offset) const
12✔
868
{
869
    MapPoint ptOut = MakeMapPoint(pt, size_);
12✔
870
    RTTR_Assert(ptOut.x < size_.x);
12✔
871
    RTTR_Assert(ptOut.y < size_.y);
12✔
872
    if(offset)
12✔
873
    {
874
        // We need the offset by which we shifted the point in screen units
875
        *offset = (pt - ptOut) * Extent(TR_W, TR_H);
12✔
876
    }
877
    return ptOut;
12✔
878
}
879

880
void TerrainRenderer::PrepareWaysPoint(PreparedRoads& sorted_roads, const GameWorldViewer& gwViewer, MapPoint pt,
×
881
                                       const Position& offset) const
882
{
883
    const WorldDescription& desc = gwViewer.GetWorld().GetDescription();
×
884
    Position startPos = Position(Position::Truncate, GetVertexPos(pt)) + offset;
×
885

886
    Visibility visibility = gwViewer.GetVisibility(pt);
×
887

888
    int totalWidth = size_.x * TR_W;
×
889
    int totalHeight = size_.y * TR_H;
×
890

891
    // Wegtypen für die drei Richtungen
892
    for(const RoadDir dir : helpers::EnumRange<RoadDir>{})
×
893
    {
894
        const PointRoad type = gwViewer.GetVisibleRoad(pt, dir, visibility);
×
895
        if(type == PointRoad::None)
×
896
            continue;
×
897
        const Direction targetDir = toDirection(dir);
×
898
        MapPoint ta = gwViewer.GetNeighbour(pt, targetDir);
×
899

900
        Position endPos = Position(Position::Truncate, GetVertexPos(ta)) + offset;
×
901
        Position diff = startPos - endPos;
×
902

903
        // Gehen wir über einen Kartenrand (horizontale Richung?)
904
        if(std::abs(diff.x) >= totalWidth / 2)
×
905
        {
906
            if(std::abs(endPos.x - totalWidth - startPos.x) < std::abs(diff.x))
×
907
                endPos.x -= totalWidth;
×
908
            else
909
                endPos.x += totalWidth;
×
910
        }
911
        // Und dasselbe für vertikale Richtung
912
        if(std::abs(diff.y) >= totalHeight / 2)
×
913
        {
914
            if(std::abs(endPos.y - totalHeight - startPos.y) < std::abs(diff.y))
×
915
                endPos.y -= totalHeight;
×
916
            else
917
                endPos.y += totalHeight;
×
918
        }
919

920
        // The gfx road type is:
921
        // Boat for boat roads
922
        // else Mountain left or right is a mountain terrain
923
        // else Upgraded for Donkey roads
924
        // else Normal
925
        uint8_t gfxRoadType;
926
        const auto terrain = gwViewer.GetWorld().GetTerrain(pt, targetDir);
×
927
        const TerrainDesc& lTerrain = desc.get(terrain.left);
×
928
        if(type == PointRoad::Boat)
×
929
        {
930
            gfxRoadType = getFlatIndex(lTerrain.landscape, LandRoadType::Boat);
×
931
        } else
932
        {
933
            if(desc.get(terrain.left).kind == TerrainKind::Mountain)
×
934
                gfxRoadType = getFlatIndex(lTerrain.landscape, LandRoadType::Mountain);
×
935
            else
936
            {
937
                const TerrainDesc& rTerrain = desc.get(terrain.right);
×
938
                if(rTerrain.kind == TerrainKind::Mountain)
×
939
                    gfxRoadType = getFlatIndex(rTerrain.landscape, LandRoadType::Mountain);
×
940
                else
941
                    gfxRoadType =
×
942
                      getFlatIndex(lTerrain.landscape,
×
943
                                   ((type == PointRoad::Donkey) ? LandRoadType::Upgraded : LandRoadType::Normal));
944
            }
945
        }
946

947
        sorted_roads[gfxRoadType].push_back(PreparedRoad(startPos, endPos, GetColor(pt), GetColor(ta), dir));
×
948
    }
949
}
×
950

951
struct Tex2C3Ver2
952
{
953
    GLfloat tx, ty;
954
    GLfloat r, g, b;
955
    GLfloat x, y;
956
};
957

958
void TerrainRenderer::DrawWays(const PreparedRoads& sorted_roads) const
×
959
{
960
    static constexpr helpers::EnumArray<std::array<Position, 4>, RoadDir> begin_end_coords = {{
961
      {{Position(0, -3), Position(0, 3), Position(3, 3), Position(3, -3)}},
962
      {{Position(2, -4), Position(-4, 2), Position(0, 6), Position(6, 0)}},
963
      {{Position(4, 2), Position(-2, -4), Position(-6, 0), Position(0, 6)}},
964
    }};
965

966
    size_t maxSize = 0;
×
967
    for(const std::vector<PreparedRoad>& sorted_road : sorted_roads)
×
968
        maxSize = std::max(maxSize, sorted_road.size());
×
969

970
    if(maxSize == 0)
×
971
        return;
×
972

973
    auto vertexData = std::unique_ptr<Tex2C3Ver2[]>(new Tex2C3Ver2[maxSize * 4]);
×
974
    // These should still be enabled
975
    RTTR_Assert(glIsEnabled(GL_VERTEX_ARRAY));
×
976
    RTTR_Assert(glIsEnabled(GL_TEXTURE_COORD_ARRAY));
×
977
    RTTR_Assert(glIsEnabled(GL_COLOR_ARRAY));
×
978
    glVertexPointer(2, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].x);
×
979
    glTexCoordPointer(2, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].tx);
×
980
    glColorPointer(3, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].r);
×
981

982
    for(const auto itRoad : sorted_roads | boost::adaptors::indexed())
×
983
    {
984
        if(itRoad.value().empty())
×
985
            continue;
×
986
        Tex2C3Ver2* curVertexData = vertexData.get();
×
987
        const glArchivItem_Bitmap& texture = *roadTextures[itRoad.index()];
×
988
        PointF scaledTexSize = texture.GetSize() / PointF(texture.GetTexSize());
×
989

990
        for(const auto& it : itRoad.value())
×
991
        {
992
            curVertexData->tx = 0.0f;
×
993
            curVertexData->ty = 0.0f;
×
994
            curVertexData->r = curVertexData->g = curVertexData->b = it.color1;
×
995
            Position tmpP = it.pos + begin_end_coords[it.dir][0];
×
996
            curVertexData->x = GLfloat(tmpP.x);
×
997
            curVertexData->y = GLfloat(tmpP.y);
×
998

999
            curVertexData++;
×
1000

1001
            curVertexData->tx = 0.0f;
×
1002
            curVertexData->ty = scaledTexSize.y;
×
1003
            curVertexData->r = curVertexData->g = curVertexData->b = it.color1;
×
1004
            tmpP = it.pos + begin_end_coords[it.dir][1];
×
1005
            curVertexData->x = GLfloat(tmpP.x);
×
1006
            curVertexData->y = GLfloat(tmpP.y);
×
1007

1008
            curVertexData++;
×
1009

1010
            curVertexData->tx = scaledTexSize.x;
×
1011
            curVertexData->ty = scaledTexSize.y;
×
1012
            curVertexData->r = curVertexData->g = curVertexData->b = it.color2;
×
1013
            tmpP = it.pos2 + begin_end_coords[it.dir][2];
×
1014
            curVertexData->x = GLfloat(tmpP.x);
×
1015
            curVertexData->y = GLfloat(tmpP.y);
×
1016

1017
            curVertexData++;
×
1018
            curVertexData->tx = scaledTexSize.x;
×
1019
            curVertexData->ty = 0.0f;
×
1020
            curVertexData->r = curVertexData->g = curVertexData->b = it.color2;
×
1021
            tmpP = it.pos2 + begin_end_coords[it.dir][3];
×
1022
            curVertexData->x = GLfloat(tmpP.x);
×
1023
            curVertexData->y = GLfloat(tmpP.y);
×
1024

1025
            curVertexData++;
×
1026
        }
1027

1028
        VIDEODRIVER.BindTexture(texture.GetTextureNoCreate());
×
1029
        glDrawArrays(GL_QUADS, 0, itRoad.value().size() * 4);
×
1030
    }
1031
    // Note: No glDisableClientState as we did not enable it
1032
}
1033

1034
void TerrainRenderer::AltitudeChanged(const MapPoint pt, const GameWorldViewer& gwv)
×
1035
{
1036
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1037
    UpdateVertexPos(pt, gwv);
×
1038
    UpdateVertexColor(pt, gwv);
×
1039

1040
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1041
        UpdateVertexColor(nb, gwv);
×
1042

1043
    // und für die Ränder
1044
    UpdateBorderVertex(pt);
×
1045

1046
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1047
        UpdateBorderVertex(nb);
×
1048

1049
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1050
    UpdateTrianglePos(pt, true);
×
1051
    UpdateTriangleColor(pt, true);
×
1052

1053
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1054
    {
1055
        UpdateTrianglePos(nb, true);
×
1056
        UpdateTriangleColor(nb, true);
×
1057
    }
1058

1059
    // Auch im zweiten Kreis drumherum die Dreiecke neu berechnen, da die durch die Schattenänderung der umliegenden
1060
    // Punkte auch geändert werden könnten
1061
    for(unsigned i = 0; i < 12; ++i)
×
1062
        UpdateTriangleColor(gwv.GetWorld().GetNeighbour2(pt, i), true);
×
1063

1064
    // und für die Ränder
1065
    UpdateBorderTrianglePos(pt, true);
×
1066
    UpdateBorderTriangleColor(pt, true);
×
1067

1068
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1069
    {
1070
        UpdateBorderTrianglePos(nb, true);
×
1071
        UpdateBorderTriangleColor(nb, true);
×
1072
    }
1073

1074
    for(unsigned i = 0; i < 12; ++i)
×
1075
        UpdateBorderTriangleColor(gwv.GetWorld().GetNeighbour2(pt, i), true);
×
1076
}
×
1077

1078
void TerrainRenderer::VisibilityChanged(const MapPoint pt, const GameWorldViewer& gwv)
×
1079
{
1080
    /// Noch kein Terrain gebaut? abbrechen
1081
    if(vertices.empty())
×
1082
        return;
×
1083

1084
    UpdateVertexColor(pt, gwv);
×
1085
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1086
        UpdateVertexColor(nb, gwv);
×
1087

1088
    // und für die Ränder
1089
    UpdateBorderVertex(pt);
×
1090
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1091
        UpdateBorderVertex(nb);
×
1092

1093
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1094
    UpdateTriangleColor(pt, true);
×
1095
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1096
        UpdateTriangleColor(nb, true);
×
1097

1098
    // und für die Ränder
1099
    UpdateBorderTriangleColor(pt, true);
×
1100
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1101
        UpdateBorderTriangleColor(nb, true);
×
1102
}
1103

1104
void TerrainRenderer::UpdateAllColors(const GameWorldViewer& gwv)
×
1105
{
1106
    RTTR_FOREACH_PT(MapPoint, size_)
×
1107
        UpdateVertexColor(pt, gwv);
×
1108

1109
    RTTR_FOREACH_PT(MapPoint, size_)
×
1110
        UpdateBorderVertex(pt);
×
1111

1112
    RTTR_FOREACH_PT(MapPoint, size_)
×
1113
        UpdateTriangleColor(pt, false);
×
1114

1115
    RTTR_FOREACH_PT(MapPoint, size_)
×
1116
        UpdateBorderTriangleColor(pt, false);
×
1117

1118
    if(vbo_colors.isValid())
×
1119
    {
1120
        vbo_colors.update(gl_colors);
×
1121
        vbo_colors.unbind();
×
1122
    }
1123
}
×
1124

1125
MapPoint TerrainRenderer::GetNeighbour(const MapPoint& pt, const Direction dir) const
×
1126
{
1127
    return MakeMapPoint(::GetNeighbour(Position(pt), dir), size_);
×
1128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc