Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / unbuild_elevation / unbuild_elevation.cpp
blob656109cae987321cb97c948e66a773afa503c30f
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2021 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "../zone_lib/zone_utility.h"
19 #include <iostream>
20 #include <nel/misc/types_nl.h>
21 #include <nel/misc/file.h>
22 #include <nel/misc/i_xml.h>
23 #include <nel/misc/common.h>
24 #include <nel/misc/cmd_args.h>
25 #include <nel/misc/bitmap.h>
26 //#include <nel/3d/quad_tree.h>
27 #include <nel/3d/zone.h>
28 //#include <nel/3d/landscape.h>
29 //#include <nel/3d/zone_smoother.h>
30 //#include <nel/3d/zone_tgt_smoother.h>
31 //#include <nel/3d/zone_corner_smoother.h>
32 #include <nel/ligo/zone_region.h>
33 #include <vector>
34 #include <set>
36 using namespace NL3D;
37 using namespace NLMISC;
38 using namespace NLLIGO;
39 using namespace std;
41 namespace /* anonymous */
44 sint32 s_ZoneMinX, s_ZoneMinY, s_ZoneMaxX, s_ZoneMaxY;
45 float s_CellSize = 160.0f;
46 bool s_ExtendCoords;
48 std::string s_SourceDir; /* R:\reference\2008_july\data\r2_desert */
49 std::string s_ReferenceDir; /* R:\pipeline\export\continents\r2_desert\zone_weld */
51 std::string s_OutputPy;
53 std::string s_SourceExt = "zonel";
54 std::string s_ReferenceExt = "zonenhw";
56 CZoneRegion s_Land; /* "R:\graphics\landscape\ligo\desert\r2_desert.land" */
58 int s_Warnings;
60 // unbuild_elevation --land "R:\graphics\landscape\ligo\desert\r2_desert.land" "Y:\temp\r2_desert_elevation.Py" "R:\reference\2008_july\data\r2_desert" "R:\pipeline\export\continents\r2_desert\zone_weld"
61 // --land "R:\graphics\landscape\ligo\jungle\zorai.land" --referenceext zonenhw "X:\wsl\big_zorai.py" "R:\reference\2008_july\data\zorai_zones" "R:\pipeline\export\continents\zorai\zone_weld"
63 // --land "R:\graphics\landscape\ligo\desert\r2_desert.land" "X:\wsl\big_r2_desert.py" "R:\reference\2008_july\data\r2_desert" "R:\pipeline\export\continents\r2_desert\zone_weld" --extendcoords
64 // --land "R:\graphics\landscape\ligo\jungle\r2_jungle.land" "X:\wsl\big_r2_jungle.py" "R:\reference\2008_july\data\r2_jungle" "R:\pipeline\export\continents\r2_jungle\zone_weld" --extendcoords
65 // --land "R:\graphics\landscape\ligo\jungle\r2_forest.land" "X:\wsl\big_r2_forest.py" "R:\reference\2008_july\data\r2_forest" "R:\pipeline\export\continents\r2_forest\zone_weld" --extendcoords
66 // --land "R:\graphics\landscape\ligo\lacustre\r2_lakes.land" "X:\wsl\big_r2_lakes.py" "R:\reference\2008_july\data\r2_lakes" "R:\pipeline\export\continents\r2_lakes\zone_weld" --extendcoords
67 // --land "R:\graphics\landscape\ligo\primes_racines\r2_roots.land" "X:\wsl\big_r2_roots.py" "R:\reference\2008_july\data\r2_roots" "R:\pipeline\export\continents\r2_roots\zone_weld" --extendcoords
69 // --land "R:\graphics\landscape\ligo\desert\r2_desert.land" --referenceext zonew "X:\wsl\check_r2_desert.py" "R:\reference\2008_july\data\r2_desert" "R:\pipeline\export\continents\r2_desert\zone_weld" --extendcoords
70 // --land "R:\graphics\landscape\ligo\jungle\r2_jungle.land" --referenceext zonew "X:\wsl\check_r2_jungle.py" "R:\reference\2008_july\data\r2_jungle" "R:\pipeline\export\continents\r2_jungle\zone_weld" --extendcoords
71 // --land "R:\graphics\landscape\ligo\primes_racines\r2_roots.land" --referenceext zonew "X:\wsl\check_r2_roots.py" "R:\reference\2008_july\data\r2_roots" "R:\pipeline\export\continents\r2_roots\zone_weld" --extendcoords
73 bool loadLand(const string &filename)
75 try
77 CIFile fileIn;
78 if (fileIn.open (filename))
80 CIXml xml(true);
81 nlverify(xml.init(fileIn));
82 s_Land.serial(xml);
84 else
86 nlwarning("Can't open the land file: %s", filename.c_str());
87 return false;
90 catch (const Exception& e)
92 nlwarning("Error in land file: %s", e.what());
93 return true;
95 return true;
98 bool getXYFromZoneName(sint32 &x, sint32 &y, const string &zoneName)
100 string xStr, yStr;
101 uint32 i = 0;
102 while (zoneName[i] != '_')
104 yStr += zoneName[i];
105 ++i;
106 if (i == zoneName.size())
107 goto Fail;
109 if (!NLMISC::fromString(yStr, y))
110 goto Fail;
111 y = -y;
112 ++i;
113 while (i < zoneName.size())
115 xStr += zoneName[i];
116 ++i;
118 if (xStr.size() != 2)
119 goto Fail;
120 xStr = NLMISC::toUpperAscii(xStr);
121 x = ((xStr[0] - 'A') * 26 + (xStr[1] - 'A'));
122 return true;
123 Fail:
124 x = -1;
125 y = -1;
126 return false;
129 void getBitmapSize(int &w, int &h)
131 sint32 sizeX = s_ZoneMaxX - s_ZoneMinX + 1;
132 sint32 sizeY = s_ZoneMaxY - s_ZoneMinY + 1;
133 w = sizeX * 20;
134 h = sizeY * 20;
136 if (!s_ExtendCoords)
138 ++w;
139 ++h;
143 void getBitmapCoord(float &xc, float &yc, float x, float y)
145 float deltaZ = 0.0f, deltaZ2 = 0.0f;
146 CRGBAF color;
147 sint32 sizeX = s_ZoneMaxX - s_ZoneMinX + 1;
148 sint32 sizeY = s_ZoneMaxY - s_ZoneMinY + 1;
150 xc = (x - s_CellSize * s_ZoneMinX) / (s_CellSize * sizeX);
151 yc = 1.0f - ((y - s_CellSize * s_ZoneMinY) / (s_CellSize * sizeY));
153 if (s_ExtendCoords)
155 int w, h;
156 getBitmapSize(w, h);
157 xc -= .5f / (float)w;
158 yc -= .5f / (float)h;
159 xc = xc * (float)(w + 1) / (float)w;
160 yc = yc * (float)(h + 1) / (float)h;
164 bool processZone(std::vector<NLMISC::CVector> &output, const std::string &sourceFile, const std::string &referenceFile)
166 std::string zone = CFile::getFilenameWithoutExtension(referenceFile);
168 std::vector<CVector> sourceVertices;
169 std::vector<CVector> referenceVertices;
171 CZoneInfo zoneInfo;
173 CZone zone;
175 CIFile f(sourceFile);
176 zone.serial(f);
177 f.close();
179 zone.retrieve(zoneInfo);
181 for (ptrdiff_t i = 0; i < (ptrdiff_t)zoneInfo.Patchs.size(); ++i)
183 sourceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[0]);
184 sourceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[1]);
185 sourceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[2]);
186 sourceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[3]);
190 CZoneInfo zoneInfo;
192 CZone zone;
194 CIFile f(referenceFile);
195 zone.serial(f);
196 f.close();
198 zone.retrieve(zoneInfo);
200 for (ptrdiff_t i = 0; i < (ptrdiff_t)zoneInfo.Patchs.size(); ++i)
202 referenceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[0]);
203 referenceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[1]);
204 referenceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[2]);
205 referenceVertices.push_back(zoneInfo.Patchs[i].Patch.Vertices[3]);
208 printf("Source vertices: %i, reference vertices: %i\n", (int)sourceVertices.size(), (int)referenceVertices.size());
209 if (sourceVertices.size() != referenceVertices.size())
211 nlwarning("Mismatching vertex count in zone %s, source vertices: %i, reference vertices: %i", zone.c_str(), (int)sourceVertices.size(), (int)referenceVertices.size());
212 ++s_Warnings;
215 std::vector<bool> processedSourceIndices;
216 std::vector<bool> processedReferenceIndices;
217 processedSourceIndices.resize(sourceVertices.size());
218 processedReferenceIndices.resize(referenceVertices.size());
220 int referenceProcessedCount = 0;
221 int sourceProcessedCount = 0;
223 for (ptrdiff_t i = 0; i < (ptrdiff_t)referenceVertices.size(); ++i)
225 if (processedReferenceIndices[i])
226 continue;
228 float referenceHeight = referenceVertices[i].z;
229 int referenceHeightDiv = 1;
230 ++referenceProcessedCount;
232 for (ptrdiff_t j = i + 1; j < (ptrdiff_t)referenceVertices.size(); ++j)
234 if (processedReferenceIndices[j])
235 continue;
237 if (abs(referenceVertices[i].x - referenceVertices[j].x) < 0.1f
238 && abs(referenceVertices[i].y - referenceVertices[j].y) < 0.1f)
240 processedReferenceIndices[j] = true;
241 referenceHeight += referenceVertices[j].z;
242 ++referenceHeightDiv;
243 ++referenceProcessedCount;
247 float sourceHeight = 0.f;
248 int sourceHeightDiv = 0;
250 for (ptrdiff_t j = 0; j < (ptrdiff_t)sourceVertices.size(); ++j)
252 if (processedSourceIndices[j])
253 continue;
255 if (abs(referenceVertices[i].x - sourceVertices[j].x) < 0.1f
256 && abs(referenceVertices[i].y - sourceVertices[j].y) < 0.1f)
258 processedSourceIndices[j] = true;
259 sourceHeight += sourceVertices[j].z;
260 ++sourceHeightDiv;
261 ++sourceProcessedCount;
265 if (!sourceHeightDiv)
267 nlwarning("No matching vertices in source for zone %s, x: %f, y: %f", zone.c_str(), referenceVertices[i].x, referenceVertices[i].y);
268 ++s_Warnings;
269 continue;
272 if (referenceHeightDiv != sourceHeightDiv)
274 nlwarning("Mismatching vertex count for zone %s, x: %f, y: %f (reference: %i, source: %i)", zone.c_str(), referenceVertices[i].x, referenceVertices[i].y, referenceHeightDiv, sourceHeightDiv);
275 ++s_Warnings;
276 continue;
279 referenceHeight /= (float)referenceHeightDiv;
280 sourceHeight /= (float)sourceHeightDiv;
282 output.push_back(NLMISC::CVector(referenceVertices[i].x, referenceVertices[i].y, sourceHeight - referenceHeight));
285 return true;
288 bool unbuildElevation()
290 std::vector<std::string> referenceZones;
291 CPath::getPathContent(s_ReferenceDir, true, false, true, referenceZones);
292 int totalZones = 0;
294 std::vector<NLMISC::CVector> output;
296 for (std::vector<std::string>::iterator it(referenceZones.begin()), end(referenceZones.end()); it != end; ++it)
298 if (CFile::getExtension(*it) != s_ReferenceExt)
299 continue;
301 std::string zone = CFile::getFilenameWithoutExtension(*it);
302 std::string sourceZone = s_SourceDir + "/" + CFile::getFilenameWithoutExtension(*it) + "." + s_SourceExt;
304 if (!CFile::fileExists(sourceZone))
305 continue;
307 if (zone == "137_JK") // Bad zone
308 continue;
310 printf("%s\n", nlUtf8ToMbcs(zone));
311 ++totalZones;
313 if (!processZone(output, sourceZone, *it))
314 return false;
316 printf("\n");
319 printf("Total zones: %i\n", totalZones);
321 #if 1
323 std::vector<bool> processedOutput;
324 processedOutput.resize(output.size());
325 std::vector<NLMISC::CVector> reducedOutput;
326 for (ptrdiff_t i = 0; i < (ptrdiff_t)output.size(); ++i)
328 if (processedOutput[i])
329 continue;
331 CVector v = output[i];
332 int div = 1;
334 for (ptrdiff_t j = i + 1; j < (ptrdiff_t)output.size(); ++j)
336 if (processedOutput[j])
337 continue;
339 if (abs(output[i].x - output[j].x) < 0.1f
340 && abs(output[i].y - output[j].y) < 0.1f)
342 processedOutput[j] = true;
343 v.z += output[j].z;
344 ++div;
348 v.z /= (float)div;
349 reducedOutput.push_back(v);
352 printf("Reduced vertex count from %i to %i\n", (int)output.size(), (int)reducedOutput.size());
354 #else
356 std::vector<NLMISC::CVector> reducedOutput = output;
358 #endif
361 int w, h;
362 getBitmapSize(w, h);
364 FILE *fo = fopen(nlUtf8ToMbcs(s_OutputPy), "w");
365 if (!fo)
366 return false;
368 fprintf(fo, "import naturalneighbor # https://github.com/innolitics/natural-neighbor-interpolation - pip3 install naturalneighbor\n");
369 fprintf(fo, "import numpy as np\n");
370 fprintf(fo, "import png # pip3 install pypng\n");
371 fprintf(fo, "grid_ranges = [[0, 1, %i%s], [0, 1, %i%s], [-1, 1, 1j]]\n", w, "j", h, "j");
373 fprintf(fo, "points = np.array([\n");
375 for (ptrdiff_t i = 0; i < (ptrdiff_t)reducedOutput.size(); ++i)
377 float x, y;
378 getBitmapCoord(x, y, reducedOutput[i].x, reducedOutput[i].y);
379 fprintf(fo, "\t[ %f, %f, 0 ], # %f, %f\n", x, y, reducedOutput[i].x, reducedOutput[i].y);
382 fprintf(fo, "])\n");
383 fprintf(fo, "\n");
384 fprintf(fo, "values = np.array([\n");
386 for (ptrdiff_t i = 0; i < (ptrdiff_t)reducedOutput.size(); ++i)
388 fprintf(fo, "\t%f,\n", reducedOutput[i].z);
391 fprintf(fo, "])\n");
393 fprintf(fo, "nn_interpolated_values = naturalneighbor.griddata(points, values, grid_ranges)\n");
394 fprintf(fo, "img = []\n");
395 fprintf(fo, "for y in range(0, %i):\n", h);
396 fprintf(fo, "\tline = []\n");
397 fprintf(fo, "\tfor x in range(0, %i):\n", w);
398 fprintf(fo, "\t\tline.append(np.round(nn_interpolated_values[x][y][0]).astype(int) + 127)\n");
399 fprintf(fo, "\timg.append(line)\n");
400 fprintf(fo, "with open('%s.png', 'wb') as f:\n", CFile::getFilenameWithoutExtension(s_OutputPy).c_str());
401 fprintf(fo, "\tw = png.Writer(%i, %i, greyscale=True)\n", w, h);
402 fprintf(fo, "\tw.write(f, img)\n");
403 fflush(fo);
404 fclose(fo);
407 printf("Warnings: %i\n", s_Warnings);
408 return true;
411 bool unbuildElevation(NLMISC::CCmdArgs &args)
413 s_OutputPy = args.getAdditionalArg("output")[0];
414 s_SourceDir = args.getAdditionalArg("source")[0];
415 s_ReferenceDir = args.getAdditionalArg("reference")[0];
417 if (args.haveLongArg("zonemin") && args.haveLongArg("zonemax"))
419 sint32 zoneMinX, zoneMinY;
420 sint32 zoneMaxX, zoneMaxY;
421 if (!getXYFromZoneName(zoneMinX, zoneMinY, args.getLongArg("zonemin")[0])
422 || !getXYFromZoneName(zoneMaxX, zoneMaxY, args.getLongArg("zonemax")[0]))
424 return false;
426 s_ZoneMinX = min(zoneMinX, zoneMaxX);
427 s_ZoneMaxX = max(zoneMinX, zoneMaxX);
428 s_ZoneMinY = min(zoneMinY, zoneMaxY);
429 s_ZoneMaxY = max(zoneMinY, zoneMaxY);
431 else if (args.haveLongArg("land"))
433 if (!loadLand(args.getLongArg("land")[0]))
434 return false;
435 s_ZoneMinX = s_Land.getMinX();
436 s_ZoneMaxX = s_Land.getMaxX();
437 s_ZoneMinY = s_Land.getMinY();
438 s_ZoneMaxY = s_Land.getMaxY();
440 else
442 nlwarning("Must have either both 'zonemin' and 'zonemax', or 'land' specified");
443 return false;
446 if (args.haveLongArg("cellsize"))
448 if (!NLMISC::fromString(args.getLongArg("cellsize")[0], s_CellSize))
449 return false;
452 s_ExtendCoords = args.haveLongArg("extendcoords");
454 if (args.haveLongArg("sourceext"))
456 s_SourceExt = args.getLongArg("sourceext")[0];
459 if (args.haveLongArg("referenceext"))
461 s_ReferenceExt = args.getLongArg("referenceext")[0];
464 return unbuildElevation();
467 } /* anonymous namespace */
469 int main(int argc, char **argv)
471 NLMISC::CApplicationContext myApplicationContext;
473 NLMISC::CCmdArgs args;
475 args.addAdditionalArg("output", "Output Python file path");
476 args.addAdditionalArg("source", "Input folder with zones at the right height");
477 args.addAdditionalArg("reference", "Input folder with zones at the wrong height");
479 args.addArg("", "sourceext", "extension", "Source zone extension (default: zonel)");
480 args.addArg("", "referenceext", "extension", "Reference zone extension (default: zonew)");
482 args.addArg("", "land", "land", "Ligo land file (either specify this or the boundaries)");
483 args.addArg("", "zonemin", "zone", "Zone boundary");
484 args.addArg("", "zonemax", "zone", "Zone boundary");
485 args.addArg("", "cellsize", "meters", "Zone cell size (default: 160)");
486 args.addArg("", "extendcoords", "flag", "Extend coordinates to edge of bitmap pixels");
488 if (!args.parse(argc, argv))
490 return EXIT_FAILURE;
493 if (!unbuildElevation(args))
495 args.displayHelp();
496 return EXIT_FAILURE;
499 return EXIT_SUCCESS;
502 /* end of file */