1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "nel/misc/stream.h"
21 #include "nel/misc/file.h"
22 #include "nel/misc/vector.h"
23 #include "nel/misc/time_nl.h"
24 #include "nel/misc/config_file.h"
25 #include "nel/misc/path.h"
28 #include "nel/georges/u_form.h"
29 #include "nel/georges/u_form_elm.h"
30 #include "nel/georges/u_form_loader.h"
33 #include "nel/3d/zone.h"
34 #include "nel/3d/zone_lighter.h"
35 #include "nel/3d/quad_grid.h"
36 #include "nel/3d/landscape.h"
37 #include "nel/3d/scene_group.h"
38 #include "nel/3d/shape.h"
39 #include "nel/3d/transform_shape.h"
40 #include "nel/3d/register_3d.h"
41 #include "nel/3d/water_shape.h"
43 #include "../zone_lib/zone_utility.h"
46 using namespace NLMISC
;
51 const char *progressbar
[BAR_LENGTH
]=
69 "[................ ]",
70 "[................. ]",
71 "[.................. ]",
72 "[................... ]",
73 "[....................]"
77 class CMyZoneLighter
: public CZoneLighter
80 virtual void progress (const char *message
, float progress
)
84 uint pgId
= (uint
)(progress
*(float)BAR_LENGTH
);
85 pgId
= min(pgId
, (uint
)(BAR_LENGTH
-1));
86 sprintf (msg
, "\r%s: %s", message
, progressbar
[pgId
]);
88 for (i
=(uint
)strlen(msg
); i
<79; i
++)
95 struct CInstanceGroupRef
101 //=======================================================================================
102 // load additionnal ig from a village (ryzom specific)
103 static void loadIGFromVillage(const NLGEORGES::UFormElm
*villageItem
, const std::string
&continentName
,
104 uint villageIndex
, std::list
<CInstanceGroupRef
> &instanceGroups
, CConfigFile::CVar
&additionalIgNames
)
106 const NLGEORGES::UFormElm
*igNamesItem
;
107 if (! (villageItem
->getNodeByName (&igNamesItem
, "IgList") && igNamesItem
) )
109 nlwarning("No list of IGs was found in the continent form %s, village #%d", continentName
.c_str(), villageIndex
);
113 // Get number of village
115 nlverify (igNamesItem
->getArraySize (numIgs
));
116 const NLGEORGES::UFormElm
*currIg
;
117 for(uint l
= 0; l
< numIgs
; ++l
)
119 if (!(igNamesItem
->getArrayNode (&currIg
, l
) && currIg
))
121 nlwarning("Couldn't get ig #%d in the continent form %s, in village #%d", l
, continentName
.c_str(), villageIndex
);
124 const NLGEORGES::UFormElm
*igNameItem
;
125 currIg
->getNodeByName (&igNameItem
, "IgName");
127 if (!igNameItem
->getValue (igName
))
129 nlwarning("Couldn't get ig name of ig #%d in the continent form %s, in village #%d", l
, continentName
.c_str(), villageIndex
);
134 nlwarning("Ig name of ig #%d in the continent form %s, in village #%d is an empty string", l
, continentName
.c_str(), villageIndex
);
138 igName
= CFile::getFilenameWithoutExtension(igName
) + ".ig";
140 // verify that the ig is not already added (case of tr_water.ig in additional_igs)
141 for(uint igAdd
= 0;igAdd
<(uint
)additionalIgNames
.size();igAdd
++)
143 if( toLowerAscii(additionalIgNames
.asString()) == toLower(igName
) )
145 nlwarning("Skipping Village Ig %s, cause already exist in additional ig", igName
.c_str());
151 string nameLookup
= CPath::lookup (igName
, false, true);
152 if (!nameLookup
.empty())
155 // Try to open the file
156 if (inputFile
.open (nameLookup
))
159 CUniquePtr
<CInstanceGroup
> group(new CInstanceGroup
);
162 group
->serial (inputFile
);
164 catch(const NLMISC::Exception
&)
166 nlwarning ("Error while loading instance group %s", igName
.c_str());
171 CInstanceGroupRef iref
;
172 iref
.IG
= group
.release();
173 iref
.AddLight
= false;
174 instanceGroups
.push_back (iref
);
179 nlwarning ("Can't open instance group %s\n", igName
.c_str());
186 //=======================================================================================
187 // load additionnal ig from a continent (ryzom specific)
188 static void loadIGFromContinent(NLMISC::CConfigFile
¶meter
, std::list
<CInstanceGroupRef
> &instanceGroups
,
189 const std::vector
<std::string
> &zoneNameArray
,
190 CConfigFile::CVar
&additionalIgNames
)
195 CConfigFile::CVar
&continent_name_var
= parameter
.getVar ("continent_name");
196 CConfigFile::CVar
&level_design_directory
= parameter
.getVar ("level_design_directory");
197 CConfigFile::CVar
&level_design_world_directory
= parameter
.getVar ("level_design_world_directory");
198 CConfigFile::CVar
&level_design_dfn_directory
= parameter
.getVar ("level_design_dfn_directory");
199 CPath::addSearchPath(level_design_dfn_directory
.asString(), true, false);
200 CPath::addSearchPath(level_design_world_directory
.asString(), true, false);
202 std::string continentName
= continent_name_var
.asString();
203 if (CFile::getExtension(continentName
).empty())
204 continentName
+= ".continent";
206 NLGEORGES::UFormLoader
*loader
= NLGEORGES::UFormLoader::createLoader();
208 std::string pathName
= CPath::lookup(continentName
); // level_design_world_directory.asString() + "/" + continentName;
209 if (pathName
.empty())
211 nlwarning("Can't find continent form : %s", continentName
.c_str());
214 NLGEORGES::UForm
*villageForm
;
215 villageForm
= loader
->loadForm(pathName
.c_str());
216 if(villageForm
!= NULL
)
218 NLGEORGES::UFormElm
&rootItem
= villageForm
->getRootNode();
219 // try to get the village list
220 // Load the village list
221 NLGEORGES::UFormElm
*villagesItem
;
222 if(!(rootItem
.getNodeByName (&villagesItem
, "Villages") && villagesItem
))
224 nlwarning("No villages where found in %s", continentName
.c_str());
228 // Get number of village
230 nlverify (villagesItem
->getArraySize (numVillage
));
233 for(uint k
= 0; k
< numVillage
; ++k
)
235 NLGEORGES::UFormElm
*currVillage
;
236 if (!(villagesItem
->getArrayNode (&currVillage
, k
) && currVillage
))
238 nlwarning("Couldn't get village %d in continent %s", continentName
.c_str(), k
);
241 // check that this village is in the dependency zones
242 NLGEORGES::UFormElm
*zoneNameItem
;
243 if (!currVillage
->getNodeByName (&zoneNameItem
, "Zone") && zoneNameItem
)
245 nlwarning("Couldn't get zone item of village %d in continent %s", continentName
.c_str(), k
);
248 std::string zoneName
;
249 if (!zoneNameItem
->getValue(zoneName
))
251 nlwarning("Couldn't get zone name of village %d in continent %s", continentName
.c_str(), k
);
255 zoneName
= CFile::getFilenameWithoutExtension(zoneName
);
256 for(uint l
= 0; l
< zoneNameArray
.size(); ++l
)
258 if (NLMISC::nlstricmp(CFile::getFilenameWithoutExtension(zoneNameArray
[l
]), zoneName
) == 0)
260 // ok, it is in the dependant zones
261 loadIGFromVillage(currVillage
, continentName
, k
, instanceGroups
, additionalIgNames
);
269 nlwarning("Can't load continent form : %s", continentName
.c_str());
272 catch (const NLMISC::EUnknownVar
&e
)
278 //=======================================================================================
279 int main(int argc
, char* argv
[])
282 TTime time
=CTime::getLocalTime ();
284 // Filter addSearchPath
285 NLMISC::createDebug();
286 InfoLog
->addNegativeFilter ("adding the path");
287 WarningLog
->addNegativeFilter ("continent.cfg");
292 // Good number of args ?
296 printf ("%s [zonein.zone] [zoneout.zone] [parameter_file] [dependancy_file] [-waterpatch bkupdir] \n", argv
[0]);
300 // to patch only the tiles flags
301 bool tileWaterPatchOnly
;
302 tileWaterPatchOnly
= argc
==7 && string(argv
[5])=="-waterpatch";
303 string tileWaterPatchBkupDir
;
304 if(tileWaterPatchOnly
)
305 tileWaterPatchBkupDir
= argv
[6];
311 string ext
=getExt (argv
[1]);
312 string dir
=getDir (argv
[1]);
314 // Open it for reading
315 if (inputFile
.open (argv
[1]))
318 string zoneName
=toLowerAscii (string ("zone_"+getName (argv
[1])));
323 // Read the config file
324 CConfigFile parameter
;
325 CConfigFile dependency
;
327 // Load and parse the dependency file
328 parameter
.load (argv
[3]);
331 // *** Build the lighter descriptor
334 CZoneLighter::CLightDesc lighterDesc
;
337 CConfigFile::CVar
&bank_name
= parameter
.getVar ("bank_name");
339 // Load instance group ?
340 CConfigFile::CVar
&load_ig
= parameter
.getVar ("load_ig");
341 bool loadInstanceGroup
= load_ig
.asInt ()!=0;
343 CConfigFile::CVar
&additionnal_ig
= parameter
.getVar ("additionnal_ig");
346 CConfigFile::CVar
&quad_grid_size
= parameter
.getVar ("quad_grid_size");
347 lighterDesc
.GridSize
=quad_grid_size
.asInt();
350 CConfigFile::CVar
&quad_grid_cell_size
= parameter
.getVar ("quad_grid_cell_size");
351 lighterDesc
.GridCellSize
=quad_grid_cell_size
.asFloat();
353 // Heightfield cell size
354 CConfigFile::CVar
&global_illumination_cell_size
= parameter
.getVar ("global_illumination_cell_size");
355 lighterDesc
.HeightfieldCellSize
=global_illumination_cell_size
.asFloat();
358 CConfigFile::CVar
&global_illumination_length
= parameter
.getVar ("global_illumination_length");
359 lighterDesc
.HeightfieldSize
=global_illumination_length
.asFloat();
362 CConfigFile::CVar
&sun_direction
= parameter
.getVar ("sun_direction");
363 lighterDesc
.SunDirection
.x
=sun_direction
.asFloat(0);
364 lighterDesc
.SunDirection
.y
=sun_direction
.asFloat(1);
365 lighterDesc
.SunDirection
.z
=sun_direction
.asFloat(2);
366 lighterDesc
.SunDirection
.normalize ();
368 // Light center position
369 CConfigFile::CVar
&sun_center
= parameter
.getVar ("sun_center");
370 lighterDesc
.SunCenter
.x
=sun_center
.asFloat(0);
371 lighterDesc
.SunCenter
.y
=sun_center
.asFloat(1);
372 lighterDesc
.SunCenter
.z
=sun_center
.asFloat(2);
375 CConfigFile::CVar
&sun_distance
= parameter
.getVar ("sun_distance");
376 lighterDesc
.SunDistance
=sun_distance
.asFloat();
379 CConfigFile::CVar
&sun_fov
= parameter
.getVar ("sun_fov");
380 lighterDesc
.SunFOV
=sun_fov
.asFloat();
383 CConfigFile::CVar
&sun_radius
= parameter
.getVar ("sun_radius");
384 lighterDesc
.SunRadius
=sun_radius
.asFloat();
386 // ZBuffer landscape size
387 CConfigFile::CVar
&zbuffer_landscape_size
= parameter
.getVar ("zbuffer_landscape_size");
388 lighterDesc
.ZBufferLandscapeSize
=zbuffer_landscape_size
.asInt();
390 // ZBuffer object size
391 CConfigFile::CVar
&zbuffer_object_size
= parameter
.getVar ("zbuffer_object_size");
392 lighterDesc
.ZBufferObjectSize
=zbuffer_object_size
.asInt();
394 // Soft shadow samples sqrt
395 CConfigFile::CVar
&soft_shadow_samples_sqrt
= parameter
.getVar ("soft_shadow_samples_sqrt");
396 lighterDesc
.SoftShadowSamplesSqrt
=soft_shadow_samples_sqrt
.asInt();
398 // Soft shadow jitter
399 CConfigFile::CVar
&soft_shadow_jitter
= parameter
.getVar ("soft_shadow_jitter");
400 lighterDesc
.SoftShadowJitter
=soft_shadow_jitter
.asFloat();
402 // Water rendering parameters
403 CConfigFile::CVar
&water_zbias
= parameter
.getVar ("water_shadow_bias");
404 lighterDesc
.WaterShadowBias
= water_zbias
.asFloat();
406 CConfigFile::CVar
&water_ambient
= parameter
.getVar ("water_ambient");
407 lighterDesc
.WaterAmbient
= water_ambient
.asFloat();
409 CConfigFile::CVar
&water_diffuse
= parameter
.getVar ("water_diffuse");
410 lighterDesc
.WaterDiffuse
= water_diffuse
.asFloat();
412 CConfigFile::CVar
&modulate_water_color
= parameter
.getVar ("modulate_water_color");
413 lighterDesc
.ModulateWaterColor
= modulate_water_color
.asInt() != 0;
415 CConfigFile::CVar
&sky_contribution_for_water
= parameter
.getVar ("sky_contribution_for_water");
416 lighterDesc
.SkyContributionForWater
= sky_contribution_for_water
.asInt() != 0;
419 CConfigFile::CVar
&cpu_num
= parameter
.getVar ("cpu_num");
420 lighterDesc
.NumCPU
=cpu_num
.asInt ();
423 CConfigFile::CVar
&sun_contribution
= parameter
.getVar ("sun_contribution");
424 lighterDesc
.SunContribution
=sun_contribution
.asInt ()!=0;
427 CConfigFile::CVar
&shadow
= parameter
.getVar ("shadow");
428 lighterDesc
.Shadow
=shadow
.asInt ()!=0;
431 CConfigFile::CVar
&sky_contribution
= parameter
.getVar ("sky_contribution");
432 lighterDesc
.SkyContribution
=sky_contribution
.asInt ()!=0;
435 CConfigFile::CVar
&sky_intensity
= parameter
.getVar ("sky_intensity");
436 lighterDesc
.SkyIntensity
=sky_intensity
.asFloat ();
439 CConfigFile::CVar
&vegetable_height
= parameter
.getVar ("vegetable_height");
440 lighterDesc
.VegetableHeight
=vegetable_height
.asFloat ();
443 // Shadow are enabled ?
444 if (lighterDesc
.Shadow
)
446 // Load and parse the dependency file
447 dependency
.load (argv
[4]);
450 // Get the search pathes
451 CConfigFile::CVar
&search_pathes
= parameter
.getVar ("search_pathes");
453 for (path
= 0; path
< (uint
)search_pathes
.size(); path
++)
455 // Add to search path
456 CPath::addSearchPath (search_pathes
.asString(path
));
459 // A landscape allocated with new: it is not delete because destruction take 3 secondes more!
460 CLandscape
*landscape
=new CLandscape
;
464 CMyZoneLighter lighter
;
467 // A vector of zone id
468 vector
<uint
> listZoneId
;
474 std::list
<CInstanceGroupRef
> instanceGroup
;
477 zone
.serial (inputFile
);
480 bool zoneIgLoaded
= false;
482 // Load ig of the zone
483 string igName
= getName (argv
[1])+".ig";
484 string igNameLookup
= CPath::lookup (igName
, false, false);
485 if (!igNameLookup
.empty())
486 igName
= igNameLookup
;
488 if (inputFile
.open (igName
))
491 CInstanceGroup
*group
=new CInstanceGroup
;
494 group
->serial (inputFile
);
498 CInstanceGroupRef iref
;
500 iref
.AddLight
= true;
501 instanceGroup
.push_back (iref
);
507 fprintf (stderr
, "Warning: can't load instance group %s\n", igName
.c_str());
508 zoneIgLoaded
= false;
512 string bankName
= bank_name
.asString();
513 string bankNameLookup
= CPath::lookup (bankName
, false, false);
514 if (!bankNameLookup
.empty())
515 bankName
= bankNameLookup
;
516 if (inputFile
.open (bankName
))
521 landscape
->TileBank
.serial (inputFile
);
522 landscape
->initTileBanks();
524 catch (const Exception
&e
)
527 nlwarning ("ERROR error loading tile bank %s\n%s\n", bankName
.c_str(), e
.what());
533 nlwarning ("ERROR can't load tile bank %s\n", bankName
.c_str());
537 landscape
->addZone (zone
);
538 listZoneId
.push_back (zone
.getZoneId());
540 // Continue to build ?
543 // Try to load additionnal instance group.
545 // Additionnal instance group
546 if (loadInstanceGroup
)
550 for (uint add
=0; add
<(uint
)additionnal_ig
.size(); add
++)
555 // Name of the instance group
556 string name
= additionnal_ig
.asString(add
);
557 string nameLookup
= CPath::lookup (name
, false, false);
558 if (!nameLookup
.empty())
561 // Try to open the file
562 if (inputFile
.open (name
))
565 CInstanceGroup
*group
=new CInstanceGroup
;
568 group
->serial (inputFile
);
572 CInstanceGroupRef iref
;
574 iref
.AddLight
= false;
575 instanceGroup
.push_back (iref
);
580 nlwarning ("ERROR can't load instance group %s\n", name
.c_str());
587 catch (const NLMISC::EUnknownVar
&)
589 nlinfo("No additionnal ig's to load");
593 // *** Scan dependency file
595 if (lighterDesc
.Shadow
)
597 CConfigFile::CVar
&dependant_zones
= dependency
.getVar ("dependencies");
598 std::vector
<std::string
> zoneNameArray
;
599 zoneNameArray
.reserve(1 + (uint
)dependant_zones
.size());
600 zoneNameArray
.push_back(argv
[1]);
602 for (uint i
=0; i
<(uint
)dependant_zones
.size(); i
++)
605 string zoneName
=dependant_zones
.asString(i
);
606 zoneNameArray
.push_back(zoneName
);
610 // Open it for reading
611 if (inputFile
.open (dir
+zoneName
+ext
))
614 zoneBis
.serial (inputFile
);
618 landscape
->addZone (zoneBis
);
619 listZoneId
.push_back (zoneBis
.getZoneId());
623 // Error message and continue
624 nlwarning ("ERROR can't load zone %s\n", (dir
+zoneName
+ext
).c_str());
627 // Try to load an instance group.
628 if (loadInstanceGroup
)
630 string name
= zoneName
+".ig";
631 string nameLookup
= CPath::lookup (name
, false, false);
632 if (!nameLookup
.empty())
635 // Name of the instance group
636 if (inputFile
.open (name
))
639 CInstanceGroup
*group
=new CInstanceGroup
;
642 group
->serial (inputFile
);
646 CInstanceGroupRef iref
;
648 iref
.AddLight
= true;
649 instanceGroup
.push_back (iref
);
653 // Error message and continue
654 nlwarning ("WARNING can't load instance group %s\n", name
.c_str());
659 if (loadInstanceGroup
)
661 // Ryzom specific : additionnal villages from a continent form
662 loadIGFromContinent(parameter
, instanceGroup
, zoneNameArray
, additionnal_ig
);
666 // A vector of CZoneLighter::CTriangle
667 vector
<CZoneLighter::CTriangle
> vectorTriangle
;
670 // *** Build triangle array
673 landscape
->checkBinds ();
675 // Add triangles from landscape
676 landscape
->enableAutomaticLighting (false);
677 // no need to add obstacles in case of water patch
678 if(!tileWaterPatchOnly
)
679 lighter
.addTriangles (*landscape
, listZoneId
, 0, vectorTriangle
);
682 std::map
<string
, IShape
*> shapeMap
;
684 // For each instance group
685 std::list
<CInstanceGroupRef
>::iterator ite
=instanceGroup
.begin();
686 while (ite
!=instanceGroup
.end())
689 CInstanceGroup
*group
=ite
->IG
;
691 // Load and add shapes
692 if (lighterDesc
.Shadow
)
695 for (uint instance
=0; instance
<group
->getNumInstance(); instance
++)
697 // Get the instance shape name
698 string name
=group
->getShapeName (instance
);
701 // Skip it?? use the DontCastShadowForExterior flag. See doc of this flag
702 if(group
->getInstance(instance
).DontCastShadow
|| group
->getInstance(instance
).DontCastShadowForExterior
)
705 if (toLowerAscii (CFile::getExtension (name
)) == "pacs_prim")
707 nlwarning("EXPORT BUG: Can't read %s (not a shape), should not be part of .ig!", name
.c_str());
712 if (toLowerAscii (CFile::getExtension (name
)) == "ps")
715 // Add a .shape at the end ?
716 if (name
.find('.') == std::string::npos
)
720 string nameLookup
= CPath::lookup (name
, false, false);
721 if (!nameLookup
.empty())
724 // Find the shape in the bank
725 std::map
<string
, IShape
*>::iterator iteMap
=shapeMap
.find (name
);
726 if (iteMap
==shapeMap
.end())
731 if (inputFile
.open (name
))
735 stream
.serial (inputFile
);
738 iteMap
=shapeMap
.insert (std::map
<string
, IShape
*>::value_type (name
, stream
.getShapePointer ())).first
;
743 nlwarning ("WARNING can't load shape %s\n", name
.c_str());
748 if (iteMap
!=shapeMap
.end())
753 scale
.scale (group
->getInstanceScale (instance
));
756 rot
.setRot (group
->getInstanceRot (instance
));
759 pos
.setPos (group
->getInstancePos (instance
));
760 CMatrix mt
=pos
*rot
*scale
;
763 // no need to add obstacles in case of water patch
764 if(!tileWaterPatchOnly
)
765 lighter
.addTriangles (*iteMap
->second
, mt
, vectorTriangle
);
767 /** If it is a lightable shape and we are dealing with the ig of the main zone,
768 * add it to the lightable shape list
770 IShape
*shape
= iteMap
->second
;
771 if (ite
== instanceGroup
.begin() /* are we dealing with main zone */
772 && zoneIgLoaded
/* ig of the main zone loaded successfully (so its indeed the ig of the first zone) ? */
773 && CZoneLighter::isLightableShape(*shape
)
774 && !tileWaterPatchOnly
777 lighter
.addLightableShape(shape
, mt
);
780 /** If it is a water shape, add it to the lighter, so that it can check
781 * which tiles are above / below water for this zone. The result is saved in the flags of tiles.
782 * A tile that have their flags set to VegetableDisabled won't get setupped
784 if (dynamic_cast<NL3D::CWaterShape
*>(shape
))
786 lighter
.addWaterShape(static_cast<NL3D::CWaterShape
*>(shape
), mt
);
793 // For each point light of the ig. No need wor tileWaterPatchOnly
794 if (ite
->AddLight
&& !tileWaterPatchOnly
)
796 const std::vector
<CPointLightNamed
> &pointLightList
= group
->getPointLightList();
797 for (uint plId
=0; plId
<pointLightList
.size(); plId
++)
800 lighter
.addStaticPointLight(pointLightList
[plId
]);
804 // Next instance group
808 // If no waterpatch, and no WaterShape at all, no op
809 bool tileWaterSkip
= false;
810 if(continu
&& tileWaterPatchOnly
&& lighter
.getNumWaterShape()==0)
812 nlinfo("NO WATER INTERSECTION FOUND: don't patch at all");
828 if(!tileWaterPatchOnly
)
831 lighter
.light (*landscape
, output
, zone
.getZoneId(), lighterDesc
, vectorTriangle
, listZoneId
);
838 // load the zonel (keep lighting)
839 if (zonelFile
.open (argv
[2]))
845 output
.serial (zonelFile
);
847 catch (const Exception
& except
)
850 nlwarning ("ERROR reading %s: %s\n", argv
[2], except
.what());
856 // Error can't open the file
857 nlwarning ("ERROR Can't open %s for reading\n", argv
[1]);
858 throw Exception("ERROR Can't open the zonel for tile water patching. abort");
865 string bkupFile
= tileWaterPatchBkupDir
+ "/" + CFile::getFilename(argv
[2]);
866 if (outputFile
.open (bkupFile
))
870 output
.serial (outputFile
);
872 catch (const Exception
& except
)
874 nlwarning ("ERROR backuping %s: %s\n", bkupFile
.c_str(), except
.what());
879 nlwarning ("ERROR Can't open %s for writing\n", bkupFile
.c_str());
883 lighter
.computeTileFlagsOnly(*landscape
, output
, zone
.getZoneId(), lighterDesc
, listZoneId
);
890 if (outputFile
.open (argv
[2]))
896 output
.serial (outputFile
);
898 catch (const Exception
& except
)
901 nlwarning ("ERROR writing %s: %s\n", argv
[2], except
.what());
906 // Error can't open the file
907 nlwarning ("ERROR Can't open %s for writing\n", argv
[2]);
911 printf ("\rCompute time: %d ms \r",
912 (uint
)(CTime::getLocalTime ()-time
));
918 nlwarning ("ERROR Abort: files are missing.\n");
921 catch (const Exception
& except
)
924 nlwarning ("ERROR %s\n", except
.what());
929 // Error can't open the file
930 nlwarning ("ERROR Can't open %s for reading\n", argv
[1]);
935 // Landscape is not deleted, nor the instanceGroups, for faster quit.
936 // Must disalbe BlockMemory checks (for pointLights).
937 NL3D_BlockMemoryAssertOnPurge
= false;
940 printf ("\rCompute time: %d ms \n",
941 (uint
)(CTime::getLocalTime ()-time
));