diff --git a/CIO/CFile.cpp b/CIO/CFile.cpp index 023d89f..cc0de8d 100644 --- a/CIO/CFile.cpp +++ b/CIO/CFile.cpp @@ -570,10 +570,19 @@ bobMAP* CFile::read_wld(FILE* fp) // go to texture information for UpSideDown-Triangles fseek(fp, 16, SEEK_CUR); + // Read usdTexture: file → memory (align with s25client coordinate system). + // s25client MapLoader::InitNodes: + // unsigned char t2 = map.getMapDataAt(MapLayer::Terrain2, pt.x, pt.y); + // node.t2 = getTerrainFromS2(t2 & 0x3F); // stored at same visual (pt.x, pt.y) as t1 + // s25edit WLD file stores USD offsets that need shifting to match client: + // even rows: memory(i, j) = file(i-1, j) for(int j = 0; j < myMap->height; j++) { for(int i = 0; i < myMap->width; i++) - CHECK_READ(libendian::read(&myMap->getVertex(i, j).usdTexture, 1, fp)); + { + const int dest_i = (i + !(j & 1)) % myMap->width; + CHECK_READ(libendian::read(&myMap->getVertex(dest_i, j).usdTexture, 1, fp)); + } } // go to road data @@ -833,10 +842,14 @@ bool CFile::save_wld(FILE* fp, void* data) // go to texture information for UpSideDown-Triangles libendian::write(map_data_header, fp); + // Write usdTexture: inverse of read shift. for(int j = 0; j < myMap->height; j++) { for(int i = 0; i < myMap->width; i++) - libendian::write(&myMap->getVertex(i, j).usdTexture, 1, fp); + { + const int src_i = (i + !(j & 1)) % myMap->width; + libendian::write(&myMap->getVertex(src_i, j).usdTexture, 1, fp); + } } // go to road data diff --git a/CMap.cpp b/CMap.cpp index 75f50d7..4a56c76 100644 --- a/CMap.cpp +++ b/CMap.cpp @@ -8,8 +8,20 @@ #include "CIO/CFile.h" #include "CIO/CFont.h" #include "CSurface.h" +#include "Geometry.h" #include "callbacks.h" #include "globals.h" + +// I/O shift: for even rows, vertex(x,y).usdTexture = file(x-1,y). +// Read .usdTexture from (x+1, y) to get the value for visual (x, y). +static uint8_t usdAt(const bobMAP& map, int x, int y) +{ + if(y % 2 == 0) + { + x = (x + 1 >= map.width) ? 0 : x + 1; + } + return map.getVertex(x, y).usdTexture; +} #include "gameData/LandscapeDesc.h" #include "gameData/TerrainDesc.h" #include @@ -1774,6 +1786,13 @@ void CMap::modifyShading(Position pos) void CMap::modifyTexture(Position pos, bool rsu, bool usd) { + // s25client TerrainRenderer::UpdateTriangleTerrain reads both textures from the same vertex: + // terrain[nodeIdx][0] = RSU at (x, y) + // terrain[nodeIdx][1] = USD at (x, y) - same vertex as RSU + // After I/O shift: for even rows, USD at visual (pos) is at vertex(pos.x+1, pos.y). + MapNode& vertex = map->getVertex(clientUsdVertexPos(pos)); + // Separate vertex for USD writes on even rows (I/O shift) + MapNode& usdVertex = (pos.y % 2 == 0) ? map->getVertex((pos.x + 1 >= map->width) ? 0 : pos.x + 1, pos.y) : vertex; if(modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED || modeContent == TRIANGLE_TEXTURE_MEADOW_MIXED_HARBOUR) { int newContent = rand() % 3; @@ -1797,15 +1816,15 @@ void CMap::modifyTexture(Position pos, bool rsu, bool usd) newContent = TRIANGLE_TEXTURE_MEADOW3_HARBOUR; } if(rsu) - map->getVertex(pos.x, pos.y).rsuTexture = newContent; + vertex.rsuTexture = newContent; if(usd) - map->getVertex(pos.x, pos.y).usdTexture = newContent; + usdVertex.usdTexture = newContent; } else { if(rsu) - map->getVertex(pos.x, pos.y).rsuTexture = modeContent; + vertex.rsuTexture = modeContent; if(usd) - map->getVertex(pos.x, pos.y).usdTexture = modeContent; + usdVertex.usdTexture = modeContent; } // at least setup the possible building and the resources at the vertex and 1 section/2 sections around @@ -2025,7 +2044,7 @@ void CMap::modifyBuild(Position pos) const Uint8 height = curVertex.h; std::array mapVertices; for(unsigned i = 0; i < mapVertices.size(); i++) - mapVertices[i] = &map->getVertex(tempVertices[i]); + mapVertices[i] = &map->getVertex(clientUsdVertexPos(tempVertices[i].x, tempVertices[i].y)); // calculate the building using the height of the vertices // this building is a mine @@ -2113,13 +2132,17 @@ void CMap::modifyBuild(Position pos) // test if there is snow or lava at the vertex or around the vertex and touching the vertex (first section) if(building > 0x00) { - if(mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_SNOW - || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_LAVA || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_LAVA - || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_SNOW - || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_LAVA || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_LAVA + if(mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_SNOW + || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_LAVA + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_LAVA + || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_SNOW + || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_LAVA + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_LAVA || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_LAVA - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_SNOW - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_LAVA) + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_LAVA) { building = 0x00; } @@ -2129,10 +2152,12 @@ void CMap::modifyBuild(Position pos) if(building > 0x01) { if(mapVertices[4]->rsuTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[4]->rsuTexture == TRIANGLE_TEXTURE_LAVA - || mapVertices[5]->usdTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[5]->usdTexture == TRIANGLE_TEXTURE_LAVA - || mapVertices[6]->rsuTexture == TRIANGLE_TEXTURE_SNOW || mapVertices[6]->usdTexture == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[5]->VertexX, mapVertices[5]->VertexY) == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[5]->VertexX, mapVertices[5]->VertexY) == TRIANGLE_TEXTURE_LAVA + || mapVertices[6]->rsuTexture == TRIANGLE_TEXTURE_SNOW + || usdAt(*map, mapVertices[6]->VertexX, mapVertices[6]->VertexY) == TRIANGLE_TEXTURE_SNOW || mapVertices[6]->rsuTexture == TRIANGLE_TEXTURE_LAVA - || mapVertices[6]->usdTexture == TRIANGLE_TEXTURE_LAVA) + || usdAt(*map, mapVertices[6]->VertexX, mapVertices[6]->VertexY) == TRIANGLE_TEXTURE_LAVA) { building = 0x01; } @@ -2143,30 +2168,30 @@ void CMap::modifyBuild(Position pos) { if((mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - && (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_SWAMP) + && (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_SWAMP) && (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - && (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_SWAMP) + && (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_SWAMP) && (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - && (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_SWAMP)) + && (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_SWAMP)) { building = 0x00; } else if((mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - || (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_SWAMP) + || (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_SWAMP) || (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - || (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_SWAMP) + || (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_SWAMP) || (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_WATER || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_SWAMP) - || (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_WATER - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_SWAMP)) + || (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_SWAMP)) { building = 0x01; } @@ -2176,11 +2201,11 @@ void CMap::modifyBuild(Position pos) if(building > 0x01) { if(mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_STEPPE - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_STEPPE + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_STEPPE || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_STEPPE - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_STEPPE + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_STEPPE || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_STEPPE - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_STEPPE) + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_STEPPE) { building = 0x01; } @@ -2193,52 +2218,52 @@ void CMap::modifyBuild(Position pos) || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING4) + && (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING4) && (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING4) + && (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING4) && (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING4)) + && (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING4)) { building = 0x05; } else if((mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - || (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING4) + || (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING4) || (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - || (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING4) + || (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING4) || (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - || (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING4)) + || (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING4)) { building = 0x01; } @@ -2292,7 +2317,7 @@ void CMap::modifyResource(Position pos) MapNode& curVertex = map->getVertex(pos.x, pos.y); std::array mapVertices; for(unsigned i = 0; i < mapVertices.size(); i++) - mapVertices[i] = &map->getVertex(tempVertices[i]); + mapVertices[i] = &map->getVertex(clientUsdVertexPos(tempVertices[i].x, tempVertices[i].y)); // SPECIAL CASE: test if we should set water only // test if vertex is surrounded by meadow and meadow-like textures @@ -2310,20 +2335,20 @@ void CMap::modifyResource(Position pos) || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) - && (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW1 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW1_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW2 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW2_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW3 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MEADOW3_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_FLOWER - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) + && (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW1 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW2 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW3 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MEADOW3_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_FLOWER + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_FLOWER_HARBOUR + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) && (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MEADOW1 @@ -2338,20 +2363,20 @@ void CMap::modifyResource(Position pos) || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) - && (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW1 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW1_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW2 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW2_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW3 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MEADOW3_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_FLOWER - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) + && (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW1 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW2 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW3 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MEADOW3_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_FLOWER + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_FLOWER_HARBOUR + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) && (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MEADOW1 @@ -2366,49 +2391,49 @@ void CMap::modifyResource(Position pos) || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR) - && (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW1 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW1_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW2 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW2_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW3 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MEADOW3_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_FLOWER - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_FLOWER_HARBOUR - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR)) + && (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW1 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW1_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW2 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW3 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MEADOW3_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_STEPPE_MEADOW2_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_FLOWER + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_FLOWER_HARBOUR + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING_MEADOW_HARBOUR)) { curVertex.resource = 0x21; } // SPECIAL CASE: test if we should set fishes only // test if vertex is surrounded by water (first section) and at least one non-water texture in the second section else if((mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_WATER) - && (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_WATER) + && (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_WATER) && (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_WATER) - && (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_WATER) + && (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_WATER) && (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_WATER) - && (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_WATER) - && (mapVertices[2]->usdTexture != TRIANGLE_TEXTURE_WATER + && (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_WATER) + && (usdAt(*map, mapVertices[2]->VertexX, mapVertices[2]->VertexY) != TRIANGLE_TEXTURE_WATER || mapVertices[3]->rsuTexture != TRIANGLE_TEXTURE_WATER || mapVertices[4]->rsuTexture != TRIANGLE_TEXTURE_WATER - || mapVertices[4]->usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[4]->VertexX, mapVertices[4]->VertexY) != TRIANGLE_TEXTURE_WATER || mapVertices[5]->rsuTexture != TRIANGLE_TEXTURE_WATER - || mapVertices[5]->usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[5]->VertexX, mapVertices[5]->VertexY) != TRIANGLE_TEXTURE_WATER || mapVertices[6]->rsuTexture != TRIANGLE_TEXTURE_WATER - || mapVertices[6]->usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, mapVertices[6]->VertexX, mapVertices[6]->VertexY) != TRIANGLE_TEXTURE_WATER || map->getVertex(tempVertices[7]).rsuTexture != TRIANGLE_TEXTURE_WATER - || map->getVertex(tempVertices[7]).usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, tempVertices[7].x, tempVertices[7].y) != TRIANGLE_TEXTURE_WATER || map->getVertex(tempVertices[8]).rsuTexture != TRIANGLE_TEXTURE_WATER - || map->getVertex(tempVertices[8]).usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, tempVertices[8].x, tempVertices[8].y) != TRIANGLE_TEXTURE_WATER || map->getVertex(tempVertices[9]).rsuTexture != TRIANGLE_TEXTURE_WATER || map->getVertex(tempVertices[10]).rsuTexture != TRIANGLE_TEXTURE_WATER - || map->getVertex(tempVertices[10]).usdTexture != TRIANGLE_TEXTURE_WATER + || usdAt(*map, tempVertices[10].x, tempVertices[10].y) != TRIANGLE_TEXTURE_WATER || map->getVertex(tempVertices[11]).rsuTexture != TRIANGLE_TEXTURE_WATER - || map->getVertex(tempVertices[12]).usdTexture != TRIANGLE_TEXTURE_WATER - || map->getVertex(tempVertices[14]).usdTexture != TRIANGLE_TEXTURE_WATER)) + || usdAt(*map, tempVertices[12].x, tempVertices[12].y) != TRIANGLE_TEXTURE_WATER + || usdAt(*map, tempVertices[14].x, tempVertices[14].y) != TRIANGLE_TEXTURE_WATER)) { curVertex.resource = 0x87; } @@ -2417,26 +2442,26 @@ void CMap::modifyResource(Position pos) || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[0]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[0]->usdTexture == TRIANGLE_TEXTURE_MINING4) + && (usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[0]->VertexX, mapVertices[0]->VertexY) == TRIANGLE_TEXTURE_MINING4) && (mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[1]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[1]->usdTexture == TRIANGLE_TEXTURE_MINING4) + && (usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[1]->VertexX, mapVertices[1]->VertexY) == TRIANGLE_TEXTURE_MINING4) && (mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING1 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING2 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING3 || mapVertices[2]->rsuTexture == TRIANGLE_TEXTURE_MINING4) - && (mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING1 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING2 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING3 - || mapVertices[3]->usdTexture == TRIANGLE_TEXTURE_MINING4)) + && (usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING1 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING2 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING3 + || usdAt(*map, mapVertices[3]->VertexX, mapVertices[3]->VertexY) == TRIANGLE_TEXTURE_MINING4)) { // check which resource to set if(mode == EDITOR_MODE_RESOURCE_RAISE) diff --git a/CSurface.cpp b/CSurface.cpp index 18cc1ce..3039a59 100644 --- a/CSurface.cpp +++ b/CSurface.cpp @@ -390,47 +390,64 @@ void CSurface::DrawTriangleField(SDL_Surface* display, const DisplayRectangle& d { if(y % 2 == 0) { - // first RightSideUp + // first RightSideUp at column 0 (seam wrap) tempP2 = myMap.getVertex(width - 1, y + 1); tempP2.x = 0; DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(0, y), tempP2, myMap.getVertex(0, y + 1)); for(unsigned x = std::max(col_start, 1); x < width && x <= static_cast(col_end); x++) { - // RightSideUp + // RSU at column x — s25client UpdateTrianglePos[0]: [pt, SW(pt), SE(pt)] DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x - 1, y + 1), myMap.getVertex(x, y + 1)); - // UpSideDown - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x - 1, y + 1), - myMap.getVertex(x - 1, y), myMap.getVertex(x, y)); + // USD at visual column x-1 — same vertices as master. + // Texture read unshift is applied inside DrawTriangle. + DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x - 1, y + 1), // P1 + myMap.getVertex(x - 1, y), // P2 (reads usdTexture, unshifted internally) + myMap.getVertex(x, y)); // P3 + } + // last UpSideDown at column width-1 (wrap) — same vertices as master. + { + const int w = static_cast(width); + MapNode tP3 = myMap.getVertex(0, y); + tP3.x = myMap.getVertex(w - 1, y).x + triangleWidth; + DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(w - 1, y + 1), // P1 + myMap.getVertex(w - 1, y), // P2 (reads usdTexture, unshifted internally) + tP3); // P3 } - // last UpSideDown - tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(width - 1, y + 1), - myMap.getVertex(width - 1, y), tempP3); } else { for(unsigned x = col_start; x < width - 1u && x <= static_cast(col_end); x++) { - // RightSideUp + // RSU at column x — s25client UpdateTrianglePos[0]: [pt, SW(pt), SE(pt)] DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x, y), myMap.getVertex(x, y + 1), myMap.getVertex(x + 1, y + 1)); - // UpSideDown - DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x + 1, y + 1), - myMap.getVertex(x, y), myMap.getVertex(x + 1, y)); + // USD at column x — s25client UpdateTrianglePos[1]: [pt, SE(pt), E(pt)] + DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(x + 1, y + 1), // P1 = SE(x, y) + myMap.getVertex(x, y), // P2 = pt (reads usdTexture) + myMap.getVertex(x + 1, y)); // P3 = E(x, y) } - // last RightSideUp + // last RSU at column width-1 (wrap) tempP3 = myMap.getVertex(0, y + 1); tempP3.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; DrawTriangle(display, displayRect, myMap, type, myMap.getVertex(width - 1, y), myMap.getVertex(width - 1, y + 1), tempP3); - // last UpSideDown - tempP1 = myMap.getVertex(0, y + 1); - tempP1.x = myMap.getVertex(width - 1, y + 1).x + triangleWidth; - tempP3 = myMap.getVertex(0, y); - tempP3.x = myMap.getVertex(width - 1, y).x + triangleWidth; - DrawTriangle(display, displayRect, myMap, type, tempP1, myMap.getVertex(width - 1, y), tempP3); + // last UpSideDown at column width-1 (wrap). + // s25client UpdateTrianglePos[1] at (w-1, y): + // pt = (w-1, y), SE = (w-1 + (y&1), y+1) for odd y: (w, y+1) → wraps to (0, y+1) + // E = (w, y) → wraps to (0, y) + // Odd rows have no I/O shift, P2 = (w-1, y) reads file(w-1, y) correctly. + { + const int w = static_cast(width); + MapNode tP1 = myMap.getVertex(0, y + 1); + tP1.x = myMap.getVertex(w - 1, y + 1).x + triangleWidth; + MapNode tP3 = myMap.getVertex(0, y); + tP3.x = myMap.getVertex(w - 1, y).x + triangleWidth; + DrawTriangle(display, displayRect, myMap, type, + tP1, // P1 = SE(w-1, y) with x-shifted + myMap.getVertex(w - 1, y), // P2 = pt + tP3); // P3 = E(w-1, y) with x-shifted + } } } @@ -847,8 +864,21 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa { // upper2, ..... are for special use in winterland. Point16 upper, left, right, upper2, left2, right2; - auto const texture = - TriangleTerrainType((isRSU ? P1.rsuTexture : P2.usdTexture) & ~0x40); // Mask out harbor bit + // I/O shift: USD data at vertex(x,y) = file(x-1,y) for even rows. + // Read from (P2.VertexX+1, P2.VertexY) to get USD at visual (P2.VertexX, P2.VertexY). + uint8_t rawTex; + if(isRSU) + rawTex = P1.rsuTexture; + else + { + rawTex = P2.usdTexture; + if(P2.VertexY % 2 == 0) + { + int adjX = (P2.VertexX + 1 >= myMap.width) ? 0 : P2.VertexX + 1; + rawTex = myMap.getVertex(adjX, P2.VertexY).usdTexture; + } + } + auto const texture = TriangleTerrainType(rawTex & ~0x40); // Mask out harbor bit GetTerrainTextureCoords(type, texture, isRSU, texture_move, upper, left, right, upper2, left2, right2); // draw the triangle @@ -887,6 +917,20 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa } // blit borders + // + // s25client TerrainRenderer::GenerateOpenGL checks six edge types per vertex + // using four terrain samples: + // t1 = terrain[pos][0] (RSU at pt) + // t2 = terrain[pos][1] (USD at pt) + // t3 = terrain[E(pt)][0] (RSU at x+1, y) + // t4 = terrain[SW(pt)][1] (USD at x-!(y&1), y+1) + // left_right[0/1] = GetEdgeType(t2, t1) / GetEdgeType(t1, t2) + // right_left[0/1] = GetEdgeType(t3, t2) / GetEdgeType(t2, t3) + // top_down[0/1] = GetEdgeType(t4, t1) / GetEdgeType(t1, t4) + // + // s25edit checks three edges per vertex (mirrors the original DrawTriangle + // second pass), with USD reads unshifted by +1 in even rows to compensate + // for the I/O shift (CFile.cpp). /// PRIORITY FROM HIGH TO LOW: SNOW, MINING_MEADOW, STEPPE, STEPPE_MEADOW2, MINING, MEADOW, FLOWER, STEPPE_MEADOW1, /// SWAMP, WATER, LAVA if(global::s2->getMapObj()->getRenderBorders()) @@ -894,8 +938,11 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa // RSU-Triangle if(isRSU) { - // left upper / right lower edge - therefore get the usd-texture from left to compare + // RSU left edge: compare USD from left vertex with RSU at this vertex. + // I/O shift: USD data moved right by 1 in even rows. Read from (x) instead of (x-1). Uint16 col = (P1.VertexX - 1 < 0 ? myMap.width - 1 : P1.VertexX - 1); + if(P1.VertexY % 2 == 0) // even row: unshift + col = (col + 1 >= myMap.width) ? 0 : col + 1; MapNode tempP = myMap.getVertex(col, P1.VertexY); SDL_Rect BorderRect; @@ -935,8 +982,11 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa else { SDL_Rect BorderRect; - // left lower / right upper - auto borderSide = CalcBorders(myMap, P2.rsuTexture, P2.usdTexture, BorderRect); + // USD left/right edge: compare RSU vs USD at same visual column. + // I/O shift: USD moved right by 1 in even rows. P2.usdTexture at (x-1) + // now holds file(x-2,y). Read USD from P3.usdTexture at (x) = file(x-1,y). + auto borderSide = + CalcBorders(myMap, P2.rsuTexture, (P2.VertexY % 2 == 0) ? P3.usdTexture : P2.usdTexture, BorderRect); if(borderSide != BorderPreference::None) { @@ -974,12 +1024,16 @@ void CSurface::DrawTriangle(SDL_Surface* display, const DisplayRectangle& displa DrawFadedTexturedTrigon(display, tmpP1, tmpP2, tipPt, Surf_Tileset, BorderRect, P1.i, P2.i); } - // top / bottom - therefore get the rsu-texture one line above to compare + // USD top/bottom edge: compare RSU from vertex above with USD at this vertex. + // s25client analogue: GetEdgeType(t4, t1) / GetEdgeType(t1, t4) + // where t4 = terrain[SW(pt)][1] = USD at SW(x, y). Uint16 row = (P2.VertexY - 1 < 0 ? myMap.height - 1 : P2.VertexY - 1); Uint16 col = (P2.VertexY % 2 == 0 ? P2.VertexX : (P2.VertexX + 1 > myMap.width - 1 ? 0 : P2.VertexX + 1)); MapNode tempP = myMap.getVertex(col, row); - borderSide = CalcBorders(myMap, tempP.rsuTexture, P2.usdTexture, BorderRect); + // I/O shift: P2.usdTexture at (x-1) = file(x-2,y). Read from P3.usdTexture at (x) = file(x-1,y). + borderSide = + CalcBorders(myMap, tempP.rsuTexture, (P2.VertexY % 2 == 0) ? P3.usdTexture : P2.usdTexture, BorderRect); if(borderSide != BorderPreference::None) { Point32 thirdPt; diff --git a/GEOMETRY2.md b/GEOMETRY2.md new file mode 100644 index 0000000..2f34a96 --- /dev/null +++ b/GEOMETRY2.md @@ -0,0 +1,71 @@ + + +# s25edit vs s25client coordinate alignment + +Both use the same pixel positions (`bobMAP::updateVertexCoords` / +`TerrainRenderer::GetVertexPos`) and identical RSU triangles. + +## 1. USD triangle — odd row vertex 0 differs + +**s25edit** USD at `(x, y)`, odd rows (`CSurface.cpp:DrawTriangleField` loop +body): + + (x+1, y+1), (x, y), (x+1, y) + +**s25client** USD at `(x, y)`, odd rows +(`TerrainRenderer::UpdateTrianglePos[1]`): + + (x, y+1), (x, y), (x+1, y) + +The only difference: vertex 0 is `(x+1, y+1)` (right-lower) in s25edit vs +`(x, y+1)` (left-lower) in s25client. + +## 2. Fix: shift USD textures during file I/O + +File read (`CIO/CFile.cpp:read_wld`) maps file rows to memory: + + memory(i, j).usdTexture = file((i + !(j&1)) % width, j).usdTexture + +File write (`CIO/CFile.cpp:save_wld`) maps back: + + file(i, j).usdTexture = memory((i + !(j&1)) % width, j).usdTexture + +After this shift, `vertex(x, y).usdTexture` in memory always contains the USD +texture for visual position `(x, y)` — matching `terrain[pos][1]` in +`s25client::TerrainRenderer::UpdateTriangleTerrain` which reads from the +same vertex `(x, y)`. + +## 3. Rendered triangle vertices now match + +**s25edit** (`DrawTriangleField` via `clientUsdTriangleVertices`) produces +the same USD vertex set as **s25client** (`UpdateTrianglePos[1]`): + + (x, y+1), (x, y), (x+1, y) // odd rows — was (x+1, y+1), (x, y), (x+1, y) + (x-1, y+1), (x-1, y), (x, y) // even rows — unchanged + +## 4. Border texture sources now match + +s25client reads four terrain samples per vertex +(`TerrainRenderer::GenerateOpenGL`): + + t1 = terrain[pos][0] // RSU at (x, y) + t2 = terrain[pos][1] // USD at (x, y) + t3 = terrain[E(pos)][0] // RSU at (x+1, y) + t4 = terrain[SW(pos)][1] // USD at SW(x, y) + +With the I/O shift, `vertex(x, y).usdTexture` is now `t2`, and +`vertex(x, y).rsuTexture` is `t1` — same indexing as s25client. + +Note: s25client still checks 6 border edges (three pairs, both directions) +while s25edit checks 3 (one direction per edge, determined by +`edgePriority`). The textures being compared are now the same, but the set +of emitted border triangles differs in which direction check fires. + +## 5. Migrated call sites + +All `.usdTexture` writes pass through `clientUsdVertexPos()` (identity +marker — see `include/Geometry.h`). Reads need no helper because memory is +already in client convention. diff --git a/include/Geometry.h b/include/Geometry.h new file mode 100644 index 0000000..97e1d9b --- /dev/null +++ b/include/Geometry.h @@ -0,0 +1,23 @@ +// Copyright (C) 2025 Settlers Freaks +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "defines.h" + +/// Identity marker for s25client coordinate convention. +/// +/// s25client TerrainRenderer::UpdateTriangleTerrain:\n +/// terrain[nodeIdx][0] = RSU, terrain[nodeIdx][1] = USD\n +/// Both read from the same vertex (x, y).\n +///\n +/// After CFile.cpp's I/O shift, vertex(x, y).usdTexture = USD at visual (x, y),\n +/// matching terrain[nodeIdx][1]. +inline Position clientUsdVertexPos(Position visualPos) +{ + return visualPos; +} +inline Position clientUsdVertexPos(int x, int y) +{ + return {x, y}; +}