Exemple #1
0
//**********************************************************************************************
void CIGInfo::load(TShapeCache &shapeCache)
{
	if (Loaded) return;
	Loaded = true; // even if loading fails, don't try twice to load it
	try
	{
		CIFile stream;
		stream.open(Path);
		printf(Path.c_str());
		CSmartPtr<CInstanceGroup> ig = new CInstanceGroup;
		ig->serial(stream);
		IG = ig; // commit
	}
	catch(EStream &e)
	{
		nlwarning(e.what());
	}
	if (IG)
	{
		// complete cache
		for(uint k = 0; k < IG->getNumInstance(); ++k)
		{
			std::string shapeName = standardizeShapeName(IG->getShapeName(k));			
			if (NLMISC::strlwr(CFile::getExtension(shapeName)) == "pacs_prim")
			{
				continue;
			}
			TShapeCache::iterator it = shapeCache.find(shapeName);
			CShapeInfo si;			
			bool buildOK = false;
			if (it == shapeCache.end())
			{
				CShapeStream ss;
				try
				{
					
					CIFile stream;
					std::string path = CPath::lookup(shapeName, false, false);
					if (!path.empty())
					{
						stream.open(path);
						ss.serial(stream);
						CShapeInfo si;
						si.build(*ss.getShapePointer());
						delete ss.getShapePointer();
						shapeCache[shapeName].swap(si);						
					}
				}
				catch (EStream &e)
				{
					// shape not loaded
					nlwarning(e.what());
				}
			}			
		}				
	}
}
Exemple #2
0
bool CNelExport::exportSkeleton	(const char *sPath, INode* pNode, TimeValue time)
{
	// Result to return
	bool bRet=false;

	// Build the skeleton format
	CSkeletonShape *skeletonShape=new CSkeletonShape();
	TInodePtrInt mapId;
	_ExportNel->buildSkeletonShape (*skeletonShape, *pNode, NULL, mapId, time);

	// Open a file
	COFile file;
	if (file.open (sPath))
	{
		try
		{
			// Create a streamable shape
			CShapeStream shapeStream (skeletonShape);
			
			// Serial the shape
			shapeStream.serial (file);

			// All is good
			bRet=true;
		}
		catch (Exception &e)
		{
			nlwarning (e.what());
		}
	}

	// Delete the pointer
	delete skeletonShape;

	return bRet;
}
int	main(int argc, char *argv[])
{
	uint	i;

	// Avoid warnings.
	NLMISC::createDebug();
	DebugLog->addNegativeFilter("Exception will be launched");
	WarningLog->addNegativeFilter("Exception will be launched");
	InfoLog->addNegativeFilter("FEHTIMER>");
	InfoLog->addNegativeFilter("adding the path");

	// Init serial
	registerSerial3d();

	if(argc<4)
	{
		puts("Usage:    build_clod_bank  path_file.cfg  config_file.cfg  destfile.clodbank  [bakeFrameRate=20] ");
		return 0;
	}


	try
	{
		// The bank to fill
		CLodCharacterShapeBank	lodShapeBank;


		// Read the frameRate to process bake of anims
		float	bakeFrameRate= 20;
		if(argc>=5)
		{
			bakeFrameRate= (float)atof(argv[4]);
			if(bakeFrameRate<=1)
			{
				nlwarning("bad bakeFrameRate value, use a default of 20");
				bakeFrameRate= 20;
			}
		}


		// parse the path file.
		//==================

		// try to load the config file.
		CConfigFile pathConfig;
		pathConfig.load (argv[1]);

		// Get the search pathes
		CConfigFile::CVar &search_pathes = pathConfig.getVar ("search_pathes");
		for (i = 0; i < (uint)search_pathes.size(); i++)
		{
			// Add to search path
			CPath::addSearchPath (search_pathes.asString(i));
		}

		// parse the config file.
		//==================

		// try to load the config file.
		CConfigFile config;
		config.load (argv[2]);

		// For all .clod to process
		//==================
		CConfigFile::CVar &clod_list = config.getVar ("clod_list");
		uint	lodId;
		for (lodId = 0; lodId < (uint)clod_list.size(); lodId++)
		{
			string	lodName= clod_list.asString(lodId);

			printf("Process LOD: %s\n", lodName.c_str());

			// Search the variable with this name.
			try
			{
				CIFile		iFile;

				// get the anim list.
				CConfigFile::CVar &clod_anim_list = config.getVar (lodName);

				// Correct format?
				if(clod_anim_list.size()<3)
				{
					nlwarning("%s skipped. Must have at least the skeleton file name, the lod file name, and one animation", lodName.c_str());
					// go to next.
					continue;
				}

				// Init lod shape process
				//===========================

				// The first variable is the name of the skeleton.
				string	skeletonName= clod_anim_list.asString(0);
				CSmartPtr<CSkeletonShape>	skeletonShape;

				// Load it.
				iFile.open(CPath::lookup(skeletonName));
				CShapeStream		strShape;
				strShape.serial(iFile);
				iFile.close();

				// Get the pointer, check it's a skeleton
				if(dynamic_cast<CSkeletonShape*>(strShape.getShapePointer()) == NULL)
					throw Exception("%s is not a Skeleton", skeletonName.c_str());
				skeletonShape= (CSkeletonShape*)strShape.getShapePointer();

				// The second var is the filename of the lod.
				string	lodFileName= clod_anim_list.asString(1);

				// Load the shape.
				CLodCharacterShapeBuild		lodShapeBuild;
				iFile.open( CPath::lookup(lodFileName) );
				iFile.serial(lodShapeBuild);
				iFile.close();

				// Prepare to build the lod.
				CLodCharacterBuilder		lodBuilder;
				lodBuilder.setShape(lodName, skeletonShape, &lodShapeBuild);


				// Traverse all anim in the list.
				//===========================
				uint	animId;
				for (animId = 2; animId < (uint)clod_anim_list.size(); animId++)
				{
					string	animFileName= clod_anim_list.asString(animId);

					// display.
					printf("Process Anim: %d/%d\r", animId-1, clod_anim_list.size()-2);

					// Try to load the animation
					CAnimation			*anim= new CAnimation;
					// NB: continue, to list all ANIM if anim not found
					try
					{
						iFile.open( CPath::lookup(animFileName) );
						iFile.serial(*anim);
						iFile.close();
						// Add to the builder. NB: animation will be delete in this method.
						// NB: the key name here is the entire file, with the .anim, for easier georges editing.
						lodBuilder.addAnim(animFileName.c_str(), anim, bakeFrameRate);
					}
					catch(EPathNotFound &)
					{
						printf("ERROR anim not found %s\n", animFileName.c_str());
						delete	anim;
					}
				}
				printf("\n");

				// Add to the bank.
				//===========================
				uint32	shapeId= lodShapeBank.addShape();
				*lodShapeBank.getShapeFullAcces(shapeId)= lodBuilder.getLodShape();
			}
			catch(EUnknownVar &evar)
			{
				nlwarning(evar.what());
				// Any other exception will make the program quit.
			}

		}

		// Save bank.
		//===========================

		// compile
		lodShapeBank.compile();

		// Save
		COFile	oFile(argv[3]);
		oFile.serial(lodShapeBank);
		oFile.close();
	}
	catch (Exception& except)
	{
		// Error message
		printf ("ERROR %s.\n Aborting.\n", except.what());
	}


	return 0;
}
Exemple #4
0
int main(int argc, char **argv)
{
	// Filter addSearchPath
	NLMISC::createDebug();
	InfoLog->addNegativeFilter("adding the path");

	createDebug();

	try
	{
		// Init
		init();

		uint	i, j, k;

		for (i=0; i<IGs.size(); ++i)
		{
			// load ig associated to the zone
			string			igName = IGs[i]+".ig";
			CIFile			igStream(CPath::lookup(igName));
			CInstanceGroup	ig;
			igStream.serial(ig);

			CAABBox			igBBox;
			bool			boxSet = false;

			nlinfo("Generating BBOX for %s", igName.c_str());

			// search in group for water instance
			for (j=0; j<ig._InstancesInfos.size(); ++j)
			{
				/*
				   Ben: c'est degueulasse, mais c'est les coders a la 3D, y savent pas coder
				   Hld: ouai, mais ca marche pas ton truc, alors p'tet qu'on sait pas coder mais toi non plus :p Special Dedicace to SupaGreg!
				string	shapeName = ig._InstancesInfos[j].Name+".shape";
				*/
				string	shapeName = ig._InstancesInfos[j].Name;
				if (CFile::getExtension (shapeName) == "")
					shapeName += ".shape";

				if (NonWaterShapes.find(shapeName) != NonWaterShapes.end())
					continue;

				string	shapeNameLookup = CPath::lookup (shapeName, false, false);
				if (!shapeNameLookup.empty())
				{
					CIFile			f;
					if (f.open (shapeNameLookup))
					{
						CShapeStream	shape;
						shape.serial(f);

						CWaterShape	*wshape = dynamic_cast<CWaterShape *>(shape.getShapePointer());
						if (wshape == NULL)
						{
							NonWaterShapes.insert(shapeName);
							continue;
						}

						CMatrix	matrix;
						ig.getInstanceMatrix(j, matrix);

						CPolygon			wpoly;
						wshape->getShapeInWorldSpace(wpoly);

						for (k=0; k<wpoly.Vertices.size(); ++k)
						{
							if (boxSet)
							{
								igBBox.extend(matrix * wpoly.Vertices[k]);
							}
							else
							{
								igBBox.setCenter(matrix * wpoly.Vertices[k]);
								boxSet = true;
							}
						}
					}
					else
					{
						nlwarning ("Can't load shape %s", shapeNameLookup.c_str());
					}
				}
				else
				{
					NonWaterShapes.insert(shapeName);
				}
			}

			if (boxSet)
			{
				Boxes.push_back(CIGBox(igName, igBBox));
				nlinfo("Bbox: (%.1f,%.1f)-(%.1f,%.1f)", igBBox.getMin().x, igBBox.getMin().y, igBBox.getMax().x, igBBox.getMax().y);
			}
		}

		COFile	output(Output);
		output.serialCont(Boxes);
	}
	catch (Exception &e)
	{
		fprintf (stderr,"main trapped an exception: '%s'\n", e.what ());
	}
#ifndef NL_DEBUG
	catch (...)
	{
		fprintf(stderr,"main trapped an unknown exception\n");
	}
#endif // NL_DEBUG

	return 0;
}
// ***************************************************************************
void	CIgLighterLib::lightIg(CInstanceLighter &instanceLighter,
	const CInstanceGroup &igIn, CInstanceGroup &igOut, CInstanceLighter::CLightDesc &lightDesc, 
	CSurfaceLightingInfo &slInfo, const char *igName)
{
	sint				i;


	// Setup.
	//=======
	// Init
	instanceLighter.init();

	// For interiors ig, disable Sun contrib according to ig.
	lightDesc.DisableSunContribution= !igIn.getRealTimeSunContribution();
	// Copy it to igOut, just to keep same setup data for in and out.
	igOut.enableRealTimeSunContribution(!lightDesc.DisableSunContribution);


	// Add obstacles.
	std::vector<CInstanceLighter::CTriangle>	obstacles;
	// only if Shadowing On.
	if(lightDesc.Shadow)
	{
		// Map of shape to load
		std::map<string, IShape*> shapeMap;

		// For all instances of igIn.
		for(i=0; i<(sint)igIn.getNumInstance();i++)
		{
			// progress
			instanceLighter.progress("Loading Shapes obstacles", float(i)/igIn.getNumInstance());

			// Skip it?? IgLighterLib use the DontCastShadowForInterior flag. See doc of this flag
			if(igIn.getInstance(i).DontCastShadow || igIn.getInstance(i).DontCastShadowForInterior)
				continue;

			// Get the instance shape name
			string name= igIn.getShapeName(i);
			bool	shapeFound= true;

			// Try to find the shape in the UseShapeMap.
			std::map<string, IShape*>::const_iterator iteMap= lightDesc.UserShapeMap.find (name);

			// If not found in userShape map, try to load it from the temp loaded ShapeBank.
			if( iteMap == lightDesc.UserShapeMap.end() )
			{
				// Add a .shape at the end ?
				if (name.find('.') == std::string::npos)
					name += ".shape";

				// Lookup the file
				string nameLookup = CPath::lookup (name, false, false);
				if (!nameLookup.empty())
					name = nameLookup;

				// Find the shape in the bank
				iteMap= shapeMap.find (name);
				if (iteMap==shapeMap.end())
				{
					// Input file
					CIFile inputFile;

					if (inputFile.open (name))
					{
						// Load it
						CShapeStream stream;
						stream.serial (inputFile);

						// Get the pointer
						iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
					}
					else
					{
						// Error
						nlwarning ("WARNING can't load shape %s\n", name.c_str());
						shapeFound= false;
					}
				}
			}

			if(shapeFound)
			{
				CMatrix		matInst;
				matInst.setPos(igIn.getInstancePos(i));
				matInst.setRot(igIn.getInstanceRot(i));
				matInst.scale(igIn.getInstanceScale(i));
				// Add triangles of this shape
				CInstanceLighter::addTriangles(*iteMap->second, matInst, obstacles, i);
			}

		}

		// Clean Up shapes.
		//-----------
		std::map<string, IShape*>::iterator iteMap;
		iteMap= shapeMap.begin();
		while(iteMap!= shapeMap.end())
		{
			// delte shape
			delete	iteMap->second;
			// delete entry in map
			shapeMap.erase(iteMap);
			// next
			iteMap= shapeMap.begin();
		}
	}

	// Add pointLights of the IG.
	for(i=0; i<(sint)igIn.getPointLightList().size();i++)
	{
		instanceLighter.addStaticPointLight( igIn.getPointLightList()[i], igName );
	}


	// Setup a CIGSurfaceLightBuild if needed.
	//=======
	CIGSurfaceLightBuild	*igSurfaceLightBuild= NULL;
	CGlobalRetriever		*globalRetriever= slInfo.GlobalRetriever;
	CRetrieverBank			*retrieverBank= slInfo.RetrieverBank;
	float	cellSurfaceLightSize= slInfo.CellSurfaceLightSize;
	if(retrieverBank && globalRetriever)
	{
		igSurfaceLightBuild= new CIGSurfaceLightBuild;
		igSurfaceLightBuild->CellSize= cellSurfaceLightSize;
		// col Identifier.
		string	colIdent= slInfo.ColIdentifierPrefix + slInfo.IgFileName + slInfo.ColIdentifierSuffix;

		// For any retreiverInstance with this identifier.
		//----------------
		uint	numInstances= (uint)globalRetriever->getInstances().size();
		for(uint instanceId=0; instanceId<numInstances; instanceId++)
		{
			const CRetrieverInstance	&instance= globalRetriever->getInstance(instanceId);
			// If this instance is an interior
			if ( instance.getType() == CLocalRetriever::Interior )
			{
				uint					localRetrieverId= instance.getRetrieverId();
				const CLocalRetriever	&localRetriever= retrieverBank->getRetriever(localRetrieverId);
				// get the identifer of this localRetriever
				string	retIdent= localRetriever.getIdentifier();

				// Match the ident??
				if( retIdent.find(colIdent)!=string::npos )
				{
					// check CRetrieverLightGrid not already present
					CIGSurfaceLightBuild::ItRetrieverGridMap	itRgm;
					itRgm= igSurfaceLightBuild->RetrieverGridMap.find(localRetrieverId);
					if( itRgm != igSurfaceLightBuild->RetrieverGridMap.end() )
					{
						nlwarning ("ERROR Found 2 different collision retriever with same identifier: '%s'. The 2nd is discared\n", retIdent.c_str());
					}
					else
					{
						// Append CRetrieverLightGrid.
						itRgm= igSurfaceLightBuild->RetrieverGridMap.insert(
							make_pair(localRetrieverId, CIGSurfaceLightBuild::CRetrieverLightGrid() ) ).first;
						CIGSurfaceLightBuild::CRetrieverLightGrid	&rlg= itRgm->second;

						// Resize Grids.
						uint	numSurfaces= (uint)localRetriever.getSurfaces().size();
						rlg.Grids.resize( numSurfaces );

						// Compute the bbox for all surfaces. (NB: local to the localRetriever).
						vector<CAABBox>		surfaceBBoxes;
						localRetriever.buildInteriorSurfaceBBoxes(surfaceBBoxes);

						// For each surface, compute it.
						for(uint surfaceId=0; surfaceId<numSurfaces; surfaceId++)
						{
							// Progress.
							char	stmp[256];
							sprintf(stmp, "Sample surfaces of %s", retIdent.c_str());
							instanceLighter.progress(stmp, surfaceId / float(numSurfaces));

							// Compute surface and size of the grid.
							CIGSurfaceLightBuild::CSurface		&surfDst= rlg.Grids[surfaceId];

							// Snap Origin on cellSize
							surfDst.Origin= surfaceBBoxes[surfaceId].getMin();
							surfDst.Origin.x= floorf(surfDst.Origin.x/cellSurfaceLightSize) * cellSurfaceLightSize;
							surfDst.Origin.y= floorf(surfDst.Origin.y/cellSurfaceLightSize) * cellSurfaceLightSize;

							// Snap Width / Height on cellSize.
							float	sizex= surfaceBBoxes[surfaceId].getMax().x - surfDst.Origin.x;
							float	sizey= surfaceBBoxes[surfaceId].getMax().y - surfDst.Origin.y;
							surfDst.Width= (uint)floorf(sizex/cellSurfaceLightSize) + 2;
							surfDst.Height= (uint)floorf(sizey/cellSurfaceLightSize) + 2;
							// Get Zcenter.
							float	zCenter= surfaceBBoxes[surfaceId].getCenter().z;

							// Allocate elements.
							surfDst.Cells.resize(surfDst.Width * surfDst.Height);

							// For all elements
							for(sint yCell=0; yCell<(sint)surfDst.Height; yCell++)
							{
								for(sint xCell=0; xCell<(sint)surfDst.Width; xCell++)
								{
									// compute pos of the cell.
									ULocalPosition	localPos;
									localPos.Estimation.x= surfDst.Origin.x + xCell*cellSurfaceLightSize;
									localPos.Estimation.y= surfDst.Origin.y + yCell*cellSurfaceLightSize;
									localPos.Estimation.z= zCenter;

									// snap the pos to the surface.
									localPos.Surface= surfaceId;
									bool	snapped;
									localRetriever.snapToInteriorGround(localPos, snapped);

									// if snapped then this point is IN the surface.
									CIGSurfaceLightBuild::CCellCorner	&cell= 
										surfDst.Cells[yCell * surfDst.Width + xCell];
									cell.InSurface= snapped;

									// If ok, retrieve the global (ie world) position
									if(snapped)
									{
										// build a valid globalPosition.
										UGlobalPosition	globalPos;
										globalPos.InstanceId= instanceId;
										globalPos.LocalPosition= localPos;
										// retrieve from globalRetriever.
										cell.CenterPos= globalRetriever->getGlobalPosition(globalPos);
										// Add a delta to simulate entity center
										cell.CenterPos.z+= slInfo.CellRaytraceDeltaZ;

										// OverSample
										if(lightDesc.OverSampling==0)
										{
											// No OverSample, just add CenterPos to the samples.
											cell.NumOverSamples= 1;
											cell.OverSamples[0]= cell.CenterPos;
										}
										else
										{
											// OverSample.
											overSampleCell(cell, lightDesc.OverSampling, localRetriever, 
												*globalRetriever, instanceId, localPos, cellSurfaceLightSize, 
												slInfo.CellRaytraceDeltaZ);
											// it is possible that no samples lies in surfaces (small surface).
											// In this case, just copy CenterPos into samples.
											if(cell.NumOverSamples==0)
											{
												cell.NumOverSamples= 1;
												cell.OverSamples[0]= cell.CenterPos;
											}
										}
									}
									else
									{
										// For debug mesh only, get an approximate pos.
										cell.CenterPos= localPos.Estimation + instance.getOrigin();
										cell.CenterPos.z+= slInfo.CellRaytraceDeltaZ;
									}

									// Init cell defaults
									cell.Dilated= false;
									cell.SunContribution= 0;
								}
							}
						}
					}
				}
			}
		}

	}


	// Run.
	//=======
	instanceLighter.light(igIn, igOut, lightDesc, obstacles, NULL, igSurfaceLightBuild);

	// Output a debug mesh??
	if(igSurfaceLightBuild && slInfo.BuildDebugSurfaceShape && !igSurfaceLightBuild->RetrieverGridMap.empty() )
	{
		// Do it for the sun and point lights.
		for(uint i=0;i<2;i++)
		{
			// compute
			CMesh::CMeshBuild			meshBuild;
			CMeshBase::CMeshBaseBuild	meshBaseBuild;
			CVector	deltaPos= CVector::Null;
			deltaPos.z= - slInfo.CellRaytraceDeltaZ + 0.1f;
			// What kind of debug?
			if( i==0 )
				igSurfaceLightBuild->buildSunDebugMesh(meshBuild, meshBaseBuild, deltaPos);
			else
				igSurfaceLightBuild->buildPLDebugMesh(meshBuild, meshBaseBuild, deltaPos, igOut);

			// build
			CMesh	mesh;
			mesh.build(meshBaseBuild, meshBuild);

			// Save.
			CShapeStream	shapeStream;
			shapeStream.setShapePointer(&mesh);
			COFile		file;
			if( i==0 )
				file.open(slInfo.DebugSunName);
			else
				file.open(slInfo.DebugPLName);
			shapeStream.serial(file);
		}
	}


	// Clean.
	//=======
	if(igSurfaceLightBuild)
		delete igSurfaceLightBuild;
}
Exemple #6
0
// ---------------------------------------------------------------------------
// main
// ---------------------------------------------------------------------------
int main(int nNbArg, char **ppArgs)
{
	
	if (nNbArg <3 || nNbArg >5)
	{
		outString ("ERROR : Wrong number of arguments\n");
		outString ("USAGE : lightmap_optimizer <path_lightmaps> <path_shapes> [path_tags] [path_flag8bit]\n");
		return -1;
	}
	
	vector<string> AllShapeNames;
	vector<CMeshBase*> AllShapes;
	std::vector<std::string> tags;	
	char sLMPDir[MAX_PATH];
	char sSHPDir[MAX_PATH];

	
	GetCurrentDirectory (MAX_PATH, sExeDir);

	
	// Get absolute directory for lightmaps
	if (!SetCurrentDirectory(ppArgs[1]))
	{
		outString (string("ERROR : directory ") + ppArgs[1] + " do not exists\n");
		return -1;
	}
	GetCurrentDirectory (MAX_PATH, sLMPDir);
	SetCurrentDirectory (sExeDir);
	// Get absolute directory for shapes
	if (!SetCurrentDirectory(ppArgs[2]))
	{
		outString (string("ERROR : directory ") + ppArgs[2] + " do not exists\n");
		return -1;
	}
	GetCurrentDirectory (MAX_PATH, sSHPDir);
	dir ("*.shape", AllShapeNames, false);
	registerSerial3d ();
	for (uint32 nShp = 0; nShp < AllShapeNames.size(); ++nShp)
	{
		try
		{
			CShapeStream mesh;
			NLMISC::CIFile meshfile (AllShapeNames[nShp]);
			meshfile.serial( mesh );
			meshfile.close();

			// Add the shape to the map.
			CMeshBase *pMB = dynamic_cast<CMeshBase*>(mesh.getShapePointer());
			AllShapes.push_back (pMB);
		}
		catch (NLMISC::EPathNotFound &e)
		{
			outString(string("ERROR: shape not found ")+AllShapeNames[nShp]+" - "+e.what());
			return -1;
		}
	}

	if (nNbArg > 3 && ppArgs[3] && strlen(ppArgs[3]) > 0)
	{
		SetCurrentDirectory (sExeDir);
		if (!SetCurrentDirectory(ppArgs[3]))
		{
			outString (string("ERROR : directory ") + ppArgs[3] + " do not exists\n");
			return -1;
		}
		dir ("*.tag", tags, false);
		for(uint k = 0; k < tags.size(); ++k)
		{
			std::string::size_type pos = tags[k].find('.');
			if (pos != std::string::npos)
			{
				tags[k] = tags[k].substr(0, pos);
			}
		}
	}


	// **** Parse all mesh loaded, to flag each lightmap if 8 bit or not (NB: all layers should be same mode)
	std::set<string>	setLM8Bit;
	for(uint i=0;i<AllShapes.size();i++)
	{
		CMeshBase *pMB= AllShapes[i];
		if(!pMB)
			continue;

		uint32		nbMat= pMB->getNbMaterial();
		for (uint32 m = 0; m < nbMat; ++m)
		{
			CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
			if (rMat.getShader() == CMaterial::LightMap)
			{
				// Begin with stage 0
				uint8 stage = 0;
				while (rMat.getLightMap(stage) != NULL)
				{
					ITexture *pIT = rMat.getLightMap (stage);
					CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
					if (pTF != NULL)
					{
						string sTexName = NLMISC::strlwr(pTF->getFileName());
						if(pTF->getUploadFormat()==ITexture::Luminance)
							setLM8Bit.insert(sTexName);
					}
					++stage;
				}
			}
		}
	}


	// **** Parse all lightmaps, sorted by layer, and 8 or 16 bit mode
	SetCurrentDirectory (sExeDir);
	for (uint32 lmc8bitMode = 0; lmc8bitMode < 2; ++lmc8bitMode)
	for (uint32 nNbLayer = 0; nNbLayer < 256; ++nNbLayer)
	{
		// Get all lightmaps with same number of layer == nNbLayer
		// merge lightmaps only if they are in same mode (8bits or 16 bits)

		vector<string> AllLightmapNames;
		vector<sint>   AllLightmapTags;
		vector<NLMISC::CBitmap*> AllLightmaps;
		sint32 i, j, k, m, n;
		string sFilter;

		// **** Get All Lightmaps that have this number of layer, and this mode
		sFilter = "*_" + NLMISC::toString(nNbLayer) + ".tga";
		SetCurrentDirectory (sLMPDir);
		dir (sFilter, AllLightmapNames, false);

		// filter by layer
		vector<string>		tmpLMs;
		tmpLMs.reserve(AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			string sTmp2 = getBaseName (AllLightmapNames[i]);
			sTmp2 += NLMISC::toString(nNbLayer+1) + ".tga";
			// if not More layer than expected, ok
			if (!fileExist(sTmp2))
			{	
				tmpLMs.push_back(AllLightmapNames[i]);
			}
		}
		AllLightmapNames= tmpLMs;
	
		// filter by 8bit or not mode.
		tmpLMs.clear();
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			bool	lm8Bit= setLM8Bit.find( NLMISC::strlwr(AllLightmapNames[i]) ) !=setLM8Bit.end();
			// if same mode
			if( lm8Bit == (lmc8bitMode==1) )
			{
				tmpLMs.push_back(AllLightmapNames[i]);
			}
		}
		AllLightmapNames= tmpLMs;

		
		// **** Build tag info
		/*
		for(uint k = 0; k < tags.size(); ++k)
		{
			nlinfo("tag %d = %s", (int) k, tags[k].c_str());
		}
		*/
		AllLightmapTags.resize(AllLightmapNames.size());
		for(uint k = 0; k < AllLightmapNames.size(); ++k)
		{
			nlinfo("k = %d", (int) k);
			AllLightmapTags[k] = -1;
			// search for longest tag that match
			uint bestLength = 0;
			for(uint l = 0; l < tags.size(); ++l)
			{
				if (AllLightmapNames[k].size() > tags[l].size())
				{
					if (tags[l].size() > bestLength)
					{					
						std::string start = AllLightmapNames[k].substr(0, tags[l].size());
						if (NLMISC::nlstricmp(start, tags[l]) == 0)
						{
							bestLength = (uint)tags[l].size();
							// the tag matchs
							AllLightmapTags[k] = l;						
						}
					}
				}
			}						
			if (AllLightmapTags[k] == -1)
			{
				nlinfo(NLMISC::toString("Lightmap %s has no tag", AllLightmapNames[k].c_str()).c_str());
			}
			else
			{			
				nlinfo(NLMISC::toString("Lightmap %s has tag %d : %s", AllLightmapNames[k].c_str(), (int) AllLightmapTags[k], tags[AllLightmapTags[k]].c_str()).c_str());
			}			
		}




		// Check if all layer of the same lightmap has the same size
		if (nNbLayer > 0)
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			string sTmp2;
			sTmp2 = getBaseName (AllLightmapNames[i]) + "0.tga";
			uint32 wRef, hRef;
			try
			{
				NLMISC::CIFile inFile;
				inFile.open(sTmp2);
				CBitmap::loadSize(inFile, wRef, hRef);
			}
			catch (NLMISC::Exception &e)
			{
				outString (string("ERROR :") + e.what());
				return -1;
			}

			bool bFound = false;
			for (k = 1; k <= (sint32)nNbLayer; ++k)
			{
				string sTmp3 = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga";
				uint32 wCur = wRef, hCur = hRef;
				try
				{
					NLMISC::CIFile inFile;
					inFile.open(sTmp3);
					CBitmap::loadSize(inFile, wCur, hCur);
				}
				catch (NLMISC::Exception &)
				{
				}

				if ((wCur != wRef) || (hCur != hRef))
				{
					bFound = true;
					break;
				}
			}
			// Should delete all layers of this lightmap (in fact in lightmapnames list we have
			// only the name of the current layer)
			if (bFound)
			{
				sTmp2 = getBaseName (AllLightmapNames[i]);
				outString(string("ERROR: lightmaps ")+sTmp2+"*.tga not all the same size\n");
				for (k = 0; k < (sint32)AllLightmapNames.size(); ++k)
				{
					if (strnicmp(AllLightmapNames[k].c_str(), sTmp2.c_str(), sTmp2.size()) == 0)
					{
						for (j = k+1; j < (sint32)AllLightmapNames.size(); ++j)
						{
							AllLightmapNames[j-1] = AllLightmapNames[j];
							AllLightmapTags[j - 1] = AllLightmapTags[j];
						}
						AllLightmapNames.resize (AllLightmapNames.size()-1);
						AllLightmapTags.resize(AllLightmapTags.size()  - 1);
						k = -1;
						i = -1;
					}
				}
			}
		}
		
		if (AllLightmapNames.size() == 0)
			continue;
		
		// Load all the lightmaps
		AllLightmaps.resize (AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmaps.size(); ++i)
		{
			try
			{
				NLMISC::CBitmap *pBtmp = new NLMISC::CBitmap;
				NLMISC::CIFile inFile;
				inFile.open(AllLightmapNames[i]);
				pBtmp->load(inFile);
				AllLightmaps[i] = pBtmp;
			}
			catch (NLMISC::Exception &e)
			{
				outString (string("ERROR :") + e.what());
				return -1;
			}
		}

		// Sort all lightmaps by decreasing size
		for (i = 0; i < (sint32)(AllLightmaps.size()-1); ++i)
		for (j = i+1; j < (sint32)AllLightmaps.size(); ++j)
		{
			NLMISC::CBitmap *pBI = AllLightmaps[i];
			NLMISC::CBitmap *pBJ = AllLightmaps[j];
			if ((pBI->getWidth()*pBI->getHeight()) < (pBJ->getWidth()*pBJ->getHeight()))
			{
				NLMISC::CBitmap *pBTmp = AllLightmaps[i];
				AllLightmaps[i] = AllLightmaps[j];
				AllLightmaps[j] = pBTmp;

				string sTmp = AllLightmapNames[i];
				AllLightmapNames[i] = AllLightmapNames[j];
				AllLightmapNames[j] = sTmp;

				sint tagTmp = AllLightmapTags[i];
				AllLightmapTags[i] = AllLightmapTags[j];
				AllLightmapTags[j] = tagTmp;
			}
		}
		nlassert(AllLightmapTags.size() == AllLightmapNames.size());
		for (i = 0; i < (sint32)AllLightmapNames.size(); ++i)
		{
			outString(NLMISC::toString("%d / %d\n", (int) i, (int) AllLightmapNames.size()));
			bool bAssigned = false;
			for (j = 0; j < i; ++j)
			{				
				// Tags of both textures must match. We don't want to spread lightmap chunk in bitmap whose other part aren't used by current ig lightmaps (this wastes vram for nothing)
				if (AllLightmapTags[i] != AllLightmapTags[j]) continue;

				// Try to place the texture i into the texture j
				// This can be done only if texture was exported from the same zone. To ensure that, check 
				NLMISC::CBitmap *pBI = AllLightmaps[i];
				NLMISC::CBitmap *pBJ = AllLightmaps[j];
				sint32 x, y;
				if (tryAllPos (pBI, pBJ, x, y))
				{
					bAssigned = true;

					if (!putIn (pBI, pBJ, x, y))
					{
						outString (string("ERROR : cannot put reference lightmap ")+AllLightmapNames[i]+
									" in "+AllLightmapNames[j]);
						return -1;
					}
					// Put texture i into texture j for all layers of the lightmap !
					for (k = 0; k <= (sint32)nNbLayer; ++k)
					{
						string sTexNameI = getBaseName (AllLightmapNames[i]) + NLMISC::toString(k) + ".tga";
						string sTexNameJ = getBaseName (AllLightmapNames[j]) + NLMISC::toString(k) + ".tga";
						NLMISC::CBitmap BitmapI;
						NLMISC::CBitmap BitmapJ;
						NLMISC::CIFile inFile;

						outString (NLMISC::toString("INFO : Transfering %s (tag = %d) in %s (tag = %d)", 
													sTexNameI.c_str(), (int) AllLightmapTags[i],
													sTexNameJ.c_str(), (int) AllLightmapTags[j]) +
													" at ("+NLMISC::toString(x)+","+NLMISC::toString(y)+")\n");

						try
						{
							inFile.open (sTexNameI);
							BitmapI.load (inFile);
							inFile.close ();
							inFile.open (sTexNameJ);
							BitmapJ.load (inFile);
							inFile.close ();
						}
						catch (NLMISC::Exception &e)
						{
							outString (string("ERROR :") + e.what());
							return -1;
						}
						
						if (!putIn (&BitmapI, &BitmapJ, x, y))
						{
							outString (string("ERROR : cannot put lightmap ")+sTexNameI+" in "+sTexNameJ+"\n");
							return -1;
						}

						// Delete File
						DeleteFile (sTexNameI.c_str());
						outString (string("INFO : Deleting file ")+sTexNameI+"\n");

						// Save destination image
						NLMISC::COFile outFile;
						outFile.open (sTexNameJ);
						BitmapJ.writeTGA (outFile, 32);
						outString (string("INFO : Saving file ")+sTexNameJ+"\n");
					}

					// Change shapes uvs related and names to the lightmap
					// ---------------------------------------------------

					SetCurrentDirectory (sSHPDir);

					for (k = 0; k < (sint32)AllShapes.size(); ++k)
					{
						CMeshBase *pMB = AllShapes[k];
						if (!pMB)
							continue;

						uint nNbMat = pMB->getNbMaterial ();
						vector< vector<bool> > VerticesNeedRemap;
						bool bMustSave = false;
						// Initialize all VerticesNeedRemap
						CMesh *pMesh = dynamic_cast<CMesh*>(pMB);
						CMeshMRM *pMeshMRM = dynamic_cast<CMeshMRM*>(pMB);
						CMeshMultiLod *pMeshML = dynamic_cast<CMeshMultiLod*>(pMB);

						if (pMesh != NULL)
						{
							VerticesNeedRemap.resize(1); // Only one meshgeom
							vector<bool> &rVNR = VerticesNeedRemap[0];
							rVNR.resize (pMesh->getMeshGeom().getVertexBuffer().getNumVertices(), false);
						}
						else if (pMeshMRM != NULL)
						{
							VerticesNeedRemap.resize(1); // Only one meshmrmgeom
							vector<bool> &rVNR = VerticesNeedRemap[0];
							rVNR.resize (pMeshMRM->getMeshGeom().getVertexBuffer().getNumVertices(), false);
						}
						else if (pMeshML != NULL)
						{
							sint32 nNumSlot = pMeshML->getNumSlotMesh();
							VerticesNeedRemap.resize(nNumSlot);
							for (m = 0; m < nNumSlot; ++m)
							{
								vector<bool> &rVNR = VerticesNeedRemap[m];
								const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m));
								if (pMG != NULL)
									rVNR.resize (pMG->getVertexBuffer().getNumVertices(), false);
								else
									rVNR.resize(0);
							}
						}
						else continue; // Next mesh
						

						// All materials must have the lightmap names changed
						for (m = 0; m < (sint32)nNbMat; ++m)
						{
							bool bMustRemapUV = false;
							CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
							if (rMat.getShader() == CMaterial::LightMap)
							{
								// Begin with stage 0
								uint8 stage = 0;
								while (rMat.getLightMap(stage) != NULL)
								{
									ITexture *pIT = rMat.getLightMap (stage);
									CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
									if (pTF != NULL)
									{
										string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName()));
										string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i]));
										if (sTexName == sTexNameMoved)
										{
											// We must remap the name and indicate to remap uvs
											bMustRemapUV = true;
											//string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j]));
											//sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga";
											//pTF->setFileName (sNewTexName);
										}
									}
									++stage;
								}
							}
							// We have to remap the uvs of this mesh for this material
							if (bMustRemapUV) // Flaggage of the vertices to remap
							{
								if (pMesh != NULL)
								{
									// Flag all vertices linked to face with material m
									FlagVertices (const_cast<CMeshGeom&>(pMesh->getMeshGeom()), m, VerticesNeedRemap[0]);
								}
								else if (pMeshMRM != NULL)
								{
									FlagVerticesMRM (const_cast<CMeshMRMGeom&>(pMeshMRM->getMeshGeom()), m, VerticesNeedRemap[0]);
								}
								else if (pMeshML != NULL)
								{
									sint32 nNumSlot = pMeshML->getNumSlotMesh();
									for (n = 0; n < nNumSlot; ++n)
									{
										// Get the mesh geom
										CMeshGeom *pMG = const_cast<CMeshGeom*>(dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(n)));
										if (pMG)
										{
											// Flag the vertices
											FlagVertices (*pMG, m, VerticesNeedRemap[n]);
										}
										else
										{
											// Get the mesh MRM geom
											CMeshMRMGeom *pMMRMG = const_cast<CMeshMRMGeom*>(dynamic_cast<const CMeshMRMGeom*>(&pMeshML->getMeshGeom(n)));
											if (pMMRMG)
											{
												// Flag the vertices
												FlagVerticesMRM (*pMMRMG, m, VerticesNeedRemap[n]);
											}
										}
									}
								}
							}
						}

						// Change lightmap names
						for (m = 0; m < (sint32)nNbMat; ++m)
						{
							CMaterial& rMat = const_cast<CMaterial&>(pMB->getMaterial (m));
							if (rMat.getShader() == CMaterial::LightMap)
							{
								// Begin with stage 0
								uint8 stage = 0;
								while (rMat.getLightMap(stage) != NULL)
								{
									ITexture *pIT = rMat.getLightMap (stage);
									CTextureFile *pTF = dynamic_cast<CTextureFile*>(pIT);
									if (pTF != NULL)
									{
										string sTexName = NLMISC::strlwr(getBaseName(pTF->getFileName()));
										string sTexNameMoved = NLMISC::strlwr(getBaseName(AllLightmapNames[i]));
										if (sTexName == sTexNameMoved)
										{
											string sNewTexName = NLMISC::strlwr(getBaseName(AllLightmapNames[j]));
											sNewTexName += NLMISC::toString(getLayerNb(pTF->getFileName())) + ".tga";
											pTF->setFileName (sNewTexName);
										}
									}
									++stage;
								}
							}
						}

						// We have now the list of vertices to remap for all material that have been changed
						// So parse this list and apply the transformation : (uv * TexSizeI + decalXY) / TexSizeJ
						for (m = 0; m < (sint32)VerticesNeedRemap.size(); ++m)
						{
							CVertexBuffer *pVB;							
							if (pMesh != NULL)
							{
								pVB = const_cast<CVertexBuffer*>(&pMesh->getMeshGeom().getVertexBuffer());
							}
							else if (pMeshMRM != NULL)
							{
								pVB = const_cast<CVertexBuffer*>(&pMeshMRM->getMeshGeom().getVertexBuffer());
							}
							else if (pMeshML != NULL)
							{
								const CMeshGeom *pMG = dynamic_cast<const CMeshGeom*>(&pMeshML->getMeshGeom(m));
								pVB = const_cast<CVertexBuffer*>(&pMG->getVertexBuffer());
							}
							CVertexBufferReadWrite vba; 
							pVB->lock (vba);

							vector<bool> &rVNR = VerticesNeedRemap[m];
							for (n = 0; n < (sint32)rVNR.size(); ++n)
							if (rVNR[n])
							{
								CUV *pUV = (CUV*)vba.getTexCoordPointer (n,1);
								pUV->U = (pUV->U*pBI->getWidth() + x) / pBJ->getWidth();
								pUV->V = (pUV->V*pBI->getHeight() + y) / pBJ->getHeight();
								bMustSave = true;
							}
						}

						if (bMustSave)
						{
							try
							{
								if (AllShapes[k])
								{
									CShapeStream mesh;
									mesh.setShapePointer (AllShapes[k]);
									NLMISC::COFile meshfile (AllShapeNames[k]);
									meshfile.serial (mesh);
									meshfile.close ();
								}
							}
							catch (NLMISC::EPathNotFound &e)
							{
								outString(string("ERROR: cannot save shape ")+AllShapeNames[k]+" - "+e.what());
								return -1;
							}
						}
					}

					SetCurrentDirectory (sLMPDir);

					// Get out of the j loop
					break;
				}
			}		
			// if assigned to another bitmap -> delete the bitmap i
			if (bAssigned)
			{
				// Delete Names && tags
				for (j = i+1; j < (sint32)AllLightmapNames.size(); ++j)
				{
					AllLightmapNames[j-1] = AllLightmapNames[j];
					AllLightmapTags[j-1] = AllLightmapTags[j];
				}
				AllLightmapNames.resize (AllLightmapNames.size()-1);
				AllLightmapTags.resize (AllLightmapTags.size()-1);
				// Delete Lightmaps
				delete AllLightmaps[i];
				for (j = i+1; j < (sint32)AllLightmaps.size(); ++j)
					AllLightmaps[j-1] = AllLightmaps[j];
				AllLightmaps.resize (AllLightmaps.size()-1);
				i = i - 1;
			}
		}

	}
	

	// **** Additionally, output or clear a "flag file" in a dir to info if a 8bit lihgtmap or not
	if (nNbArg >=5 && ppArgs[4] && strlen(ppArgs[4]) > 0)
	{
		SetCurrentDirectory (sExeDir);

		// out a text file, with list of
		FILE	*out= fopen(ppArgs[4], "wt");
		if(!out)
		{
			outString(string("ERROR: cannot save ")+ppArgs[4]);
		}

		set<string>::iterator	it(setLM8Bit.begin()), end(setLM8Bit.end());
		for(;it!=end;it++)
		{
			string	temp= (*it);
			temp+= "\n";
			fputs(temp.c_str(), out);
		}

		fclose(out);
	}

	return 0;
}
int main(int argc, char* argv[])
{
	// Filter addSearchPath
	NLMISC::createDebug();
	InfoLog->addNegativeFilter ("adding the path");

	// Register 3d
	registerSerial3d ();

	// Good number of args ?
	if (argc<5)
	{
		// Help message
		printf ("%s [zonein.zonel] [igout.ig] [parameter_file] [dependancy_file]\n", argv[0]);
	}
	else
	{
		// Ok, read the zone
		CIFile inputFile;

		// Get extension
		string ext=getExt (argv[1]);
		string dir=getDir (argv[1]);

		// Open it for reading
		if (inputFile.open (argv[1]))
		{
			// Zone name
			string zoneName=toLower (string ("zone_"+getName (argv[1])));

			// Load the zone
			try
			{
				// Read the config file
				CConfigFile parameter;

				// Load and parse the parameter file
				parameter.load (argv[3]);

				// **********
				// *** Build the lighter descriptor
				// **********

				CInstanceLighter::CLightDesc lighterDesc;

				// Light direction
				CConfigFile::CVar &sun_direction = parameter.getVar ("sun_direction");
				lighterDesc.LightDirection.x=sun_direction.asFloat(0);
				lighterDesc.LightDirection.y=sun_direction.asFloat(1);
				lighterDesc.LightDirection.z=sun_direction.asFloat(2);
				lighterDesc.LightDirection.normalize ();

				// Grid size
				CConfigFile::CVar &quad_grid_size = parameter.getVar ("quad_grid_size");
				lighterDesc.GridSize=quad_grid_size.asInt();

				// Grid size
				CConfigFile::CVar &quad_grid_cell_size = parameter.getVar ("quad_grid_cell_size");
				lighterDesc.GridCellSize=quad_grid_cell_size.asFloat();

				// Shadows enabled ?
				CConfigFile::CVar &shadow = parameter.getVar ("shadow");
				lighterDesc.Shadow=shadow.asInt ()!=0;

				// OverSampling
				CConfigFile::CVar &ig_oversampling = parameter.getVar ("ig_oversampling");
				lighterDesc.OverSampling= ig_oversampling.asInt ();
				// validate value: 0, 2, 4, 8, 16
				lighterDesc.OverSampling= raiseToNextPowerOf2(lighterDesc.OverSampling);
				clamp(lighterDesc.OverSampling, 0U, 16U);
				if(lighterDesc.OverSampling<2)
					lighterDesc.OverSampling= 0;

				// For ig of Zones, never disable Sun contrib !!!
				lighterDesc.DisableSunContribution= false;

				// Get the search pathes
				CConfigFile::CVar &search_pathes = parameter.getVar ("search_pathes");
				uint path;
				for (path = 0; path < (uint)search_pathes.size(); path++)
				{
					// Add to search path
					CPath::addSearchPath (search_pathes.asString(path));
				}

				// A landscape allocated with new: it is not delete because destruction take 3 secondes more!
				CLandscape *landscape=new CLandscape;
				landscape->init();

				// A zone lighter
				CMyIgZoneLighter lighter;
				lighter.init ();

				// A vector of zone id
				vector<uint> listZoneId;

				// The zone
				CZone zone;

				// List of ig
				std::list<CInstanceGroup*> instanceGroup;

				// Load
				zone.serial (inputFile);
				inputFile.close();

				// Load ig of the zone
				string igName = getName (argv[1])+".ig";
				string igNameLookup = CPath::lookup (igName, false, false);
				if (!igNameLookup.empty())
					igName = igNameLookup;

				bool zoneIgLoaded;

				// Try to open the file
				CInstanceGroup *centerInstanceGroup= NULL;
				if (inputFile.open (igName))
				{
					// load the center ig
					centerInstanceGroup=new CInstanceGroup;

					// Serial it
					centerInstanceGroup->serial (inputFile);
					inputFile.close();

					// Add to the list
					instanceGroup.push_back (centerInstanceGroup);
					zoneIgLoaded = true;
				}
				else
				{
					// Warning
					fprintf (stderr, "Warning: can't load instance group %s\n", igName.c_str());
					zoneIgLoaded = false;
				}

				// If can't load the center instanceGroup, skip it.
				if(!zoneIgLoaded)
					return 0;

				// Get bank path
				CConfigFile::CVar &bank_name_var = parameter.getVar ("bank_name");
				string bank_name = bank_name_var.asString ();
				string bank_name_lookup = CPath::lookup (bank_name);
				if (!bank_name_lookup.empty())
					bank_name = bank_name_lookup;

				// Load the bank
				if (inputFile.open (bank_name))
				{
					try
					{
						// Load
						landscape->TileBank.serial (inputFile);
						landscape->initTileBanks();
					}
					catch (const Exception &e)
					{
						// Error
						nlwarning ("ERROR error loading tile bank %s\n%s\n", bank_name.c_str(), e.what());
					}
				}
				else
				{
					// Error
					nlwarning ("ERROR can't load tile bank %s\n", bank_name.c_str());
				}

				// Add the zone
				landscape->addZone (zone);
				listZoneId.push_back (zone.getZoneId());

				// Load instance group ?
				CConfigFile::CVar &load_ig= parameter.getVar ("load_ig");
				bool loadInstanceGroup = load_ig.asInt ()!=0;

				// Continue to build ?
				bool continu=true;

				// Try to load additionnal instance group.
				if (loadInstanceGroup)
				{
					// Additionnal instance group
					try
					{
						CConfigFile::CVar &additionnal_ig = parameter.getVar ("additionnal_ig");									
						for (uint add=0; add<(uint)additionnal_ig.size(); add++)
						{
							// Input file
							CIFile inputFile;

							// Name of the instance group
							string name = additionnal_ig.asString(add);
							string nameLookup = CPath::lookup (name, false, false);
							if (!nameLookup.empty())
								name = nameLookup;

							// Try to open the file
							if (inputFile.open (name))
							{
								// New ig
								CInstanceGroup *group=new CInstanceGroup;

								// Serial it
								group->serial (inputFile);
								inputFile.close();

								// Add to the list
								instanceGroup.push_back (group);
							}
							else
							{
								// Error
								nlwarning ("ERROR can't load instance group %s\n", name.c_str());

								// Stop before build
								continu=false;
							}
						}
					}
					catch (const NLMISC::EUnknownVar &)
					{
						nlinfo("No additionnal ig's to load");
					}
				}
				
				// Shadow ?
				if (lighterDesc.Shadow)
				{
					// Load and parse the dependency file
					CConfigFile dependency;
					dependency.load (argv[4]);

					// *** Scan dependency file
					CConfigFile::CVar &dependant_zones = dependency.getVar ("dependencies");
					for (uint i=0; i<(uint)dependant_zones.size(); i++)
					{
						// Get zone name
						string zoneName=dependant_zones.asString(i);

						// Load the zone
						CZone zoneBis;

						// Open it for reading
						if (inputFile.open (dir+zoneName+ext))
						{
							// Read it
							zoneBis.serial (inputFile);
							inputFile.close();

							// Add the zone
							landscape->addZone (zoneBis);
							listZoneId.push_back (zoneBis.getZoneId());
						}
						else
						{
							// Error message and continue
							nlwarning ("ERROR can't load zone %s\n", (dir+zoneName+ext).c_str());
						}

						// Try to load an instance group.
						if (loadInstanceGroup)
						{
							string name = zoneName+".ig";
							string nameLookup = CPath::lookup (name, false, false);
							if (!nameLookup.empty())
								name = nameLookup;

							// Name of the instance group
							if (inputFile.open (name))
							{
								// New ig
								CInstanceGroup *group=new CInstanceGroup;

								// Serial it
								group->serial (inputFile);
								inputFile.close();

								// Add to the list
								instanceGroup.push_back (group);
							}
							else
							{
								// Error message and continue
								nlwarning ("WARNING can't load instance group %s\n", name.c_str());
							}
						}
					}
				}

				// A vector of CInstanceLighter::CTriangle
				vector<CInstanceLighter::CTriangle> vectorTriangle;

				// **********
				// *** Build triangle array
				// **********

				landscape->checkBinds ();

				// Add triangles from landscape, for pointLight lighting.
				landscape->enableAutomaticLighting (false);
				lighter.addTriangles (*landscape, listZoneId, 0, vectorTriangle);

				// Load and add shapes

				// Map of shape
				std::map<string, IShape*> shapeMap;

				// For each instance group
				std::list<CInstanceGroup*>::iterator ite=instanceGroup.begin();
				while (ite!=instanceGroup.end())
				{
					// Instance group
					CInstanceGroup *group=*ite;

					// For each instance
					for (uint instance=0; instance<group->getNumInstance(); instance++)
					{
						// Get the instance shape name
						string name=group->getShapeName (instance);

						// Skip it?? use the DontCastShadowForExterior flag. See doc of this flag
						if(group->getInstance(instance).DontCastShadow || group->getInstance(instance).DontCastShadowForExterior)
							continue;

						// Add a .shape at the end ?
						if (!name.empty())
						{
							if (name.find('.') == std::string::npos)
								name += ".shape";

							// Find the file
							string nameLookup = CPath::lookup (name, false, false);
							if (!nameLookup.empty())
								name = nameLookup;

							// Find the shape in the bank
							std::map<string, IShape*>::iterator iteMap=shapeMap.find (name);
							if (iteMap==shapeMap.end())
							{
								// Input file
								CIFile inputFile;

								if (inputFile.open (name))
								{
									// Load it
									CShapeStream stream;
									stream.serial (inputFile);

									// Get the pointer
									iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
								}
								else
								{
									// Error
									nlwarning ("WARNING can't load shape %s\n", name.c_str());
								}
							}
							
							// Loaded ?
							if (iteMap!=shapeMap.end())
							{
								// Build the matrix
								CMatrix scale;
								scale.identity ();
								scale.scale (group->getInstanceScale (instance));
								CMatrix rot;
								rot.identity ();
								rot.setRot (group->getInstanceRot (instance));
								CMatrix pos;
								pos.identity ();
								pos.setPos (group->getInstancePos (instance));
								CMatrix mt=pos*rot*scale;

								// If centerInstanceGroup, take good instanceId, to avoid selfShadowing
								sint	instanceId;
								if(group == centerInstanceGroup)
									instanceId= instance;
								else
									instanceId= -1;

								// Add triangles
								lighter.addTriangles (*iteMap->second, mt, vectorTriangle, instanceId);
							}
						}
					}

					// For each point light of the ig
					const std::vector<CPointLightNamed>	&pointLightList= group->getPointLightList();
					for (uint plId=0; plId<pointLightList.size(); plId++)
					{
						// Add it to the Ig.
						lighter.addStaticPointLight(pointLightList[plId], igName.c_str ());
					}

					// Next instance group
					ite++;
				}

				// Continue ?
				if (continu)
				{
					// **********
					// *** Light!
					// **********

					// Start time
					TTime time=CTime::getLocalTime ();

					// Output ig
					CInstanceGroup	output;

					// Light the zone
					lighter.light (*centerInstanceGroup, output, lighterDesc, vectorTriangle, landscape);

					// Compute time
					printf ("\rCompute time: %d ms                                                      \r", 
						(uint)(CTime::getLocalTime ()-time));

					// Save the zone
					COFile outputFile;

					// Open it
					if (outputFile.open (argv[2]))
					{
						try
						{
							// Save the new ig
							outputFile.serial(output);
						}
						catch (const Exception& except)
						{
							// Error message
							nlwarning ("ERROR writing %s: %s\n", argv[2], except.what());
						}
					}
					else
					{
						// Error can't open the file
						nlwarning ("ERROR Can't open %s for writing\n", argv[2]);
					}
				}
				else
				{
					// Error
					nlwarning ("ERROR Abort: files are missing.\n");
				}
			}
			catch (const Exception& except)
			{
				// Error message
				nlwarning ("ERROR %s\n", except.what());
			}
		}
		else
		{
			// Error can't open the file
			nlwarning ("ERROR Can't open %s for reading\n", argv[1]);
		}

	}
	

	// Landscape is not deleted, nor the instanceGroups, for faster quit.
	// Must disalbe BlockMemory checks (for pointLights).
	NL3D_BlockMemoryAssertOnPurge= false;

	// exit.
	return 0;
}
Exemple #8
0
bool CNelExport::exportMesh (const char *sPath, INode& node, TimeValue time)
{
	// Result to return
	bool bRet=false;

	// Eval the object a time
	ObjectState os = node.EvalWorldState(time);

	// Object exist ?
	if (os.obj)
	{
		// Skeleton shape
		CSkeletonShape *skeletonShape=NULL;
		TInodePtrInt *mapIdPtr=NULL;
		TInodePtrInt mapId;

		// If model skinned ?
		if (CExportNel::isSkin (node))
		{
			// Create a skeleton
			INode *skeletonRoot=CExportNel::getSkeletonRootBone (node);

			// Skeleton exist ?
			if (skeletonRoot)
			{
				// Build a skeleton
				skeletonShape=new CSkeletonShape();

				// Add skeleton bind pos info
				CExportNel::mapBoneBindPos boneBindPos;
				CExportNel::addSkeletonBindPos (node, boneBindPos);

				// Build the skeleton based on the bind pos information
				_ExportNel->buildSkeletonShape (*skeletonShape, *skeletonRoot, &boneBindPos, mapId, time);

				// Set the pointer to not NULL
				mapIdPtr=&mapId;

				// Erase the skeleton
				if (skeletonShape)
					delete skeletonShape;
			}
		}

		DWORD t = timeGetTime();
		if (InfoLog)
			InfoLog->display("Beg buildShape %s \n", node.GetName());
		// Export in mesh format
		IShape*	pShape=_ExportNel->buildShape (node, time, mapIdPtr, true);
		if (InfoLog)
			InfoLog->display("End buildShape in %d ms \n", timeGetTime()-t);

		// Conversion success ?
		if (pShape)
		{
			// Open a file
			COFile file;
			if (file.open (sPath))
			{
				try
				{
					// Create a streamable shape
					CShapeStream shapeStream (pShape);
					
					// Serial the shape
					shapeStream.serial (file);

					// All is good
					bRet=true;
				}
				catch (...)
				{
				}
			}

			// Delete the pointer
			delete pShape;
		}
	}
	return bRet;
}
Exemple #9
0
/*
 *		init()
 */
