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

Return-To-The-Roots / s25client / 20641422872

01 Jan 2026 03:57PM UTC coverage: 50.532% (-0.05%) from 50.58%
20641422872

Pull #1804

github

web-flow
Merge 04b41dbf7 into d98c92f3b
Pull Request #1804: Android build

65 of 226 new or added lines in 13 files covered. (28.76%)

15 existing lines in 5 files now uncovered.

22599 of 44722 relevant lines covered (50.53%)

35465.07 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 <openglCfg.hpp>
28
#include <set>
29

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

48
namespace {
49
// gl4es has some problems with GL_MODULATE so we need to change the colors without using a gl function
50
#if RTTR_OGL_GL4ES
51
constexpr float TEXTURE_COLOR_DIVISOR = 1;
52
#else
53
constexpr float TEXTURE_COLOR_DIVISOR = 2;
54
#endif
55
} // namespace
56

UNCOV
57
glArchivItem_Bitmap* new_clone(const glArchivItem_Bitmap& bmp)
×
58
{
59
    return dynamic_cast<glArchivItem_Bitmap*>(bmp.clone());
×
60
}
61

62
TerrainRenderer::TerrainRenderer() : size_(0, 0) {}
23✔
63
TerrainRenderer::~TerrainRenderer() = default;
23✔
64

65
static constexpr unsigned getFlatIndex(DescIdx<LandscapeDesc> ls, LandRoadType road)
×
66
{
67
    return ls.value * helpers::NumEnumValues_v<LandRoadType> + rttr::enum_cast(road);
×
68
}
69

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

75
    Position offset;
×
76
    MapPoint t = ConvertCoords(ptNb, &offset);
×
77

78
    return GetVertexPos(t) + PointF(offset);
×
79
}
80

81
PointF TerrainRenderer::GetNeighbourBorderPos(const MapPoint pt, const unsigned char triangle,
×
82
                                              const Direction dir) const
83
{
84
    // Note: We want the real neighbour point which might be outside of the map to get the offset right
85
    Position ptNb = ::GetNeighbour(Position(pt), dir);
×
86

87
    Position offset;
×
88
    MapPoint t = ConvertCoords(ptNb, &offset);
×
89

90
    return GetBorderPos(t, triangle) + PointF(offset);
×
91
}
92

