Esempio n. 1
0
bool CModelFile::ReadBinaryModel(const std::string& fileName)
{
    std::ifstream stream;
    stream.open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
    if (!stream.good())
    {
        GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
        return false;
    }

    return ReadBinaryModel(stream);
}
/*
=================
idRenderWorldLocal::InitFromMap

A NULL or empty name will make a world without a map model, which
is still useful for displaying a bare model
=================
*/
bool idRenderWorldLocal::InitFromMap( const char* name )
{
	idLexer* 		src;
	idToken			token;
	idRenderModel* 	lastModel;
	
	// if this is an empty world, initialize manually
	if( !name || !name[0] )
	{
		FreeWorld();
		mapName.Clear();
		ClearWorld();
		return true;
	}
	
	// load it
	idStrStatic< MAX_OSPATH > filename = name;
	filename.SetFileExtension( PROC_FILE_EXT );
	
	// check for generated file
	idStrStatic< MAX_OSPATH > generatedFileName = filename;
	generatedFileName.Insert( "generated/", 0 );
	generatedFileName.SetFileExtension( "bproc" );
	
	// if we are reloading the same map, check the timestamp
	// and try to skip all the work
	ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( filename );
	
	if( name == mapName )
	{
		if( fileSystem->InProductionMode() || ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) )
		{
			common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
			FreeDefs();
			TouchWorldModels();
			AddWorldModelEntities();
			ClearPortalStates();
			return true;
		}
		common->Printf( "idRenderWorldLocal::InitFromMap: timestamp has changed, reloading.\n" );
	}
	
	FreeWorld();
	
	// see if we have a generated version of this
	static const byte BPROC_VERSION = 1;
	static const unsigned int BPROC_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION;
	bool loaded = false;
	idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
	if( file != NULL )
	{
		int numEntries = 0;
		int magic = 0;
		file->ReadBig( magic );
		if( magic == BPROC_MAGIC )
		{
			file->ReadBig( numEntries );
			file->ReadString( mapName );
			file->ReadBig( mapTimeStamp );
			loaded = true;
			for( int i = 0; i < numEntries; i++ )
			{
				idStrStatic< MAX_OSPATH > type;
				file->ReadString( type );
				type.ToLower();
				if( type == "model" )
				{
					idRenderModel* lastModel = ReadBinaryModel( file );
					if( lastModel == NULL )
					{
						loaded = false;
						break;
					}
					renderModelManager->AddModel( lastModel );
					localModels.Append( lastModel );
				}
				else if( type == "shadowmodel" )
				{
					idRenderModel* lastModel = ReadBinaryModel( file );
					if( lastModel == NULL )
					{
						loaded = false;
						break;
					}
					renderModelManager->AddModel( lastModel );
					localModels.Append( lastModel );
				}
				else if( type == "interareaportals" )
				{
					ReadBinaryAreaPortals( file );
				}
				else if( type == "nodes" )
				{
					ReadBinaryNodes( file );
				}
				else
				{
					idLib::Error( "Binary proc file failed, unexpected type %s\n", type.c_str() );
				}
			}
		}
	}
	
	if( !loaded )
	{
	
		src = new( TAG_RENDER ) idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
		if( !src->IsLoaded() )
		{
			common->Printf( "idRenderWorldLocal::InitFromMap: %s not found\n", filename.c_str() );
			ClearWorld();
			return false;
		}
		
		
		mapName = name;
		mapTimeStamp = currentTimeStamp;
		
		// if we are writing a demo, archive the load command
		if( common->WriteDemo() )
		{
			WriteLoadMap();
		}
		
		if( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) )
		{
			common->Printf( "idRenderWorldLocal::InitFromMap: bad id '%s' instead of '%s'\n", token.c_str(), PROC_FILE_ID );
			delete src;
			return false;
		}
		
		int numEntries = 0;
		idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
		if( outputFile != NULL )
		{
			int magic = BPROC_MAGIC;
			outputFile->WriteBig( magic );
			outputFile->WriteBig( numEntries );
			outputFile->WriteString( mapName );
			outputFile->WriteBig( mapTimeStamp );
		}
		
		// parse the file
		while( 1 )
		{
			if( !src->ReadToken( &token ) )
			{
				break;
			}
			
			common->UpdateLevelLoadPacifier();
			
			
			if( token == "model" )
			{
				lastModel = ParseModel( src, name, currentTimeStamp, outputFile );
				
				// add it to the model manager list
				renderModelManager->AddModel( lastModel );
				
				// save it in the list to free when clearing this map
				localModels.Append( lastModel );
				
				numEntries++;
				
				continue;
			}
			
			if( token == "shadowModel" )
			{
				lastModel = ParseShadowModel( src, outputFile );
				
				// add it to the model manager list
				renderModelManager->AddModel( lastModel );
				
				// save it in the list to free when clearing this map
				localModels.Append( lastModel );
				
				numEntries++;
				continue;
			}
			
			if( token == "interAreaPortals" )
			{
				ParseInterAreaPortals( src, outputFile );
				
				numEntries++;
				continue;
			}
			
			if( token == "nodes" )
			{
				ParseNodes( src, outputFile );
				
				numEntries++;
				continue;
			}
			
			src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
		}
		
		delete src;
		
		if( outputFile != NULL )
		{
			outputFile->Seek( 0, FS_SEEK_SET );
			int magic = BPROC_MAGIC;
			outputFile->WriteBig( magic );
			outputFile->WriteBig( numEntries );
		}
		
	}
	
	
	
	// if it was a trivial map without any areas, create a single area
	if( !numPortalAreas )
	{
		ClearWorld();
	}
	
	// find the points where we can early-our of reference pushing into the BSP tree
	CommonChildrenArea_r( &areaNodes[0] );
	
	AddWorldModelEntities();
	ClearPortalStates();
	
	// done!
	return true;
}