bool	CPrimChecker::build(const string &primitivesPath, const string &igLandPath, const string &igVillagePath, const string &outputDirectory, bool forceRebuild)
{
	if (Verbose)
		nlinfo("Checking pacs.packed_prims consistency");

	NLLIGO::Register();

	// Init ligo
	if (!LigoConfig.readPrimitiveClass ("world_editor_classes.xml", false))
	{
		// Should be in l:\leveldesign\world_edit_files
		nlwarning ("Can't load ligo primitive config file world_editor_classes.xml");
		return false;
	}

	uint	i, j;
	string	outputfname = CPath::standardizePath(outputDirectory)+"pacs.packed_prims";

	_Grid.clear();

	vector<string>	files;
	CPath::getPathContent(primitivesPath, true, false, true, files);

	for (i=0; i<files.size(); ++i)
	{
		if (CFile::getExtension(files[i]) == "primitive")
		{
			readFile(files[i]);
		}
	}

	files.clear();
	CPath::getPathContent(igLandPath, true, false, true, files);
	CPath::getPathContent(igVillagePath, true, false, true, files);

	set<string>		noWaterShapes;

	for (i=0; i<files.size(); ++i)
	{
		try
		{
			// load ig associated to the zone
			string	igname = files[i];

			string	ignamelookup = CPath::lookup(igname);
			//nlinfo("Reading ig '%s'", ignamelookup.c_str());
			CIFile			igStream(ignamelookup);
			CInstanceGroup	ig;
			igStream.serial(ig);

			// search in group for water instance
			for (j=0; j<ig._InstancesInfos.size(); ++j)
			{
				string	shapeName = ig._InstancesInfos[j].Name;
				if (CFile::getExtension (shapeName) == "")
					shapeName += ".shape";

				if (noWaterShapes.find(shapeName) != noWaterShapes.end())
					continue;

				string	shapeNameLookup = CPath::lookup (shapeName, false, false);
				if (!shapeNameLookup.empty())
				{
					CIFile			f;
					if (f.open (shapeNameLookup))
					{
						CShapeStream	shape;
						shape.serial(f);

						CWaterShape	*wshape = dynamic_cast<CWaterShape*>(shape.getShapePointer());
						if (wshape == NULL)
						{
							noWaterShapes.insert(shapeName);
							continue;
						}

						//nlinfo("Render water shape '%s'", shapeNameLookup.c_str());

						CMatrix	matrix;
						ig.getInstanceMatrix(j, matrix);

						CPolygon			wpoly;
						//wshape->getShapeInWorldSpace(wpoly);
						CPolygon2D			wpoly2d = wshape->getShape();

						uint	k;
						for (k=0; k<wpoly2d.Vertices.size(); ++k)
						{
							wpoly.Vertices.push_back(matrix * wpoly2d.Vertices[k]);
						}

						float	zwater = wpoly.Vertices[0].z - WaterThreshold;
						uint16	idx = (uint16)_WaterHeight.size();
						_WaterHeight.push_back(zwater);
						render(wpoly, idx);

						if (Verbose)
							nlinfo("Rendered water shape '%s' in instance '%s'", CFile::getFilenameWithoutExtension(shapeName).c_str(), CFile::getFilenameWithoutExtension(igname).c_str());
					}
					else if (Verbose)
					{
						noWaterShapes.insert(shapeName);
						nlwarning ("Can't load shape %s", shapeNameLookup.c_str());
					}
				}
				else if (Verbose)
				{
					noWaterShapes.insert(shapeName);
					nlwarning ("Can't find shape %s", shapeName.c_str());
				}
			}
		}
		catch (const Exception &e)
		{
			nlwarning("%s", e.what());
		}
	}

	COFile	f;
	if (f.open(outputfname))
	{
		f.serial(_Grid);
		f.serialCont(_WaterHeight);
	}
	else
	{
		nlwarning("Couldn't save pacs.packed_prims file '%s'", outputfname.c_str());
	}

	return true;
}
void CResourceManager::loadChildren(const std::string &filename)
{
	string ext = CFile::getExtension(filename);
	if(ext == "shape")
	{
		// need to get texture inside the shape
		NL3D::registerSerial3d();

		CShapeStream ss;
		NLMISC::CIFile i(CPath::lookup(filename, false).c_str());
		i.serial(ss);
		i.close();

		CMesh *m = (CMesh*)ss.getShapePointer();
		uint nbm = m->getNbMaterial();
		for(uint i = 0; i < nbm; i++)
		{
			CMaterial &mat = m->getMaterial(i);
			for(uint j = 0; j < IDRV_MAT_MAXTEXTURES; j++)
			{
				ITexture *t = mat.getTexture(j);
				if(t)
				{
					CTextureFile *tf = dynamic_cast<CTextureFile *>(t);
					if(tf)
					{
						get(tf->getFileName());
					}
					else
					{
						CTextureMultiFile *tmf = dynamic_cast<CTextureMultiFile *>(t);
						if(tmf)
						{
							for(uint t = 0; t < tmf->getNumFileName(); t++)
								get(tmf->getFileName(t));
						}
					}
				}
			}
		}
	}
	else if(ext == "ps")
	{
		// need to get texture inside the shape
		NL3D::registerSerial3d();
		

		string fn = CFile::getFilename(filename);
		CShapeBank *bank = new CShapeBank;
		string shapeCache("mtptShapeCache");
		bank->addShapeCache(shapeCache);
		bank->setShapeCacheSize(shapeCache,1024*1024);
		std::vector<std::string> filelist;
		filelist.push_back(filename);
		CDriverUser *drv = (CDriverUser *)(&C3DTask::getInstance().driver());
		bank->preLoadShapes(shapeCache,filelist,string("*.ps"),NULL,true,drv->getDriver());
		bool b = bank->isShapeWaiting();
		IShape *is = bank->getShape(fn);
		//bank->load(filename)

		CParticleSystemShape *ps = (CParticleSystemShape *)is;
		
		uint numTexture = ps->getNumCachedTextures();
		nlinfo("loadchildren(%s) : num texture = %d",filename.c_str(),numTexture);
		
		for(uint i=0;i<numTexture;i++)
		{
			ITexture *tex = ps->getCachedTexture(i);
			CTextureFile *utex = (CTextureFile *)tex;
			nlinfo("loadchildren(%s) : texture = %s",filename.c_str(),utex->getFileName().c_str());
			get(utex->getFileName());
		}
		
		bank->reset();
		delete bank;
		
	}
}