93
void TerrainRenderer::LoadTextures(const WorldDescription& desc)
×
94
{
95
    terrainTextures.clear();
×
96
    edgeTextures.clear();
×
97
    roadTextures.clear();
×
98

99
    std::set<DescIdx<LandscapeDesc>> usedLandscapes;
×
100
    std::set<DescIdx<TerrainDesc>> usedTerrains;
×
101
    std::set<DescIdx<EdgeDesc>> usedEdges;
×
102
    using TerrainPair = std::array<DescIdx<TerrainDesc>, 2>;
103
    for(const TerrainPair& ts : terrain)
×
104
    {
105
        for(const DescIdx<TerrainDesc>& tIdx : ts)
×
106
        {
107
            if(!helpers::contains(usedTerrains, tIdx))
×
108
            {
109
                usedTerrains.insert(tIdx);
×
110
                DescIdx<EdgeDesc> edge = desc.get(tIdx).edgeType;
×
111
                if(!!edge)
×
112
                    usedEdges.insert(edge);
×
113
                DescIdx<LandscapeDesc> lt = desc.get(tIdx).landscape;
×
114
                if(!!lt)
×
115
                    usedLandscapes.insert(lt);
×
116
            }
117
        }
118
    }
119
    terrainTextures.resize(usedTerrains.rbegin()->value + 1);
×
120
    edgeTextures.resize(usedEdges.rbegin()->value + 1);
×
121
    roadTextures.resize((usedLandscapes.rbegin()->value + 1) * helpers::NumEnumValues_v<LandRoadType>);
×
122

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

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

202
void TerrainRenderer::GenerateVertices(const GameWorldViewer& gwv)
×
203
{
204
    // Terrain generieren
205
    RTTR_FOREACH_PT(MapPoint, size_)
×
206
    {
207
        UpdateVertexPos(pt, gwv);
×
208
        UpdateVertexColor(pt, gwv);
×
209
        LoadVertexTerrain(pt, gwv);
×
210
    }
211

212
    // Ränder generieren
213
    RTTR_FOREACH_PT(MapPoint, size_)
×
214
        UpdateBorderVertex(pt);
×
215
}
×
216

217
void TerrainRenderer::UpdateVertexPos(const MapPoint pt, const GameWorldViewer& gwv)
×
218
{
219
    GetVertex(pt).pos = PointF(gwv.GetWorld().GetNodePos(pt));
×
220
}
×
221

222
void TerrainRenderer::UpdateVertexColor(const MapPoint pt, const GameWorldViewer& gwv)
×
223
{
224
    auto shadow = static_cast<float>(gwv.GetNode(pt).shadow);
×
225
    float clr = -1.f / (256.f * 256.f) * shadow * shadow + 1.f / 90.f * shadow + 0.38f;
×
226
    switch(gwv.GetVisibility(pt))
×
227
    {
228
        case Visibility::Invisible:
×
229
            // Unsichtbar -> schwarz
230
            GetVertex(pt).color = 0.0f;
×
231
            break;
×
232
        case Visibility::FogOfWar:
×
233
            // Fog of War -> abgedunkelt
NEW
234
            GetVertex(pt).color = clr / (TEXTURE_COLOR_DIVISOR * 2);
×
235
            break;
×
236
        case Visibility::Visible:
×
237
            // Normal sichtbar
NEW
238
            GetVertex(pt).color = clr / TEXTURE_COLOR_DIVISOR;
×
239
            break;
×
240
    }
241
}
×
242

243
void TerrainRenderer::LoadVertexTerrain(const MapPoint pt, const GameWorldViewer& gwv)
×
244
{
245
    const MapNode& node = gwv.GetNode(pt);
×
246
    terrain[GetVertexIdx(pt)][0] = node.t1;
×
247
    terrain[GetVertexIdx(pt)][1] = node.t2;
×
248
}
×
249

250
void TerrainRenderer::UpdateBorderVertex(const MapPoint pt)
×
251
{
252
    Vertex& vertex = GetVertex(pt);
×
253
    vertex.borderPos[0] = (GetNeighbourVertexPos(pt, Direction::SouthWest) + GetVertexPos(pt)
×
254
                           + GetNeighbourVertexPos(pt, Direction::SouthEast))
×
255
                          / 3.0f;
×
256
    vertex.borderColor[0] = (GetColor(GetNeighbour(pt, Direction::SouthWest)) + GetColor(pt)
×
257
                             + GetColor(GetNeighbour(pt, Direction::SouthEast)))
×
258
                            / 3.0f;
×
259

260
    vertex.borderPos[1] =
×
261
      (GetNeighbourVertexPos(pt, Direction::East) + GetVertexPos(pt) + GetNeighbourVertexPos(pt, Direction::SouthEast))
×
262
      / 3.0f;
×
263
    vertex.borderColor[1] =
×
264
      (GetColor(GetNeighbour(pt, Direction::East)) + GetColor(pt) + GetColor(GetNeighbour(pt, Direction::SouthEast)))
×
265
      / 3.0f;
×
266
}
×
267

268
void TerrainRenderer::Init(const MapExtent& size)
1✔
269
{
270
    size_ = size;
1✔
271
    // Clear first, so they are default-initialized
272
    vertices.clear();
1✔
273
    terrain.clear();
1✔
274
    borders.clear();
1✔
275
    vertices.resize(size_.x * size_.y);
1✔
276
    terrain.resize(vertices.size());
1✔
277
    borders.resize(size_.x * size_.y);
1✔
278

279
    gl_vertices.clear();
1✔
280
    gl_texcoords.clear();
1✔
281
    gl_colors.clear();
1✔
282
    // We have 2 triangles per map point
283
    gl_vertices.resize(vertices.size() * 2);
1✔
284
    gl_texcoords.resize(gl_vertices.size());
1✔
285
    gl_colors.resize(gl_vertices.size());
1✔
286
}
1✔
287

288
/// Get the edge type description index that t1 draws over t2. If none a falsy index is returned
289
static DescIdx<EdgeDesc> GetEdgeType(const TerrainDesc& t1, const TerrainDesc& t2)
×
290
{
291
    if(!t1.edgeType || t1.edgePriority <= t2.edgePriority)
×
292
        return {};
×
293
    else
294
        return t1.edgeType;
×
295
}
296

297
/**
298
 *  erzeugt die OpenGL-Vertices.
299
 */
300
void TerrainRenderer::GenerateOpenGL(const GameWorldViewer& gwv)
×
301
{
302
    const GameWorldBase& world = gwv.GetWorld();
×
303
    Init(world.GetSize());
×
304

305
    GenerateVertices(gwv);
×
306
    const WorldDescription& desc = world.GetDescription();
×
307
    LoadTextures(desc);
×
308

309
    // Add extra vertices for borders
310
    unsigned numTriangles = gl_vertices.size();
×
311
    RTTR_FOREACH_PT(MapPoint, size_)
×
312
    {
313
        const unsigned pos = GetVertexIdx(pt);
×
314
        const TerrainDesc& t1 = desc.get(terrain[pos][0]);
×
315
        const TerrainDesc& t2 = desc.get(terrain[pos][1]);
×
316
        const TerrainDesc& t3 = desc.get(terrain[GetVertexIdx(GetNeighbour(pt, Direction::East))][0]);
×
317
        const TerrainDesc& t4 = desc.get(terrain[GetVertexIdx(GetNeighbour(pt, Direction::SouthWest))][1]);
×
318

319
        if((borders[pos].left_right[0] = GetEdgeType(t2, t1)))
×
320
            borders[pos].left_right_offset[0] = numTriangles++;
×
321
        if((borders[pos].left_right[1] = GetEdgeType(t1, t2)))
×
322
            borders[pos].left_right_offset[1] = numTriangles++;
×
323

324
        if((borders[pos].right_left[0] = GetEdgeType(t3, t2)))
×
325
            borders[pos].right_left_offset[0] = numTriangles++;
×
326
        if((borders[pos].right_left[1] = GetEdgeType(t2, t3)))
×
327
            borders[pos].right_left_offset[1] = numTriangles++;
×
328

329
        if((borders[pos].top_down[0] = GetEdgeType(t4, t1)))
×
330
            borders[pos].top_down_offset[0] = numTriangles++;
×
331
        if((borders[pos].top_down[1] = GetEdgeType(t1, t4)))
×
332
            borders[pos].top_down_offset[1] = numTriangles++;
×
333
    }
334

335
    gl_vertices.resize(numTriangles);
×
336
    gl_texcoords.resize(numTriangles);
×
337
    gl_colors.resize(numTriangles);
×
338

339
    // Normales Terrain erzeugen
340
    RTTR_FOREACH_PT(MapPoint, size_)
×
341
    {
342
        UpdateTrianglePos(pt, false);
×
343
        UpdateTriangleColor(pt, false);
×
344
        UpdateTriangleTerrain(pt, false);
×
345
    }
346

347
    // Ränder erzeugen
348
    RTTR_FOREACH_PT(MapPoint, size_)
×
349
    {
350
        UpdateBorderTrianglePos(pt, false);
×
351
        UpdateBorderTriangleColor(pt, false);
×
352
        UpdateBorderTriangleTerrain(pt, false);
×
353
    }
354

355
    if(SETTINGS.video.vbo)
×
356
    {
357
        // Create and fill the 3 VBOs for vertices, texCoords and colors
358
        vbo_vertices = ogl::VBO<Triangle>(ogl::Target::Array);
×
359
        vbo_vertices.fill(gl_vertices, ogl::Usage::Static);
×
360

361
        vbo_texcoords = ogl::VBO<Triangle>(ogl::Target::Array);
×
362
        vbo_texcoords.fill(gl_texcoords, ogl::Usage::Static);
×
363

364
        vbo_colors = ogl::VBO<ColorTriangle>(ogl::Target::Array);
×
365
        vbo_colors.fill(gl_colors, ogl::Usage::Static);
×
366

367
        // Unbind VBO to not interfere with other program parts
368
        vbo_colors.unbind();
×
369
    }
370
}
×
371

372
void TerrainRenderer::UpdateTrianglePos(const MapPoint pt, bool updateVBO)
×
373
{
374
    unsigned pos = GetTriangleIdx(pt);
×
375

376
    gl_vertices[pos][0] = GetVertexPos(pt);
×
377
    gl_vertices[pos][1] = GetNeighbourVertexPos(pt, Direction::SouthWest);
×
378
    gl_vertices[pos][2] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
379

380
    ++pos;
×
381

382
    gl_vertices[pos][0] = GetVertexPos(pt);
×
383
    gl_vertices[pos][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
384
    gl_vertices[pos][2] = GetNeighbourVertexPos(pt, Direction::East);
×
385

386
    if(updateVBO && vbo_vertices.isValid())
×
387
    {
388
        vbo_vertices.update(&gl_vertices[pos - 1], 2, pos - 1);
×
389
        vbo_vertices.unbind();
×
390
    }
391
}
×
392

393
void TerrainRenderer::UpdateTriangleColor(const MapPoint pt, bool updateVBO)
×
394
{
395
    unsigned pos = GetTriangleIdx(pt);
×
396

397
    Color& clr0 = gl_colors[pos][0];
×
398
    Color& clr1 = gl_colors[pos][1];
×
399
    Color& clr2 = gl_colors[pos][2];
×
400
    clr0.r = clr0.g = clr0.b = GetColor(pt);
×
401
    clr1.r = clr1.g = clr1.b = GetColor(GetNeighbour(pt, Direction::SouthWest));
×
402
    clr2.r = clr2.g = clr2.b = GetColor(GetNeighbour(pt, Direction::SouthEast));
×
403

404
    ++pos;
×
405

406
    Color& clr3 = gl_colors[pos][0];
×
407
    Color& clr4 = gl_colors[pos][1];
×
408
    Color& clr5 = gl_colors[pos][2];
×
409
    clr3.r = clr3.g = clr3.b = GetColor(pt);
×
410
    clr4.r = clr4.g = clr4.b = GetColor(GetNeighbour(pt, Direction::SouthEast));
×
411
    clr5.r = clr5.g = clr5.b = GetColor(GetNeighbour(pt, Direction::East));
×
412

413
    if(updateVBO && vbo_colors.isValid())
×
414
    {
415
        vbo_colors.update(&gl_colors[pos - 1], 2, pos - 1);
×
416
        vbo_colors.unbind();
×
417
    }
418
}
×
419

420
void TerrainRenderer::UpdateTriangleTerrain(const MapPoint pt, bool updateVBO)
×
421
{
422
    const unsigned nodeIdx = GetVertexIdx(pt);
×
423
    const DescIdx<TerrainDesc> t1 = terrain[nodeIdx][0];
×
424
    const DescIdx<TerrainDesc> t2 = terrain[nodeIdx][1];
×
425

426
    const unsigned triangleIdx = GetTriangleIdx(pt);
×
427
    gl_texcoords[triangleIdx] = terrainTextures[t1].rsuCoords;
×
428
    gl_texcoords[triangleIdx + 1] = terrainTextures[t2].usdCoords;
×
429

430
    if(updateVBO && vbo_texcoords.isValid())
×
431
    {
432
        vbo_texcoords.update(&gl_texcoords[triangleIdx - 1], 2, triangleIdx - 1);
×
433
        vbo_texcoords.unbind();
×
434
    }
435
}
×
436

437
/// Erzeugt die Dreiecke für die Ränder
438
void TerrainRenderer::UpdateBorderTrianglePos(const MapPoint pt, bool updateVBO)
×
439
{
440
    unsigned pos = GetVertexIdx(pt);
×
441

442
    // Für VBO-Aktualisierung:
443
    // Erzeugte Ränder zählen
444
    unsigned count_borders = 0;
×
445
    // Erstes Offset merken
446
    unsigned first_offset = 0;
×
447

448
    // Rand links - rechts
449
    for(unsigned char i = 0; i < 2; ++i)
×
450
    {
451
        if(!borders[pos].left_right[i])
×
452
            continue;
×
453
        unsigned offset = borders[pos].left_right_offset[i];
×
454

455
        if(!first_offset)
×
456
            first_offset = offset;
×
457

458
        gl_vertices[offset][i ? 0 : 2] = GetVertexPos(pt);
×
459
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
460
        gl_vertices[offset][i ? 2 : 0] = GetBorderPos(pt, i);
×
461

462
        ++count_borders;
×
463
    }
464

465
    // Rand rechts - links
466
    for(unsigned char i = 0; i < 2; ++i)
×
467
    {
468
        if(!borders[pos].right_left[i])
×
469
            continue;
×
470
        unsigned offset = borders[pos].right_left_offset[i];
×
471

472
        if(!first_offset)
×
473
            first_offset = offset;
×
474

475
        gl_vertices[offset][i ? 2 : 0] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
476
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::East);
×
477

478
        if(i == 0)
×
479
            gl_vertices[offset][2] = GetBorderPos(pt, 1);
×
480
        else
481
            gl_vertices[offset][0] = GetNeighbourBorderPos(pt, 0, Direction::East);
×
482

483
        ++count_borders;
×
484
    }
485

486
    // Rand oben - unten
487
    for(unsigned char i = 0; i < 2; ++i)
×
488
    {
489
        if(!borders[pos].top_down[i])
×
490
            continue;
×
491
        unsigned offset = borders[pos].top_down_offset[i];
×
492

493
        if(!first_offset)
×
494
            first_offset = offset;
×
495

496
        gl_vertices[offset][i ? 2 : 0] = GetNeighbourVertexPos(pt, Direction::SouthWest);
×
497
        gl_vertices[offset][1] = GetNeighbourVertexPos(pt, Direction::SouthEast);
×
498

499
        if(i == 0)
×
500
            gl_vertices[offset][2] = GetBorderPos(pt, i);
×
501
        else
502
            gl_vertices[offset][0] = GetNeighbourBorderPos(pt, i, Direction::SouthWest);
×
503

504
        ++count_borders;
×
505
    }
506

507
    if(updateVBO && vbo_vertices.isValid())
×
508
    {
509
        vbo_vertices.update(&gl_vertices[first_offset], count_borders, first_offset);
×
510
        vbo_vertices.unbind();
×
511
    }
512
}
×
513

514
void TerrainRenderer::UpdateBorderTriangleColor(const MapPoint pt, bool updateVBO)
×
515
{
516
    unsigned pos = GetVertexIdx(pt);
×
517

518
    // Für VBO-Aktualisierung:
519
    // Erzeugte Ränder zählen
520
    unsigned count_borders = 0;
×
521
    // Erstes Offset merken
522
    unsigned first_offset = 0;
×
523

524
    // Rand links - rechts
525
    for(unsigned char i = 0; i < 2; ++i)
×
526
    {
527
        if(!borders[pos].left_right[i])
×
528
            continue;
×
529
        unsigned offset = borders[pos].left_right_offset[i];
×
530

531
        if(!first_offset)
×
532
            first_offset = offset;
×
533

534
        gl_colors[offset][i ? 0 : 2].r = gl_colors[offset][i ? 0 : 2].g = gl_colors[offset][i ? 0 : 2].b =
×
535
          GetColor(pt); //-V807
×
536
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
537
          GetColor(GetNeighbour(pt, Direction::SouthEast)); //-V807
×
538
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
539
          GetBorderColor(pt, i); //-V807
×
540

541
        ++count_borders;
×
542
    }
543

544
    // Rand rechts - links
545
    for(unsigned char i = 0; i < 2; ++i)
×
546
    {
547
        if(!borders[pos].right_left[i])
×
548
            continue;
×
549
        unsigned offset = borders[pos].right_left_offset[i];
×
550

551
        if(!first_offset)
×
552
            first_offset = offset;
×
553

554
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
555
          GetColor(GetNeighbour(pt, Direction::SouthEast));
×
556
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
557
          GetColor(GetNeighbour(pt, Direction::East));
×
558
        MapPoint pt2(pt.x + i, pt.y);
×
559
        if(pt2.x >= size_.x)
×
560
            pt2.x -= size_.x;
×
561
        gl_colors[offset][i ? 0 : 2].r = gl_colors[offset][i ? 0 : 2].g = gl_colors[offset][i ? 0 : 2].b =
×
562
          GetBorderColor(pt2, i ? 0 : 1);
×
563

564
        ++count_borders;
×
565
    }
566

567
    // Rand oben - unten
568
    for(unsigned char i = 0; i < 2; ++i)
×
569
    {
570
        if(!borders[pos].top_down[i])
×
571
            continue;
×
572
        unsigned offset = borders[pos].top_down_offset[i];
×
573

574
        if(!first_offset)
×
575
            first_offset = offset;
×
576

577
        gl_colors[offset][i ? 2 : 0].r = gl_colors[offset][i ? 2 : 0].g = gl_colors[offset][i ? 2 : 0].b =
×
578
          GetColor(GetNeighbour(pt, Direction::SouthWest));
×
579
        gl_colors[offset][1].r = gl_colors[offset][1].g = gl_colors[offset][1].b =
×
580
          GetColor(GetNeighbour(pt, Direction::SouthEast));
×
581

582
        if(i == 0)
×
583
            gl_colors[offset][2].r = gl_colors[offset][2].g = gl_colors[offset][2].b = GetBorderColor(pt, i); //-V807
×
584
        else
585
            gl_colors[offset][0].r = gl_colors[offset][0].g = gl_colors[offset][0].b =
×
586
              GetBorderColor(GetNeighbour(pt, Direction::SouthWest), i); //-V807
×
587

588
        ++count_borders;
×
589
    }
590

591
    if(updateVBO && vbo_colors.isValid())
×
592
    {
593
        vbo_colors.update(&gl_colors[first_offset], count_borders, first_offset);
×
594
        vbo_colors.unbind();
×
595
    }
596
}
×
597

598
void TerrainRenderer::UpdateBorderTriangleTerrain(const MapPoint pt, bool updateVBO)
×
599
{
600
    unsigned pos = GetVertexIdx(pt);
×
601

602
    // For updating the VBO count created borders and first offset
603
    unsigned count_borders = 0;
×
604
    unsigned first_offset = 0;
×
605

606
    // left to right border
607
    for(unsigned char i = 0; i < 2; ++i)
×
608
    {
609
        if(borders[pos].left_right[i])
×
610
        {
611
            unsigned offset = borders[pos].left_right_offset[i];
×
612

613
            if(!first_offset)
×
614
                first_offset = offset;
×
615

616
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].left_right[i]];
×
617
            Extent bmpSize = texture.GetSize();
×
618
            PointF texSize(texture.GetTexSize());
×
619

620
            gl_texcoords[offset][i ? 0 : 2] = PointF(0.0f, 0.0f);
×
621
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
622
            gl_texcoords[offset][i ? 2 : 0] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
623

624
            ++count_borders;
×
625
        }
626
    }
