2 * Copyright (C) 2012 by Jan Boon (Kaetemi)
4 * This file is part of RYZOM CORE PIPELINE.
5 * RYZOM CORE PIPELINE is free software: you can redistribute it
6 * and/or modify it under the terms of the GNU Affero General Public
7 * License as published by the Free Software Foundation, either
8 * version 3 of the License, or (at your option) any later version.
10 * RYZOM CORE PIPELINE is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public
16 * License along with RYZOM CORE PIPELINE. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include <nel/misc/types_nl.h>
21 #include <nel/misc/common.h>
23 #include <gsf/gsf-outfile-msole.h>
24 #include <gsf/gsf-outfile.h>
25 #include <gsf/gsf-output-stdio.h>
26 #include <gsf/gsf-infile-msole.h>
27 #include <gsf/gsf-infile.h>
28 #include <gsf/gsf-input-stdio.h>
29 #include <gsf/gsf-utils.h>
30 #include <gsf/gsf-doc-meta-data.h>
31 #include <gsf/gsf-msole-utils.h>
32 #include <glib/gi18n.h>
41 #include <nel/misc/file.h>
42 #include <nel/misc/vector.h>
43 #include "nel/misc/dynloadlib.h"
44 #include "nel/misc/debug.h"
45 #include "nel/misc/path.h"
46 #include "nel/misc/algo.h"
47 #include "nel/misc/file.h"
48 #include "nel/misc/mem_stream.h"
50 #include "../pipeline_max/storage_stream.h"
51 #include "../pipeline_max/storage_object.h"
52 #include "../pipeline_max/dll_directory.h"
53 #include "../pipeline_max/class_directory_3.h"
54 #include "../pipeline_max/class_data.h"
55 #include "../pipeline_max/config.h"
56 #include "../pipeline_max/scene.h"
57 #include "../pipeline_max/scene_class_registry.h"
60 #include "../pipeline_max/builtin/builtin.h"
61 #include "../pipeline_max/update1/update1.h"
62 #include "../pipeline_max/epoly/epoly.h"
64 #include "../pipeline_max/builtin/storage/app_data.h"
65 #include "../pipeline_max/builtin/storage/geom_buffers.h"
66 #include "../pipeline_max/builtin/scene_impl.h"
67 #include "../pipeline_max/builtin/i_node.h"
68 #include "../pipeline_max/update1/editable_mesh.h"
69 #include "../pipeline_max/epoly/editable_poly.h"
71 #include <boost/algorithm/string.hpp>
73 using namespace boost::algorithm
;
75 using namespace PIPELINE::MAX
;
76 using namespace PIPELINE::MAX::BUILTIN
;
77 using namespace PIPELINE::MAX::BUILTIN::STORAGE
;
78 using namespace PIPELINE::MAX::UPDATE1
;
79 using namespace PIPELINE::MAX::EPOLY
;
81 CSceneClassRegistry SceneClassRegistry
;
84 bool DebugParser
= false;
86 bool DisplayStream
= false;
87 bool DisplayReplaces
= false;
89 bool ReplacePaths
= true;
90 bool ReplaceMapExt
= false;
92 bool WritePathChangesOnly
= true;
93 bool WriteModified
= true;
94 bool WriteDummy
= false;
96 bool HaltOnIssue
= false;
98 const char *DatabaseDirectory
= "w:\\database\\";
99 const char *LinuxDatabaseDirectory
= "/mnt/y/ryzom-assets/database/";
100 bool RunningLinux
= true;
102 //const char *SrcDirectoryRecursive = "w:\\database\\interfaces\\";
103 //const char *SrcDirectoryRecursive = "w:\\database\\";
104 //const char *SrcDirectoryRecursive = "w:\\database\\stuff\\fyros\\city\\newpositionville\\";
105 const char *SrcDirectoryRecursiveInit
= "w:\\database\\";
106 //const char *SrcDirectoryRecursiveHandle = "w:\\database\\stuff\\generique\\agents\\accessories\\";
107 //const char *SrcDirectoryRecursiveHandle = "w:\\database\\landscape\\ligo\\primes_racines\\max\\";
108 const char *SrcDirectoryRecursiveHandle
= "w:\\database\\stuff\\fyros\\decors\\constructions\\";
110 bool UseFallbackTga
= false;
111 const char *FallbackTga
= "w:\\database\\stuff\\lod_actors\\texture_lod\\trame.png";
113 std::set
<std::string
> MissingFiles
;
114 std::map
<std::string
, std::string
> KnownFileCache
;
116 std::string
nativeDatabasePath(const std::string
&standardizedPath
)
120 std::string result
= standardizedPath
;
121 NLMISC::strFindReplace(result
, DatabaseDirectory
, LinuxDatabaseDirectory
);
122 while (NLMISC::strFindReplace(result
, "\\", "/")) { }
125 return standardizedPath
;
128 std::string
unnativeDatabasePath(const std::string
&nativizedPath
)
132 std::string result
= nativizedPath
;
133 NLMISC::strFindReplace(result
, LinuxDatabaseDirectory
, DatabaseDirectory
);
134 while (NLMISC::strFindReplace(result
, "/", "\\")) { }
137 return nativizedPath
;
140 // COPY FROM PIPELINE_SERVICE.CPP WITH BACKSLASHES INSTEAD OF FORWARD SLASHES
141 std::string
standardizePath(const std::string
&path
, bool addFinalSlash
)
148 newPath
.resize(path
.size() + 1);
150 std::string::size_type j
= 0;
151 for (std::string::size_type i
= 0; i
< path
.size(); ++i
)
153 if (path
[i
] == '\\' || path
[i
] == '/')
155 if (j
<= 1 && path
[i
] == '\\')
157 // for windows network
161 else if (j
== 0 || newPath
[j
- 1] != '\\')
169 newPath
[j
] = path
[i
];
176 // add terminal slash
177 if (addFinalSlash
&& newPath
[newPath
.size()-1] != '\\')
183 inline bool isCharacter(char c0
)
185 uint8 c
= *(uint8
*)(void *)(&c0
);
186 return (32 <= c
/*&& c <= 127) || (161 <= c*/ /*&& c <= 255*/);
189 inline char stripFrenchLocale(char c0
)
191 uint8 c
= *(uint8
*)(void *)(&c0
);
192 if (192 <= c
&& c
<= 197) return 'a';
193 if (200 <= c
&& c
<= 203) return 'e';
194 if (204 <= c
&& c
<= 207) return 'i';
195 if (210 <= c
&& c
<= 214) return 'o';
196 if (217 <= c
&& c
<= 220) return 'u';
197 if (c
== 221) return 'y';
198 if (224 <= c
&& c
<= 229) return 'a';
199 if (232 <= c
&& c
<= 235) return 'e';
200 if (236 <= c
&& c
<= 239) return 'i';
201 if (242 <= c
&& c
<= 246) return 'o';
202 if (249 <= c
&& c
<= 252) return 'u';
203 if (c
== 253 || c
== 255) return 'y';
207 std::string
rewritePath(const std::string
&path
, const std::string
&databaseDirectory
)
209 // nldebug("Rewrite: %s", path.c_str());
211 static std::set
<std::string
> fileNameCache
;
213 std::string stdPath
= standardizePath(path
, false);
214 for (std::string::size_type i
= 0; i
< stdPath
.size(); ++i
)
215 stdPath
[i
] = stripFrenchLocale(stdPath
[i
]);
216 stdPath
= NLMISC::toLower(stdPath
);
218 // TODO: remove ./stuff/caravan/agents/_textures/actors/trame.png
220 NLMISC::strFindReplace(stdPath
, "w:\\database\\", databaseDirectory
);
221 NLMISC::strFindReplace(stdPath
, "\\\\amiga\\3d\\database\\", databaseDirectory
);
222 NLMISC::strFindReplace(stdPath
, "ma_hom_armor_01", "ma_hom_armor01");
223 NLMISC::strFindReplace(stdPath
, "ma_hof_armor_01", "ma_hof_armor01");
224 NLMISC::strFindReplace(stdPath
, "ma_hom_armor_00", "ma_hom_armor00");
225 NLMISC::strFindReplace(stdPath
, "ma_hof_armor_00", "ma_hof_armor00");
226 NLMISC::strFindReplace(stdPath
, "zo_hom_armor_00", "zo_hom_armor00");
227 NLMISC::strFindReplace(stdPath
, "zo_hof_armor_00", "zo_hof_armor00");
228 NLMISC::strFindReplace(stdPath
, "fy_hof_cheveux_shave01", "fy_hof_cheveux_shave");
230 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hom_underwear_avtbras", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_avtbras");
231 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hom_underwear_epaule", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_epaule");
232 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hom_underwear_hand-downside", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_hand-downside");
233 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hom_underwear_hand-upside", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_hand-upside");
234 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hom_underwear_molet", "tryker\\agents\\_textures\\actors\\tr_hom_underwear_molet");
235 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hof_underwear_hand-downside", "tryker\\agents\\_textures\\actors\\tr_hof_underwear_hand-downside");
236 NLMISC::strFindReplace(stdPath
, "matis\\agents\\_textures\\actors\\ma_hof_underwear_hand-upside", "tryker\\agents\\_textures\\actors\\tr_hof_underwear_hand-upside");
238 NLMISC::strFindReplace(stdPath
, "tr_hof_underwear_torso", "tr_hof_underwear_torse");
239 NLMISC::strFindReplace(stdPath
, "tr_hof_underwear_hand-", "tr_hof_underwear_hand_");
241 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_avbras.", "fy_hom_armor00_avbras_c1.");
242 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_bottes.", "fy_hom_armor00_bottes_c1.");
243 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_bras.", "fy_hom_armor00_bras_c1.");
244 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_cuissear.", "fy_hom_armor00_cuissear_c1.");
245 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_cuisseav.", "fy_hom_armor00_cuisseav_c1.");
246 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_dos.", "fy_hom_armor00_dos_c1.");
247 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_hand-downside.", "fy_hom_armor00_hand-downside_c1.");
248 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_hand-upside.", "fy_hom_armor00_hand-upside_c1.");
249 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_pieds.", "fy_hom_armor00_pieds_c1.");
250 NLMISC::strFindReplace(stdPath
, "fy_hom_armor00_torse.", "fy_hom_armor00_torse_c1.");
252 NLMISC::strFindReplace(stdPath
, "fy-hof-gilet02-dos", "fy_hof_gilet02_arriere_n");
253 NLMISC::strFindReplace(stdPath
, "fy-hof-pantalon02-arriere", "fy_hof_pantalon02_arriere_n");
254 NLMISC::strFindReplace(stdPath
, "fy-hof-pantalon02-avant", "fy_hof_pantalon02_avant_n");
255 NLMISC::strFindReplace(stdPath
, "fy-hom-blouson02-avantbras", "fy_hom_blouson02_avbras_n");
256 NLMISC::strFindReplace(stdPath
, "fy-hom-blouson02-bras", "fy_hom_blouson02_bras_n");
257 NLMISC::strFindReplace(stdPath
, "fy-hom-blouson02-dos", "fy_hom_blouson02_arriere_n");
258 NLMISC::strFindReplace(stdPath
, "fy-hom-blouson02-torse", "fy_hom_blouson02_avant_n");
259 NLMISC::strFindReplace(stdPath
, "fy-hom-pantalon02-mollet", "fy_hom_pantalon02_mollet_n");
260 NLMISC::strFindReplace(stdPath
, "fy-hom-shoes02", "fy_hom_shoes02_shoes_n");
261 NLMISC::strFindReplace(stdPath
, "fyhof-gilet02-torse", "fy_hof_gilet02_torse_n");
263 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_armpad", "ge_hom_armor02_avbras");
264 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_bottes", "ge_hom_armor02_pied");
265 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_cuisse-arr", "ge_hom_armor02_cuisse_arr");
266 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_cuisse-avt", "ge_hom_armor02_cuisse_avt");
267 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_hand-down", "ge_hom_armor02_hand_down");
268 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_hand-up", "ge_hom_armor02_hand_up");
269 NLMISC::strFindReplace(stdPath
, "ge_hom_armor02_torse", "ge_hom_armor02_torso");
271 NLMISC::strFindReplace(stdPath
, "fy_lovejail.", "fy_lovejail_su.");
272 NLMISC::strFindReplace(stdPath
, "\\caissebonusaction.", "\\g_caissebonus.");
273 NLMISC::strFindReplace(stdPath
, "\\sactoile.", "\\g_sactoile.");
274 NLMISC::strFindReplace(stdPath
, "\\ge_mission_stele_kami0.", "\\ge_mission_stele_kami.");
275 NLMISC::strFindReplace(stdPath
, "\\ge_mission_reward_karavan_bigshield.", "\\ge_mission_reward_karavan_bigshield_c1.");
277 NLMISC::strFindReplace(stdPath
, "\\tr_hom_underwear_cuisse_arr.", "\\tr_hom_underwear_cuisse-arr.");
278 NLMISC::strFindReplace(stdPath
, "\\tr_hom_underwear_cuisse_avt.", "\\tr_hom_underwear_cuisse-avt.");
280 NLMISC::strFindReplace(stdPath
, "interfaces_visage", "visage_interface");
282 if (stdPath
.find("\\trame.") != std::string::npos
)
283 stdPath
= standardizePath(databaseDirectory
+ "/stuff/lod_actors/texture_lod/trame.png", false);
284 if (stdPath
.find("\\tr_hof_visage_c1.") != std::string::npos
)
285 stdPath
= standardizePath(databaseDirectory
+ "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c1.png", false);
286 if (stdPath
.find("\\tr_hof_visage_c2.") != std::string::npos
)
287 stdPath
= standardizePath(databaseDirectory
+ "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c2.png", false);
288 if (stdPath
.find("\\tr_hof_visage_c3.") != std::string::npos
)
289 stdPath
= standardizePath(databaseDirectory
+ "/stuff/tryker/agents/_textures/actors/tr_hof_visage_c3.png", false);
290 if (stdPath
.find("\\ma_hof_cheveux_medium02.") != std::string::npos
)
291 stdPath
= standardizePath(databaseDirectory
+ "/stuff/matis/agents/_textures/actors/ma_hof_cheveux_medium02.png", false);
293 /*if (stdPath.size() > path.size())
295 nlwarning("Path size becomes too large: '%s' -> '%s'", path.c_str(), stdPath.c_str());
299 if (NLMISC::CFile::getFilename(stdPath
) == stdPath
)
303 if (fileNameCache
.find(stdPath
) == fileNameCache
.end() || KnownFileCache
.find(stdPath
) == KnownFileCache
.end())
305 if (stdPath
[stdPath
.size() - 3] == 't' && stdPath
[stdPath
.size() - 2] == 'g' && stdPath
[stdPath
.size() - 1] == 'a')
307 stdPath
[stdPath
.size() - 3] = 'p';
308 stdPath
[stdPath
.size() - 2] = 'n';
309 stdPath
[stdPath
.size() - 1] = 'g';
310 if (fileNameCache
.find(stdPath
) != fileNameCache
.end())
313 //#nlwarning("File name not known: '%s' ('%s')", path.c_str(), stdPath.c_str());
314 // MissingFiles.insert(path);
322 if (stdPath
.find(databaseDirectory
) == std::string::npos
)
324 if (stdPath
[1] == ':' || (stdPath
[0] == '\\' && stdPath
[1] == '\\'))
326 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
327 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
329 if (stdPath
[stdPath
.size() - 3] == 't' && stdPath
[stdPath
.size() - 2] == 'g' && stdPath
[stdPath
.size() - 1] == 'a')
330 { stdPath
[stdPath
.size() - 3] = 'p'; stdPath
[stdPath
.size() - 2] = 'n'; stdPath
[stdPath
.size() - 1] = 'g'; }
331 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
332 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
334 if (stdPath
[stdPath
.size() - 3] == 'p' && stdPath
[stdPath
.size() - 2] == 'n' && stdPath
[stdPath
.size() - 1] == 'g')
335 { stdPath
[stdPath
.size() - 3] = 't'; stdPath
[stdPath
.size() - 2] = 'g'; stdPath
[stdPath
.size() - 1] = 'a'; }
336 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
337 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
339 //#nlwarning("Path not in database: '%s' ('%s')", path.c_str(), stdPath.c_str());
340 MissingFiles
.insert(path
);
345 // invalid path, don't care too much
352 if (!NLMISC::CFile::fileExists(nativeDatabasePath(stdPath
)))
354 if (stdPath
[stdPath
.size() - 3] == 't' && stdPath
[stdPath
.size() - 2] == 'g' && stdPath
[stdPath
.size() - 1] == 'a')
356 stdPath
[stdPath
.size() - 3] = 'p';
357 stdPath
[stdPath
.size() - 2] = 'n';
358 stdPath
[stdPath
.size() - 1] = 'g';
359 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPath
)))
363 std::string stdPathVv2
= standardizePath(NLMISC::CFile::getPath(stdPath
) + "/vv2/" + NLMISC::CFile::getFilename(stdPath
), false);
364 bool vv2works
= false;
365 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPathVv2
)))
371 if (stdPathVv2
[stdPathVv2
.size() - 3] == 'p' && stdPathVv2
[stdPathVv2
.size() - 2] == 'n' && stdPathVv2
[stdPathVv2
.size() - 1] == 'g')
373 stdPathVv2
[stdPathVv2
.size() - 3] = 't';
374 stdPathVv2
[stdPathVv2
.size() - 2] = 'g';
375 stdPathVv2
[stdPathVv2
.size() - 1] = 'a';
376 if (NLMISC::CFile::fileExists(nativeDatabasePath(stdPathVv2
)))
385 /*if (stdPathVv2.size() > path.size())
387 nlwarning("Path with vv2 size becomes too large: '%s' -> '%s'", path.c_str(), stdPathVv2.c_str());
392 stdPath
= stdPathVv2
;
398 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
399 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
401 if (stdPath
[stdPath
.size() - 3] == 't' && stdPath
[stdPath
.size() - 2] == 'g' && stdPath
[stdPath
.size() - 1] == 'a')
402 { stdPath
[stdPath
.size() - 3] = 'p'; stdPath
[stdPath
.size() - 2] = 'n'; stdPath
[stdPath
.size() - 1] = 'g'; }
403 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
404 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
406 if (stdPath
[stdPath
.size() - 3] == 'p' && stdPath
[stdPath
.size() - 2] == 'n' && stdPath
[stdPath
.size() - 1] == 'g')
407 { stdPath
[stdPath
.size() - 3] = 't'; stdPath
[stdPath
.size() - 2] = 'g'; stdPath
[stdPath
.size() - 1] = 'a'; }
408 if (KnownFileCache
.find(NLMISC::CFile::getFilename(stdPath
)) != KnownFileCache
.end())
409 return KnownFileCache
[NLMISC::CFile::getFilename(stdPath
)];
411 //#nlwarning("Path file does not exist: '%s' ('%s')", path.c_str(), stdPath.c_str());
412 MissingFiles
.insert(path
);
418 fileNameCache
.insert(NLMISC::CFile::getFilename(stdPath
));
422 void doFileInitialize(const std::string
&filePath
)
424 // nldebug("File: '%s'", filePath.c_str());
425 // nldebug("Native: '%s'", nativeDatabasePath(filePath).c_str());
427 KnownFileCache
[NLMISC::CFile::getFilename(filePath
)] = standardizePath(filePath
, false);
430 // maxRewritePaths R:/graphics/interfaces/anims_max
432 void doDirectoryInitialize(const std::string
&directoryPath
)
434 nldebug("Directory: '%s'", directoryPath
.c_str());
436 std::string dirPath
= standardizePath(directoryPath
, true);
437 std::vector
<std::string
> dirContents
;
439 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath
), false, true, true, dirContents
);
441 // nldebug("Native: '%s'", nativeDatabasePath(dirPath).c_str());
442 // nldebug("Contents: %i", dirContents.size());
444 for (std::vector
<std::string
>::iterator it
= dirContents
.begin(), end
= dirContents
.end(); it
!= end
; ++it
)
446 std::string subPath
= standardizePath(unnativeDatabasePath(*it
), false);
447 // nldebug("Path: '%s'", subPath.c_str());
448 // nldebug("Native: '%s'", nativeDatabasePath(subPath + " ").c_str());
450 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath
)))
452 if (subPath
.find("\\.") == std::string::npos
)
453 doDirectoryInitialize(subPath
);
456 doFileInitialize(subPath
);
462 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory
);
464 doDirectoryInitialize(std::string(SrcDirectoryRecursiveInit
));
468 void doFileScanner(const std::string
&filePath
)
470 if (filePath
[filePath
.size() - 3] == 'm' && filePath
[filePath
.size() - 2] == 'a' && filePath
[filePath
.size() - 1] == 'x')
472 nldebug("File: '%s'", filePath
.c_str());
474 std::vector
<char> buffer
;
475 buffer
.resize(NLMISC::CFile::getFileSize(nativeDatabasePath(filePath
)));
479 NLMISC::CIFile ifile
;
480 ifile
.open(nativeDatabasePath(filePath
), false);
481 ifile
.serialBuffer((uint8
*)(&buffer
[0]), buffer
.size());
486 for (std::vector
<char>::size_type i
= 256; i
< buffer
.size(); ++i
) // skip the first 256 lol :)
488 if (((NLMISC::toLower(buffer
[i
- 1]) == 'x' && NLMISC::toLower(buffer
[i
- 2]) == 'a' && NLMISC::toLower(buffer
[i
- 3]) == 'm')
489 || (NLMISC::toLower(buffer
[i
- 1]) == 'a' && NLMISC::toLower(buffer
[i
- 2]) == 'g' && NLMISC::toLower(buffer
[i
- 3]) == 't')
490 || (NLMISC::toLower(buffer
[i
- 1]) == 'g' && NLMISC::toLower(buffer
[i
- 2]) == 'n' && NLMISC::toLower(buffer
[i
- 3]) == 'p'))
491 && (NLMISC::toLower(buffer
[i
- 4]) == '.'))
493 // buffer[i] is the character after the path! :)
494 std::vector
<char>::size_type beginPath
= 0;
495 for (std::vector
<char>::size_type j
= i
- 4; j
> 0; --j
)
497 if (!isCharacter(buffer
[j
]))
499 if ((buffer
[j
+ 1] == '\\' && buffer
[j
+ 2] == '\\') || buffer
[j
] == 0)
504 // nlwarning("Invalid characters '%i' in path at %i, len %i!", (uint32)buffer[j], (uint32)j, (uint32)(i - j));
505 // beginPath = j + 1; // test
508 if (buffer
[j
] == ':')
516 std::vector
<char>::size_type sizePath
= i
- beginPath
;
517 std::string foundPath
= std::string(&buffer
[beginPath
], sizePath
); //std::string(buffer.at(beginPath), buffer.at(i));
518 //nldebug("Found path: '%s' from %i to %i", foundPath.c_str(), (uint32)beginPath, (uint32)i);
519 std::string fixedPath
= rewritePath(foundPath
, DatabaseDirectory
);
520 //nldebug("Rewrite to: '%s'", fixedPath.c_str());
531 void doDirectoryScanner(const std::string
&directoryPath
)
533 nldebug("Directory: '%s'", directoryPath
.c_str());
535 std::string dirPath
= standardizePath(directoryPath
, true);
536 std::vector
<std::string
> dirContents
;
538 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath
), false, true, true, dirContents
);
540 for (std::vector
<std::string
>::iterator it
= dirContents
.begin(), end
= dirContents
.end(); it
!= end
; ++it
)
542 std::string subPath
= standardizePath(unnativeDatabasePath(*it
), false);
544 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath
)))
546 if (subPath
.find("\\.") == std::string::npos
)
547 doDirectoryScanner(subPath
);
550 doFileScanner(subPath
);
556 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory
);
558 doDirectoryScanner(SrcDirectoryRecursiveHandle
);
560 for (std::set
<std::string
>::iterator it
= MissingFiles
.begin(), end
= MissingFiles
.end(); it
!= end
; ++it
)
561 nlinfo("Missing: '%s'", (*it
).c_str());
564 void handleFile(const std::string
&path
);
566 void doFileHandler(const std::string
&filePath
)
568 if (filePath
[filePath
.size() - 3] == 'm' && filePath
[filePath
.size() - 2] == 'a' && filePath
[filePath
.size() - 1] == 'x')
570 nldebug("File: '%s'", filePath
.c_str());
572 handleFile(nativeDatabasePath(filePath
));
576 void doDirectoryHandler(const std::string
&directoryPath
)
578 nldebug("Directory: '%s'", directoryPath
.c_str());
580 std::string dirPath
= standardizePath(directoryPath
, true);
581 std::vector
<std::string
> dirContents
;
583 NLMISC::CPath::getPathContent(nativeDatabasePath(dirPath
), false, true, true, dirContents
);
585 for (std::vector
<std::string
>::iterator it
= dirContents
.begin(), end
= dirContents
.end(); it
!= end
; ++it
)
587 std::string subPath
= standardizePath(unnativeDatabasePath(*it
), false);
589 if (NLMISC::CFile::isDirectory(nativeDatabasePath(subPath
)))
591 if (subPath
.find("\\.") == std::string::npos
)
592 doDirectoryHandler(subPath
);
595 doFileHandler(subPath
);
601 nlinfo("DatabaseDirectory: '%s'", DatabaseDirectory
);
603 doDirectoryHandler(SrcDirectoryRecursiveHandle
);
606 void serializeStorageContainer(PIPELINE::MAX::CStorageContainer
*storageContainer
, GsfInfile
*infile
, const char *streamName
)
608 GsfInput
*input
= gsf_infile_child_by_name(infile
, streamName
);
611 nlerror("GSF Could not read stream %s", streamName
);
615 PIPELINE::MAX::CStorageStream
instream(input
);
616 storageContainer
->serial(instream
);
618 g_object_unref(input
);
621 void serializeStorageContainer(PIPELINE::MAX::CStorageContainer
*storageContainer
, GsfOutfile
*outfile
, const char *streamName
)
624 GsfOutput
*output
= GSF_OUTPUT(gsf_outfile_new_child(outfile
, streamName
, false));
627 nlerror("GSF Could not write stream %s", streamName
);
631 PIPELINE::MAX::CStorageStream
outstream(output
);
632 storageContainer
->serial(outstream
);
634 gsf_output_close(output
);
635 g_object_unref(G_OBJECT(output
));
638 void serializeRaw(std::vector
<uint8
> &rawOutput
, GsfInfile
*infile
, const char *streamName
)
640 GsfInput
*input
= gsf_infile_child_by_name(infile
, streamName
);
643 nlerror("GSF Could not read stream %s", streamName
);
647 PIPELINE::MAX::CStorageStream
instream(input
);
648 rawOutput
.resize(instream
.size());
649 instream
.serialBuffer(&rawOutput
[0], rawOutput
.size());
651 g_object_unref(input
);
654 void serializeRaw(std::vector
<uint8
> &rawOutput
, GsfOutfile
*outfile
, const char *streamName
)
656 GsfOutput
*output
= GSF_OUTPUT(gsf_outfile_new_child(outfile
, streamName
, false));
659 nlerror("GSF Could not write stream %s", streamName
);
663 PIPELINE::MAX::CStorageStream
outstream(output
);
664 outstream
.serialBuffer(&rawOutput
[0], rawOutput
.size());
666 gsf_output_close(output
);
667 g_object_unref(G_OBJECT(output
));
670 std::string
cleanString(const std::string
&str
)
672 std::string res
= str
;
674 // \\Amiga\3D (10 chars)
677 if (res
.substr(res
.size() - 10) == "\\\\Amiga\\3D")
678 res
= res
.substr(0, res
.size() - 10);
682 if (res
.substr(res
.size() - 1) == "0")
683 res
= res
.substr(0, res
.size() - 1);
685 if (res
.size() > 4 && res
[res
.size() - 1] == '.')
687 if (res
.substr(res
.size() - 4) == "max.") // fix a stupid typo
688 res
= res
.substr(0, res
.size() - 1);
693 std::string
rewritePathFinal(const std::string
&str
)
695 std::string strtrimmed
= cleanString(str
);
696 std::string result
= rewritePath(strtrimmed
, DatabaseDirectory
);
697 if (NLMISC::CFile::getFilename(result
) != result
&& !NLMISC::CFile::fileExists(nativeDatabasePath(result
)) &&
698 ((result
[result
.size() - 3] == 't' && result
[result
.size() - 2] == 'g' && result
[result
.size() - 1] == 'a') || (result
[result
.size() - 3] == 'p' && result
[result
.size() - 2] == 'n' && result
[result
.size() - 1] == 'g'))
701 // nlwarning("Replacing missing '%s' with '%s'", result.c_str(), FallbackTga);
708 return NLMISC::CFile::getFilename(result
);
713 nldebug("Replacing '%s' with '%s'", str
.c_str(), result
.c_str());
718 bool isImportantFilePath(const std::string
&str
)
720 // nldebug("Is important? %s", str.c_str());
722 std::string strtrimmed
= cleanString(str
);
723 if (strtrimmed
.size() >= 4)
725 std::string strlw
= NLMISC::toLower(strtrimmed
);
726 return (strlw
[strlw
.size() - 3] == 'm' && strlw
[strlw
.size() - 2] == 'a' && strlw
[strlw
.size() - 1] == 'x')
727 || (strlw
[strlw
.size() - 3] == 't' && strlw
[strlw
.size() - 2] == 'g' && strlw
[strlw
.size() - 1] == 'a')
728 || (strlw
[strlw
.size() - 3] == 'p' && strlw
[strlw
.size() - 2] == 'n' && strlw
[strlw
.size() - 1] == 'g');
733 bool hasImportantFilePath(CStorageRaw
*raw
)
735 if (raw
->Value
.size() >= 4)
737 // Find any occurences of .max, .png or .tga in ascii or utf16
738 for (uint i
= 0; i
< raw
->Value
.size() - 3; ++i
)
740 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
741 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 1]) == 'm'
742 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 'a'
743 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 3]) == 'x')
745 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
746 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 1]) == 't'
747 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 'g'
748 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 3]) == 'a')
750 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
751 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 1]) == 'p'
752 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 'n'
753 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 3]) == 'g')
757 if (raw
->Value
.size() >= 6)
759 for (uint i
= 0; i
< raw
->Value
.size() - 6; ++i
)
761 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
762 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 'm'
763 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 4]) == 'a'
764 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 6]) == 'x')
766 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
767 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 't'
768 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 4]) == 'g'
769 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 6]) == 'a')
771 if (NLMISC::toLower(((char *)&raw
->Value
[0])[i
]) == '.'
772 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 2]) == 'p'
773 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 4]) == 'n'
774 && NLMISC::toLower(((char *)&raw
->Value
[0])[i
+ 6]) == 'g')
781 bool fixChunk(uint16 id
, IStorageObject
*chunk
)
785 // nldebug("testing 4656: %s", chunk->toString().c_str());
787 bool changed
= false;
788 CStorageValue
<std::string
> *asString
= dynamic_cast<CStorageValue
<std::string
> *>(chunk
);
791 // nldebug("String: %s", asString->Value.c_str());
792 if (isImportantFilePath(asString
->Value
))
794 std::string rewritten
= rewritePathFinal(asString
->Value
);
795 if (rewritten
!= asString
->Value
)
797 asString
->Value
= rewritten
;
803 CStorageValue
<ucstring
> *asUCString
= dynamic_cast<CStorageValue
<ucstring
> *>(chunk
);
806 // nldebug("UCString: %s", asUCString->Value.toUtf8().c_str());
807 if (isImportantFilePath(asUCString
->Value
.toString()))
809 std::string rewritten
= rewritePathFinal(asUCString
->Value
.toString());
810 if (rewritten
!= asUCString
->Value
.toString())
812 asUCString
->Value
.fromUtf8(rewritten
);
818 CStorageRaw
*asRaw
= dynamic_cast<CStorageRaw
*>(chunk
);
824 // nldebug("4656: %s", chunk->toString().c_str());
827 case 288: // .max xref in classdata
828 if (hasImportantFilePath(asRaw
))
830 // generic ucstring really
831 nlassert(asRaw
->Value
.size() % 2 == 0);
833 str
.resize(asRaw
->Value
.size() / 2);
834 memcpy(&str
[0], &asRaw
->Value
[0], asRaw
->Value
.size());
835 // nldebug("[%s]", str.toString().c_str());
836 nlassert(isImportantFilePath(str
.toString()));
837 std::string rewritten
= rewritePathFinal(str
.toString());
838 if (rewritten
!= str
.toString())
840 str
.fromUtf8(rewritten
);
841 asRaw
->Value
.resize(str
.size() * 2);
842 memcpy(&asRaw
->Value
[0], &str
[0], asRaw
->Value
.size());
848 if (hasImportantFilePath(asRaw
))
850 // 10 00 08 00 00 00 02 00 80 00 40 // 11 bytes O_O
852 // 57 3a 5c 44 61 74 61 62 61 73
853 // 65 5c 73 74 75 66 66 5c 74 72
854 // 79 6b 65 72 5c 61 67 65 6e 74
855 // 73 5c 5f 74 65 78 74 75 72 65
856 // 73 5c 61 63 74 6f 72 73 5c 54
857 // 52 5f 48 4f 46 5f 63 69 76 69
858 // 6c 30 31 5f 74 6f 72 73 6f 5f
859 // 43 31 2e 74 67 61 00
860 bool overrideFF
= true; // Patch for some ligo max files
861 if (overrideFF
&& asRaw
->Value
.size() > 4 && asRaw
->Value
[asRaw
->Value
.size() - 4] == 0xFF)
863 nlwarning("0xFFFFFFFF");
865 else if (!(asRaw
->Value
[asRaw
->Value
.size() - 1] == 0))
867 nlinfo("Id: %i, size: %i", (uint32
)id
, asRaw
->Value
.size());
868 asRaw
->toString(std::cout
);
870 nlwarning("not null term");
878 uint32 size
= ((uint32
*)&asRaw
->Value
[11])[0];
879 if (!(asRaw
->Value
.size() == size
+ 4 + 11))
881 nlinfo("Id: %i, size: %i", (uint32
)id
, asRaw
->Value
.size());
882 asRaw
->toString(std::cout
);
884 nlwarning("size '%i' does not match '%i', use different algo :)", size
, asRaw
->Value
.size() - 4 - 11);
887 std::vector
<std::string
> strings
;
889 NLMISC::CMemStream mem
;
892 mem
.serialBuffer(nonsense
, 11);
895 while ((sint
)mem
.getPos() != (sint
)mem
.size())
897 //nldebug("pos %i", mem.getPos());
898 //nldebug("size %i", mem.size());
901 nlassert(funny
== '@');
904 //nldebug("size %i", size);
905 if (!overrideFF
&& size
== -1)
907 nldebug("size %i", size
);
908 nlwarning("bad size");
917 if (overrideFF
&& size
== -1)
925 mem
.serialBuffer((uint8
*)&v
[0], size
);
927 if (!(v
[v
.size() - 1] == 0))
929 nlinfo("Id: %i, size: %i", (uint32
)id
, asRaw
->Value
.size());
930 asRaw
->toString(std::cout
);
932 nlwarning("not null term inside array stuff %i '%s'", i
, v
.c_str());
940 v
.resize(v
.size() - 1);
941 // nldebug("%s", v.c_str());
942 strings
.push_back(v
);
946 nlassert(strings
.size() == counter
);
947 asRaw
->Value
.resize(0);
949 bool foundone
= false;
950 for (uint i
= 0; i
< strings
.size(); ++i
)
952 if (isImportantFilePath(strings
[i
]))
955 std::string rewritten
= rewritePathFinal(strings
[i
]);
956 if (rewritten
!= strings
[i
])
958 strings
[i
] = rewritten
;
966 NLMISC::CMemStream mem
;
967 mem
.serialBuffer(nonsense
, 11);
969 for (uint i
= 0; i
< strings
.size(); ++i
)
974 strings
[i
].resize(strings
[i
].size() + 1);
975 strings
[i
][strings
[i
].size() - 1] = 0;
976 uint32 size
= strings
[i
].size();
978 mem
.serialBuffer((uint8
*)&strings
[i
][0], size
);
980 asRaw
->setSize(mem
.getPos());
989 str
.resize(size
- 1);
990 memcpy(&str
[0], &asRaw
->Value
[15], str
.size());
991 // nldebug("test '%s'", str.c_str());
992 // asRaw->toString(std::cout);
993 if (!isImportantFilePath(str
))
995 nlinfo("Id: %i, size: %i", (uint32
)id
, asRaw
->Value
.size());
996 asRaw
->toString(std::cout
);
998 nlwarning("not important");
1006 std::string rewritten
= rewritePathFinal(str
);
1007 if (rewritten
!= str
)
1010 asRaw
->Value
.resize(str
.size() + 11 + 4 + 1);
1011 memcpy(&asRaw
->Value
[15], &str
[0], str
.size());
1012 ((uint32
*)&asRaw
->Value
[11])[0] = str
.size() + 1;
1013 asRaw
->Value
[asRaw
->Value
.size() - 1] = 0;
1019 if (hasImportantFilePath(asRaw
))
1021 // null term c string
1022 nlassert(asRaw
->Value
[asRaw
->Value
.size() - 1] == 0);
1024 str
.resize(asRaw
->Value
.size() - 1);
1025 memcpy(&str
[0], &asRaw
->Value
[0], str
.size());
1026 if (!isImportantFilePath(str
))
1028 nlinfo("Id: %i", (uint32
)id
);
1029 asRaw
->toString(std::cout
);
1030 nlerror("not important");
1032 std::string rewritten
= rewritePathFinal(str
);
1033 if (rewritten
!= str
)
1036 asRaw
->Value
.resize(str
.size() + 1);
1037 memcpy(&asRaw
->Value
[0], &str
[0], str
.size());
1038 asRaw
->Value
[asRaw
->Value
.size() - 1] = 0;
1044 if (asRaw
->Value
.size() > 0 && asRaw
->Value
[0] == 'I')
1050 if (hasImportantFilePath(asRaw
))
1052 nlinfo("Id: %i", (uint32
)id
);
1053 asRaw
->toString(std::cout
);
1054 nlwarning("Found important file path");
1068 bool fixChunks(CStorageContainer
*container
)
1070 bool changed
= false;
1071 for (CStorageContainer::TStorageObjectConstIt it
= container
->chunks().begin(), end
= container
->chunks().end(); it
!= end
; ++it
)
1073 if (it
->second
->isContainer())
1075 changed
= (changed
|| fixChunks(static_cast<CStorageContainer
*>(it
->second
)));
1079 changed
= (changed
|| fixChunk(it
->first
, it
->second
));
1085 void handleFile(const std::string
&path
)
1089 GsfDocMetaData
*metadata
= gsf_doc_meta_data_new();
1092 GsfInput
*src
= gsf_input_stdio_new(path
.c_str(), &err
);
1093 if (err
) { nlerror("GSF Failed to open %s", path
.c_str()); return; }
1095 GsfInfile
*infile
= gsf_infile_msole_new(src
, NULL
);
1096 if (!infile
) { nlerror("GSF Failed to recognize %s", path
.c_str()); return; }
1097 g_object_unref(src
);
1100 if (!gsf_infile_msole_get_class_id((GsfInfileMSOle
*)infile
, classId
))
1101 nlerror("GSF Did not find classId");
1103 PIPELINE::MAX::CStorageContainer videoPostQueue
;
1104 serializeStorageContainer(&videoPostQueue
, infile
, "VideoPostQueue");
1105 PIPELINE::MAX::CStorageContainer config
;
1106 serializeStorageContainer(&config
, infile
, "Config");
1107 PIPELINE::MAX::CStorageContainer classData
;
1108 serializeStorageContainer(&classData
, infile
, "ClassData");
1110 std::vector
<uint8
> summaryInformation
;
1111 serializeRaw(summaryInformation
, infile
, "\05SummaryInformation");
1113 std::vector
<uint8
> documentSummaryInformation
;
1114 serializeRaw(documentSummaryInformation
, infile
, "\05DocumentSummaryInformation"); // Can't read this, don't care.
1116 PIPELINE::MAX::CDllDirectory dllDirectory
;
1117 serializeStorageContainer(&dllDirectory
, infile
, "DllDirectory");
1118 dllDirectory
.parse(VersionUnknown
);
1120 PIPELINE::MAX::CClassDirectory3
classDirectory3(&dllDirectory
);
1121 serializeStorageContainer(&classDirectory3
, infile
, "ClassDirectory3");
1122 classDirectory3
.parse(VersionUnknown
);
1124 PIPELINE::MAX::CScene
scene(&SceneClassRegistry
, &dllDirectory
, &classDirectory3
);
1125 serializeStorageContainer(&scene
, infile
, "Scene");
1129 // Not parsing the scene for this function.
1130 scene
.parse(VersionUnknown
);
1135 PIPELINE::MAX::CStorageContainer dllDirectory;
1136 serializeStorageContainer(&dllDirectory, infile, "DllDirectory");
1138 PIPELINE::MAX::CStorageContainer classDirectory3;
1139 serializeStorageContainer(&classDirectory3, infile, "ClassDirectory3");
1141 PIPELINE::MAX::CStorageContainer scene;
1142 serializeStorageContainer(&scene, infile, "Scene");
1147 videoPostQueue
.toString(std::cout
);
1148 config
.toString(std::cout
);
1149 classData
.toString(std::cout
);
1150 dllDirectory
.toString(std::cout
);
1151 classDirectory3
.toString(std::cout
);
1152 scene
.toString(std::cout
);
1157 // Not parsing the scene for this function.
1158 scene
.build(VersionUnknown
);
1162 g_object_unref(infile
);
1164 bool pathsChanged
= !WritePathChangesOnly
;
1167 pathsChanged
= pathsChanged
|| fixChunks(&classData
);
1168 pathsChanged
= pathsChanged
|| fixChunks(&scene
);
1174 scene
.parse(VersionUnknown
);
1175 NLMISC::CClassId editMeshClassId
= NLMISC::CClassId(0x00000050, 0x00000000);
1176 NLMISC::CClassId editableMeshClassId
= NLMISC::CClassId(0xe44f10b3, 0x00000000);
1177 // from: (0x2ec82081, 0x045a6271)
1178 NLMISC::CClassId fromClassId
= NLMISC::CClassId(0x2ec82081, 0x045a6271);
1179 // Find all object space modifier derived containing map extender
1180 for (CStorageContainer::TStorageObjectConstIt it
= scene
.container()->chunks().begin(), end
= scene
.container()->chunks().end(); it
!= end
; ++it
)
1182 if (it
->first
== 0x2032) // Derived Object
1184 // nldebug("Found derived object");
1185 CReferenceMaker
*derivedObject
= dynamic_cast<CReferenceMaker
*>(it
->second
);
1186 nlassert(derivedObject
);
1188 // Find map extender in the modifier stack
1189 uint mapExtenderIndex
= 0;
1190 CReferenceMaker
*mapExtender
= NULL
;
1191 for (uint i
= 0; i
< derivedObject
->nbReferences(); ++i
)
1193 if (derivedObject
->getReference(i
) && derivedObject
->getReference(i
)->classDesc()->classId() == fromClassId
)
1195 nldebug("Found map extender at '%i' / '%i'!", i
, derivedObject
->nbReferences());
1196 mapExtenderIndex
= i
;
1197 mapExtender
= derivedObject
->getReference(i
);
1199 bool deleteDerivedGeom
= false;
1200 CStorageContainer
*derivedData
= dynamic_cast<CStorageContainer
*>(derivedObject
->findStorageObject(0x2500, mapExtenderIndex
));
1201 nlassert(derivedData
);
1202 CStorageContainer
*derivedGeom
= dynamic_cast<CStorageContainer
*>(derivedData
->findStorageObject(0x2512));
1205 CStorageRaw
*derivedGeomRaw
= dynamic_cast<CStorageRaw
*>(derivedData
->findStorageObject(0x2512));
1208 nlwarning("Derived geometry raw instead of as container");
1209 NLMISC::CMemStream memGeom
;
1210 derivedGeomRaw
->serial(memGeom
);
1211 uint size
= memGeom
.getPos();
1213 derivedGeom
= new CStorageContainer();
1214 deleteDerivedGeom
= true;
1215 derivedGeom
->serial(memGeom
, size
);
1219 derivedData
->toString(std::cout
);
1220 nlwarning("derived geometry missing!!!");
1229 CStorageRaw
*derivedVertices
= dynamic_cast<CStorageRaw
*>(derivedGeom
->findStorageObject(0x03e9));
1230 if (!derivedVertices
)
1232 derivedGeom
->toString(std::cout
);
1233 nlwarning("derived vertices missing!!!");
1241 CStorageRaw
*derivedIndices
= dynamic_cast<CStorageRaw
*>(derivedGeom
->findStorageObject(0x03eb));
1242 if (!derivedIndices
)
1244 derivedGeom
->toString(std::cout
);
1245 nlwarning("derived indices missing!!!");
1254 CStorageContainer::TStorageObjectContainer
&mapChunks
= const_cast<CStorageContainer::TStorageObjectContainer
&>(mapExtender
->chunks());
1256 // CStorageContainer::TStorageObjectWithId
1258 nlassert(derivedVertices
->Value
.size() % 12 == 0);
1259 nlassert(derivedIndices
->Value
.size() % 12 == 0);
1260 uint32 nbVertices
= derivedVertices
->Value
.size() / 12;
1261 uint32 nbFaces
= derivedIndices
->Value
.size() / 12;
1262 nldebug("Vertices: %i", nbVertices
);
1263 nldebug("Faces: %i", nbFaces
);
1265 // Write vertex chunks
1266 CStorageValue
<uint32
> *chunkVertCount
= new CStorageValue
<uint32
>();
1267 chunkVertCount
->Value
= nbVertices
;
1268 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0100, chunkVertCount
));
1270 CStorageRaw
*chunkVerts
= new CStorageRaw();
1271 NLMISC::CMemStream memVerts
;
1272 derivedVertices
->serial(memVerts
);
1273 chunkVerts
->setSize(memVerts
.getPos());
1275 chunkVerts
->serial(memVerts
);
1276 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0110, chunkVerts
));
1278 // Write face chunks
1279 CStorageValue
<uint32
> *chunkFaceCount
= new CStorageValue
<uint32
>();
1280 chunkFaceCount
->Value
= nbFaces
;
1281 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0230, chunkFaceCount
));
1283 CStorageRaw
*chunkFaces
= new CStorageRaw();
1284 NLMISC::CMemStream memFaces
;
1285 derivedIndices
->serial(memFaces
);
1286 chunkFaces
->setSize(memFaces
.getPos());
1288 chunkFaces
->serial(memFaces
);
1289 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0240, chunkFaces
));
1291 // Write geom points
1292 CStorageValue
<uint32
> *chunkGeomPointCount
= new CStorageValue
<uint32
>();
1293 chunkGeomPointCount
->Value
= nbVertices
; // derived vertices?
1294 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0320, chunkGeomPointCount
));
1296 CStorageRaw
*chunkGeomPoints
= new CStorageRaw();
1297 NLMISC::CMemStream memGeomPoints
;
1298 derivedVertices
->serial(memGeomPoints
); // derived vertices?
1299 chunkGeomPoints
->setSize(memGeomPoints
.getPos());
1300 memGeomPoints
.invert();
1301 chunkGeomPoints
->serial(memGeomPoints
);
1302 mapChunks
.push_back(CStorageContainer::TStorageObjectWithId(0x0330, chunkGeomPoints
));
1304 if (deleteDerivedGeom
)
1308 nldebug("Converted!");
1315 CReferenceMaker
*editMesh
= NULL
;
1316 for (uint i
= 0; i
< derivedObject
->nbReferences(); ++i
)
1318 if (derivedObject
->getReference(i
) && derivedObject
->getReference(i
)->classDesc()->classId() == editMeshClassId
)
1320 nldebug("Found edit mesh at '%i' / '%i'!", i
, derivedObject
->nbReferences());
1322 editMesh
= derivedObject
->getReference(i
);
1324 // Ensure no selection
1326 CStorageContainer::TStorageObjectContainer
&meshChunks
= const_cast<CStorageContainer::TStorageObjectContainer
&>(editMesh
->chunks());
1328 // Ensure no selection
1329 for (CStorageContainer::TStorageObjectIterator it
= meshChunks
.begin(), end
= meshChunks
.end(); it
!= end
; )
1331 CStorageContainer::TStorageObjectIterator next
= it
; ++next
;
1335 nldebug("Override selection");
1338 CStorageValue
<uint16
> *v
= new CStorageValue
<uint16
>();
1351 uint editableMeshIndex
;
1352 CReferenceMaker
*editableMesh
= NULL
;
1353 for (uint i
= 0; i
< derivedObject
->nbReferences(); ++i
)
1355 if (derivedObject
->getReference(i
) && derivedObject
->getReference(i
)->classDesc()->classId() == editableMeshClassId
)
1357 nldebug("Found editable mesh at '%i' / '%i'!", i
, derivedObject
->nbReferences());
1358 editableMeshIndex
= i
;
1359 editableMesh
= derivedObject
->getReference(i
);
1361 CStorageContainer::TStorageObjectContainer
&meshChunks
= const_cast<CStorageContainer::TStorageObjectContainer
&>(editableMesh
->chunks());
1363 // Ensure no selection
1364 for (CStorageContainer::TStorageObjectIterator it
= meshChunks
.begin(), end
= meshChunks
.end(); it
!= end
; )
1366 CStorageContainer::TStorageObjectIterator next
= it
; ++next
;
1377 nldebug("Erase selection");
1378 meshChunks
.erase(it
);
1381 nldebug("Override selection");
1384 CStorageValue
<uint32
> *v
= new CStorageValue
<uint32
>();
1397 if (editableMesh
&& editableMeshIndex
+ 1 != derivedObject
->nbReferences())
1399 nlwarning("Editable mesh not at bottom of the stack, this is unpossible!");
1405 if (editableMesh == NULL || editMesh == NULL)
1407 derivedObject->toString(std::cout);
1408 nlwarning("editable mesh or edit mesh not found");
1415 //derivedObject->toString(std::cout);
1416 //editableMesh->toString(std::cout);
1418 // derivedObject -> 0x2500 -> 0x2512 -> 0x03e9 / 0x03eb
1419 // editableMesh -> 0x08fe (geom) -> 0x0916 / 0x0918
1421 CStorageContainer *editableMeshGeometry = dynamic_cast<CStorageContainer *>(editableMesh->findStorageObject(0x08fe));
1422 // nlassert(editableMeshGeometry);
1423 if (!editableMeshGeometry)
1425 nlwarning("broken");
1430 CStorageRaw *editableVertices = dynamic_cast<CStorageRaw *>(editableMeshGeometry->findStorageObject(0x0916));
1431 nlassert(editableVertices);
1432 CStorageRaw *editableIndices = dynamic_cast<CStorageRaw *>(editableMeshGeometry->findStorageObject(0x0918));
1433 nlassert(editableIndices);
1435 //return new CStorageArraySizePre<NLMISC::CVector>();
1436 if (derivedIndices->Value.size() != editableIndices->Value.size())
1438 editableMesh->toString(std::cout);
1439 derivedObject->toString(std::cout);
1440 nlwarning("size mismatch");
1446 editableVertices->Value.clear();
1447 editableIndices->Value.clear();
1449 nlassert(derivedVertices->Value.size() % 12 == 0);
1450 uint32 nbVertices = derivedVertices->Value.size() / 12;
1451 NLMISC::CMemStream memVertices;
1452 memVertices.serial(nbVertices);
1453 derivedVertices->serial(memVertices);
1454 memVertices.invert();
1455 editableVertices->setSize(derivedVertices->Value.size() + 4);
1456 editableVertices->serial(memVertices);
1458 NLMISC::CMemStream memIndices;
1459 derivedIndices->serial(memIndices);
1460 memIndices.invert();
1461 editableIndices->setSize(derivedIndices->Value.size());
1462 editableIndices->serial(memIndices);
1467 // to: (0x02df2e3a, 0x72ba4e1f)
1468 NLMISC::CClassId toClassId
= NLMISC::CClassId(0x02df2e3a, 0x72ba4e1f); // uvw unwrap
1469 // NLMISC::CClassId toClassId = NLMISC::CClassId(0x5c5b50f7,0x60397ca1); // converttomesh :|
1470 // NLMISC::CClassId toClassId = NLMISC::CClassId(0x31f9c666, 0x03b4a577); // uvw mapping add
1471 // dllname to: uvwunwrap.dlm
1472 for (CStorageContainer::TStorageObjectConstIt it
= classDirectory3
.chunks().begin(), end
= classDirectory3
.chunks().end(); it
!= end
; ++it
)
1474 CClassEntry
*classEntry
= dynamic_cast<CClassEntry
*>(it
->second
);
1477 //nldebug("class entry %s", classEntry->classId().toString().c_str());
1478 if (classEntry
->classId() == fromClassId
)
1480 nldebug("Found class id to replace!");
1481 classEntry
->overrideClassId(toClassId
);
1482 CDllEntry
*dllEntry
= const_cast<CDllEntry
*>(dllDirectory
.get(classEntry
->dllIndex()));
1483 dllEntry
->overrideDllFilename(ucstring("uvwunwrap.dlm"));
1486 //else nldebug("not class entry");
1492 dllDirectory
.disown();
1493 classDirectory3
.disown();
1494 if (WriteModified
&& (ReplaceMapExt
|| pathsChanged
))
1496 const char *outpath
= (WriteDummy
? "testdummy.max" : path
.c_str());
1498 GsfOutfile
*outfile
;
1500 output
= gsf_output_stdio_new(outpath
, &err
);
1501 if (err
) { nlerror("GSF Failed to create %s", outpath
); return; }
1502 outfile
= gsf_outfile_msole_new(output
);
1503 g_object_unref(G_OBJECT(output
));
1505 serializeStorageContainer(&videoPostQueue
, outfile
, "VideoPostQueue");
1506 serializeStorageContainer(&scene
, outfile
, "Scene");
1507 serializeStorageContainer(&dllDirectory
, outfile
, "DllDirectory");
1508 serializeStorageContainer(&config
, outfile
, "Config");
1509 serializeStorageContainer(&classDirectory3
, outfile
, "ClassDirectory3");
1510 serializeStorageContainer(&classData
, outfile
, "ClassData");
1511 serializeRaw(summaryInformation
, outfile
, "\05SummaryInformation");
1512 serializeRaw(documentSummaryInformation
, outfile
, "\05DocumentSummaryInformation");
1514 if (!gsf_outfile_msole_set_class_id((GsfOutfileMSOle
*)outfile
, classId
))
1515 nlerror("GSF Cannot write class id");
1517 gsf_output_close(GSF_OUTPUT(outfile
));
1518 g_object_unref(G_OBJECT(outfile
));
1522 nlinfo("Dummy written, press key for next");
1528 g_object_unref(metadata
);
1531 // int __stdcall WinMain(void *, void *, void *, int)
1532 int main(int argc
, char **argv
)
1535 printf("Pipeline Max Rewrite Assets\n");
1536 char const *me
= (argv
[0] ? argv
[0] : "pipeline_max_rewrite_assets");
1540 // Register all plugin classes
1541 CBuiltin::registerClasses(&SceneClassRegistry
);
1542 CUpdate1::registerClasses(&SceneClassRegistry
);
1543 CEPoly::registerClasses(&SceneClassRegistry
);
1545 //handleFile("/srv/work/database/interfaces/anims_max/cp_fy_hof_species.max");
1548 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\desert\\max\\zonematerial-converted-brandon.max")); // overrideFF
1549 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\desert\\max\\zonematerial-converted-154_dz.max")); // overrideFF
1550 //handleFile(nativeDatabasePath("w:\\database\\landscape\\ligo\\lacustre\\max\\zonematerial-converted-village_a.max"));
1551 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_mission_reward_karavan_bigshield.max"));
1552 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_acc_pick_o.max"));
1553 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_zo_wea_trib_masse1m.max"));
1554 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_fy_wea_trib_grand_bouclier.max"));
1555 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\ge_mission_entrepot.max"));
1556 //handleFile(nativeDatabasePath("w:\\database\\stuff\\generique\\agents\\accessories\\mesh_wip\\all_trib_weapons.max"));
1557 //handleFile(nativeDatabasePath("w:\\database\\stuff\\fyros\\decors\\constructions\\fy_cn_smokehouse.max"));
1558 //handleFile("/srv/work/database/landscape/ligo/jungle/pipeline_max/zonematerial-foret-ruine_boss.max");
1559 //handleFile("/srv/work/database/stuff/fyros/agents/actors/male/animation/anims_non_utilisees/fy_hom_assis_boire_verre.max");
1560 //handleFile("/home/kaetemi/3dsMax/scenes/test_clear_add_uvw.max");
1563 for (std::set
<std::string
>::iterator it
= MissingFiles
.begin(), end
= MissingFiles
.end(); it
!= end
; ++it
)
1564 nlinfo("Missing: '%s'", (*it
).c_str());