627

628
    // right to left border
629
    for(unsigned char i = 0; i < 2; ++i)
×
630
    {
631
        if(borders[pos].right_left[i])
×
632
        {
633
            unsigned offset = borders[pos].right_left_offset[i];
×
634

635
            if(!first_offset)
×
636
                first_offset = offset;
×
637

638
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].right_left[i]];
×
639
            Extent bmpSize = texture.GetSize();
×
640
            PointF texSize(texture.GetTexSize());
×
641

642
            gl_texcoords[offset][i ? 2 : 0] = PointF(0.0f, 0.0f);
×
643
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
644
            gl_texcoords[offset][i ? 0 : 2] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
645

646
            ++count_borders;
×
647
        }
648
    }
649

650
    // top to bottom border
651
    for(unsigned char i = 0; i < 2; ++i)
×
652
    {
653
        if(borders[pos].top_down[i])
×
654
        {
655
            unsigned offset = borders[pos].top_down_offset[i];
×
656

657
            if(!first_offset)
×
658
                first_offset = offset;
×
659

660
            const glArchivItem_Bitmap& texture = *edgeTextures[borders[pos].top_down[i]];
×
661
            Extent bmpSize = texture.GetSize();
×
662
            PointF texSize(texture.GetTexSize());
×
663

664
            gl_texcoords[offset][i ? 2 : 0] = PointF(0.0f, 0.0f);
×
665
            gl_texcoords[offset][1] = PointF(bmpSize.x / texSize.x, 0.0f);
×
666
            gl_texcoords[offset][i ? 0 : 2] = PointF(bmpSize.x / texSize.x / 2.f, bmpSize.y / texSize.y);
×
667

668
            ++count_borders;
×
669
        }
670
    }
671

672
    if(updateVBO && vbo_texcoords.isValid())
×
673
    {
674
        vbo_texcoords.update(&gl_texcoords[first_offset], count_borders, first_offset);
×
675
        vbo_texcoords.unbind();
×
676
    }
677
}
×
678

679
void TerrainRenderer::Draw(const Position& firstPt, const Position& lastPt, const GameWorldViewer& gwv,
×
680
                           unsigned* water) const
681
{
682
    RTTR_Assert(!gl_vertices.empty());
×
683
    RTTR_Assert(!borders.empty());
×
684

685
    // Sort textures into lists by type
686
    DescriptionVector<std::vector<MapTile>, TerrainDesc> sorted_textures(terrainTextures.size());
×
687
    DescriptionVector<std::vector<BorderTile>, EdgeDesc> sorted_borders(edgeTextures.size());
×
688
    PreparedRoads sorted_roads(roadTextures.size());
×
689

690
    Position lastOffset(0, 0);
×
691

692
    // Only draw visible area
693
    for(auto const y : helpers::range(firstPt.y, lastPt.y + 1))
×
694
    {
695
        DescIdx<TerrainDesc> lastTerrain;
×
696
        DescIdx<EdgeDesc> lastBorder;
×
697

698
        for(auto const x : helpers::range(firstPt.x, lastPt.x + 1))
×
699
        {
700
            Position posOffset;
×
701
            MapPoint tP = ConvertCoords(Position(x, y), &posOffset);
×
702

703
            auto t = terrain[GetVertexIdx(tP)][0];
×
704
            if(posOffset != lastOffset)
×
705
                lastTerrain = DescIdx<TerrainDesc>();
×
706

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

716
            t = terrain[GetVertexIdx(tP)][1];
×
717

718
            if(t == lastTerrain)
×
719
                ++sorted_textures[t].back().count;
×
720
            else
721
            {
722
                MapTile tmp(GetTriangleIdx(tP) + 1, posOffset);
×
723
                sorted_textures[t].push_back(tmp);
×
724
            }
725

726
            lastTerrain = t;
×
727

728
            const Borders& curBorders = borders[GetVertexIdx(tP)];
×
729
            helpers::EnumArray<DescIdx<EdgeDesc>, Direction> tiles = {
730
              {curBorders.left_right[0], curBorders.left_right[1], curBorders.right_left[0], curBorders.right_left[1],
×
731
               curBorders.top_down[0], curBorders.top_down[1]}};
×
732

733
            // Offsets into gl_* arrays
734
            helpers::EnumArray<unsigned, Direction> offsets = {
735
              {curBorders.left_right_offset[0], curBorders.left_right_offset[1], curBorders.right_left_offset[0],
×
736
               curBorders.right_left_offset[1], curBorders.top_down_offset[0], curBorders.top_down_offset[1]}};
×
737

738
            for(const auto dir : helpers::EnumRange<Direction>{})
×
739
            {
740
                if(!tiles[dir])
×
741
                    continue;
×
742
                if(tiles[dir] == lastBorder)
×
743
                {
744
                    BorderTile& curTile = sorted_borders[lastBorder].back();
×
745
                    // Check that we did not wrap around the map and the expected offset matches
746
                    if(curTile.tileOffset + curTile.count == offsets[dir])
×
747
                    {
748
                        ++curTile.count;
×
749
                        continue;
×
750
                    }
751
                }
752
                lastBorder = tiles[dir];
×
753
                BorderTile tmp(offsets[dir], posOffset);
×
754
                sorted_borders[lastBorder].push_back(tmp);
×
755
            }
756

757
            PrepareWaysPoint(sorted_roads, gwv, tP, posOffset);
×
758

759
            lastOffset = posOffset;
×
760
        }
761
    }
762

763
    if(water)
×
764
    {
765
        const WorldDescription& desc = gwv.GetWorld().GetDescription();
×
766
        unsigned water_count = 0;
×
767
        for(const auto t : sorted_textures.indices())
×
768
        {
769
            if(desc.get(t).kind == TerrainKind::Water)
×
770
            {
771
                for(const MapTile& tile : sorted_textures[t])
×
772
                    water_count += tile.count;
×
773
            }
774
        }
775

776
        Position diff =
777
          lastPt - firstPt + Position(1, 1); // Number of points checked in X and Y, including(!) the last one
×
778
        // For each point there are 2 tiles added (USD, RSU) so we have 2 times the tiles as the number of points.
779
        // Calculate the percentage of water tiles
780
        *water = 100 * water_count / (2 * prodOfComponents(diff));
×
781
    }
782

783
    lastOffset = Position(0, 0);
×
784

785
    glEnableClientState(GL_COLOR_ARRAY);
×
786

787
    if(vbo_vertices.isValid())
×
788
    {
789
        vbo_vertices.bind();
×
790
        glVertexPointer(2, GL_FLOAT, 0, nullptr);
×
791

792
        vbo_texcoords.bind();
×
793
        glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
×
794

795
        vbo_colors.bind();
×
796
        glColorPointer(3, GL_FLOAT, 0, nullptr);
×
797
    } else
798
    {
799
        glVertexPointer(2, GL_FLOAT, 0, &gl_vertices.front());
×
800
        glTexCoordPointer(2, GL_FLOAT, 0, &gl_texcoords.front());
×
801
        glColorPointer(3, GL_FLOAT, 0, &gl_colors.front());
×
802
    }
803

804
#if RTTR_OGL_GL4ES
805
    // Gl4ES behaves weird with GL_COMBINE. All textures are too bright and some shadows are missing. The function might
806
    // not be implemented in GL4ES at all.
807
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
808
#else
809
    // Modulate2x
810
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
×
NEW
811
    glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, TEXTURE_COLOR_DIVISOR);
×
812
#endif
813

814
    // Disable alpha blending
815
    glDisable(GL_BLEND);
×
816

817
    glPushMatrix();
×
818
    for(const auto t : sorted_textures.indices())
×
819
    {
820
        if(sorted_textures[t].empty())
×
821
            continue;
×
822
        unsigned animationFrame;
823
        const unsigned numFrames = terrainTextures[t].textures.size();
×
824
        if(numFrames > 1)
×
825
            animationFrame = GAMECLIENT.GetGlobalAnimation(numFrames, 5 * numFrames, 16, 0); // We have 5/16 per frame
×
826
        else
827
            animationFrame = 0;
×
828

829
        VIDEODRIVER.BindTexture(terrainTextures[t].textures[animationFrame].GetTextureNoCreate());
×
830

831
        for(const auto& texture : sorted_textures[t])
×
832
        {
833
            if(texture.posOffset != lastOffset)
×
834
            {
835
                Position trans = texture.posOffset - lastOffset;
×
836
                glTranslatef(float(trans.x), float(trans.y), 0.0f);
×
837
                lastOffset = texture.posOffset;
×
838
            }
839

840
            RTTR_Assert(texture.tileOffset + texture.count <= size_.x * size_.y * 2u);
×
841
            glDrawArrays(GL_TRIANGLES, texture.tileOffset * 3,
×
842
                         texture.count * 3); // Arguments are in Elements. 1 triangle has 3 values
×
843
        }
844
    }
845
    glPopMatrix();
×
846

847
    glEnable(GL_BLEND);
×
848

849
    lastOffset = Position(0, 0);
×
850
    glPushMatrix();
×
851
    for(const auto i : sorted_borders.indices())
×
852
    {
853
        if(sorted_borders[i].empty())
×
854
            continue;
×
855
        VIDEODRIVER.BindTexture(edgeTextures[i]->GetTextureNoCreate());
×
856

857
        for(const auto& texture : sorted_borders[i])
×
858
        {
859
            if(texture.posOffset != lastOffset)
×
860
            {
861
                Position trans = texture.posOffset - lastOffset;
×
862
                glTranslatef(float(trans.x), float(trans.y), 0.0f);
×
863
                lastOffset = texture.posOffset;
×
864
            }
865
            RTTR_Assert(texture.tileOffset + texture.count <= gl_vertices.size());
×
866
            glDrawArrays(GL_TRIANGLES, texture.tileOffset * 3,
×
867
                         texture.count * 3); // Arguments are in elements. 1 triangle has 3 values
×
868
        }
869
    }
870
    glPopMatrix();
×
871

872
    // unbind VBO
873
    if(vbo_vertices.isValid())
×
874
        vbo_vertices.unbind();
×
875

876
    DrawWays(sorted_roads);
×
877

878
    glDisableClientState(GL_COLOR_ARRAY);
×
879
    // Switch back to modulation
880
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
×
881
}
×
882

883
MapPoint TerrainRenderer::ConvertCoords(const Position pt, Position* offset) const
12✔
884
{
885
    MapPoint ptOut = MakeMapPoint(pt, size_);
12✔
886
    RTTR_Assert(ptOut.x < size_.x);
12✔
887
    RTTR_Assert(ptOut.y < size_.y);
12✔
888
    if(offset)
12✔
889
    {
890
        // We need the offset by which we shifted the point in screen units
891
        *offset = (pt - ptOut) * Extent(TR_W, TR_H);
12✔
892
    }
893
    return ptOut;
12✔
894
}
895

896
void TerrainRenderer::PrepareWaysPoint(PreparedRoads& sorted_roads, const GameWorldViewer& gwViewer, MapPoint pt,
×
897
                                       const Position& offset) const
898
{
899
    const WorldDescription& desc = gwViewer.GetWorld().GetDescription();
×
900
    Position startPos = Position(Position::Truncate, GetVertexPos(pt)) + offset;
×
901

902
    Visibility visibility = gwViewer.GetVisibility(pt);
×
903

904
    int totalWidth = size_.x * TR_W;
×
905
    int totalHeight = size_.y * TR_H;
×
906

907
    // Wegtypen für die drei Richtungen
908
    for(const RoadDir dir : helpers::EnumRange<RoadDir>{})
×
909
    {
910
        const PointRoad type = gwViewer.GetVisibleRoad(pt, dir, visibility);
×
911
        if(type == PointRoad::None)
×
912
            continue;
×
913
        const Direction targetDir = toDirection(dir);
×
914
        MapPoint ta = gwViewer.GetNeighbour(pt, targetDir);
×
915

916
        Position endPos = Position(Position::Truncate, GetVertexPos(ta)) + offset;
×
917
        Position diff = startPos - endPos;
×
918

919
        // Gehen wir über einen Kartenrand (horizontale Richung?)
920
        if(std::abs(diff.x) >= totalWidth / 2)
×
921
        {
922
            if(std::abs(endPos.x - totalWidth - startPos.x) < std::abs(diff.x))
×
923
                endPos.x -= totalWidth;
×
924
            else
925
                endPos.x += totalWidth;
×
926
        }
927
        // Und dasselbe für vertikale Richtung
928
        if(std::abs(diff.y) >= totalHeight / 2)
×
929
        {
930
            if(std::abs(endPos.y - totalHeight - startPos.y) < std::abs(diff.y))
×
931
                endPos.y -= totalHeight;
×
932
            else
933
                endPos.y += totalHeight;
×
934
        }
935

936
        // The gfx road type is:
937
        // Boat for boat roads
938
        // else Mountain left or right is a mountain terrain
939
        // else Upgraded for Donkey roads
940
        // else Normal
941
        uint8_t gfxRoadType;
942
        const auto terrain = gwViewer.GetWorld().GetTerrain(pt, targetDir);
×
943
        const TerrainDesc& lTerrain = desc.get(terrain.left);
×
944
        if(type == PointRoad::Boat)
×
945
        {
946
            gfxRoadType = getFlatIndex(lTerrain.landscape, LandRoadType::Boat);
×
947
        } else
948
        {
949
            if(desc.get(terrain.left).kind == TerrainKind::Mountain)
×
950
                gfxRoadType = getFlatIndex(lTerrain.landscape, LandRoadType::Mountain);
×
951
            else
952
            {
953
                const TerrainDesc& rTerrain = desc.get(terrain.right);
×
954
                if(rTerrain.kind == TerrainKind::Mountain)
×
955
                    gfxRoadType = getFlatIndex(rTerrain.landscape, LandRoadType::Mountain);
×
956
                else
957
                    gfxRoadType =
×
958
                      getFlatIndex(lTerrain.landscape,
×
959
                                   ((type == PointRoad::Donkey) ? LandRoadType::Upgraded : LandRoadType::Normal));
960
            }
961
        }
962

963
        sorted_roads[gfxRoadType].push_back(PreparedRoad(startPos, endPos, GetColor(pt), GetColor(ta), dir));
×
964
    }
965
}
×
966

967
struct Tex2C3Ver2
968
{
969
    GLfloat tx, ty;
970
    GLfloat r, g, b;
971
    GLfloat x, y;
972
};
973

974
void TerrainRenderer::DrawWays(const PreparedRoads& sorted_roads) const
×
975
{
976
    static constexpr helpers::EnumArray<std::array<Position, 4>, RoadDir> begin_end_coords = {{
977
      {{Position(0, -3), Position(0, 3), Position(3, 3), Position(3, -3)}},
978
      {{Position(2, -4), Position(-4, 2), Position(0, 6), Position(6, 0)}},
979
      {{Position(4, 2), Position(-2, -4), Position(-6, 0), Position(0, 6)}},
980
    }};
981

982
    size_t maxSize = 0;
×
983
    for(const std::vector<PreparedRoad>& sorted_road : sorted_roads)
×
984
        maxSize = std::max(maxSize, sorted_road.size());
×
985

986
    if(maxSize == 0)
×
987
        return;
×
988

989
    auto vertexData = std::unique_ptr<Tex2C3Ver2[]>(new Tex2C3Ver2[maxSize * 4]);
×
990
    // These should still be enabled
991
    RTTR_Assert(glIsEnabled(GL_VERTEX_ARRAY));
×
992
    RTTR_Assert(glIsEnabled(GL_TEXTURE_COORD_ARRAY));
×
993
    RTTR_Assert(glIsEnabled(GL_COLOR_ARRAY));
×
994
    glVertexPointer(2, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].x);
×
995
    glTexCoordPointer(2, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].tx);
×
996
    glColorPointer(3, GL_FLOAT, sizeof(Tex2C3Ver2), &vertexData[0].r);
×
997

998
    for(const auto itRoad : sorted_roads | boost::adaptors::indexed())
×
999
    {
1000
        if(itRoad.value().empty())
×
1001
            continue;
×
1002
        Tex2C3Ver2* curVertexData = vertexData.get();
×
1003
        const glArchivItem_Bitmap& texture = *roadTextures[itRoad.index()];
×
1004
        PointF scaledTexSize = texture.GetSize() / PointF(texture.GetTexSize());
×
1005

1006
        for(const auto& it : itRoad.value())
×
1007
        {
1008
            curVertexData->tx = 0.0f;
×
1009
            curVertexData->ty = 0.0f;
×
1010
            curVertexData->r = curVertexData->g = curVertexData->b = it.color1;
×
1011
            Position tmpP = it.pos + begin_end_coords[it.dir][0];
×
1012
            curVertexData->x = GLfloat(tmpP.x);
×
1013
            curVertexData->y = GLfloat(tmpP.y);
×
1014

1015
            curVertexData++;
×
1016

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

1024
            curVertexData++;
×
1025

1026
            curVertexData->tx = scaledTexSize.x;
×
1027
            curVertexData->ty = scaledTexSize.y;
×
1028
            curVertexData->r = curVertexData->g = curVertexData->b = it.color2;
×
1029
            tmpP = it.pos2 + begin_end_coords[it.dir][2];
×
1030
            curVertexData->x = GLfloat(tmpP.x);
×
1031
            curVertexData->y = GLfloat(tmpP.y);
×
1032

1033
            curVertexData++;
×
1034
            curVertexData->tx = scaledTexSize.x;
×
1035
            curVertexData->ty = 0.0f;
×
1036
            curVertexData->r = curVertexData->g = curVertexData->b = it.color2;
×
1037
            tmpP = it.pos2 + begin_end_coords[it.dir][3];
×
1038
            curVertexData->x = GLfloat(tmpP.x);
×
1039
            curVertexData->y = GLfloat(tmpP.y);
×
1040

1041
            curVertexData++;
×
1042
        }
1043

1044
        VIDEODRIVER.BindTexture(texture.GetTextureNoCreate());
×
1045
        glDrawArrays(GL_QUADS, 0, itRoad.value().size() * 4);
×
1046
    }
1047
    // Note: No glDisableClientState as we did not enable it
1048
}
1049

1050
void TerrainRenderer::AltitudeChanged(const MapPoint pt, const GameWorldViewer& gwv)
×
1051
{
1052
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1053
    UpdateVertexPos(pt, gwv);
×
1054
    UpdateVertexColor(pt, gwv);
×
1055

1056
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1057
        UpdateVertexColor(nb, gwv);
×
1058

1059
    // und für die Ränder
1060
    UpdateBorderVertex(pt);
×
1061

1062
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1063
        UpdateBorderVertex(nb);
×
1064

1065
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1066
    UpdateTrianglePos(pt, true);
×
1067
    UpdateTriangleColor(pt, true);
×
1068

1069
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1070
    {
1071
        UpdateTrianglePos(nb, true);
×
1072
        UpdateTriangleColor(nb, true);
×
1073
    }
1074

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

1080
    // und für die Ränder
1081
    UpdateBorderTrianglePos(pt, true);
×
1082
    UpdateBorderTriangleColor(pt, true);
×
1083

1084
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1085
    {
1086
        UpdateBorderTrianglePos(nb, true);
×
1087
        UpdateBorderTriangleColor(nb, true);
×
1088
    }
1089

1090
    for(unsigned i = 0; i < 12; ++i)
×
1091
        UpdateBorderTriangleColor(gwv.GetWorld().GetNeighbour2(pt, i), true);
×
1092
}
×
1093

1094
void TerrainRenderer::VisibilityChanged(const MapPoint pt, const GameWorldViewer& gwv)
×
1095
{
1096
    /// Noch kein Terrain gebaut? abbrechen
1097
    if(vertices.empty())
×
1098
        return;
×
1099

1100
    UpdateVertexColor(pt, gwv);
×
1101
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1102
        UpdateVertexColor(nb, gwv);
×
1103

1104
    // und für die Ränder
1105
    UpdateBorderVertex(pt);
×
1106
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1107
        UpdateBorderVertex(nb);
×
1108

1109
    // den selbst sowieso die Punkte darum updaten, da sich bei letzteren die Schattierung geändert haben könnte
1110
    UpdateTriangleColor(pt, true);
×
1111
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1112
        UpdateTriangleColor(nb, true);
×
1113

1114
    // und für die Ränder
1115
    UpdateBorderTriangleColor(pt, true);
×
1116
    for(const MapPoint nb : gwv.GetNeighbours(pt))
×
1117
        UpdateBorderTriangleColor(nb, true);
×
1118
}
1119

1120
void TerrainRenderer::UpdateAllColors(const GameWorldViewer& gwv)
×
1121
{
1122
    RTTR_FOREACH_PT(MapPoint, size_)
×
1123
        UpdateVertexColor(pt, gwv);
×
1124

1125
    RTTR_FOREACH_PT(MapPoint, size_)
×
1126
        UpdateBorderVertex(pt);
×
1127

1128
    RTTR_FOREACH_PT(MapPoint, size_)
×
1129
        UpdateTriangleColor(pt, false);
×
1130

1131
    RTTR_FOREACH_PT(MapPoint, size_)
×
1132
        UpdateBorderTriangleColor(pt, false);
×
1133

1134
    if(vbo_colors.isValid())
×
1135
    {
1136
        vbo_colors.update(gl_colors);
×
1137
        vbo_colors.unbind();
×
1138
    }
1139
}
×
1140

1141
MapPoint TerrainRenderer::GetNeighbour(const MapPoint& pt, const Direction dir) const
×
1142
{
1143
    return MakeMapPoint(::GetNeighbour(Position(pt), dir), size_);
×
1144
}
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