// Jet3d - JMiniApp
// Filename:jlevel.cpp
/***************************************************************
Copyright (C) 2000 Novasoft Consulting

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************/

#include "jmini_app.h"












/*****************************************************************************/
/*                             PROCESSING FUNCTIONS							 */
/*****************************************************************************/


/*----------------------------------------------------------------------------
  Name:		InitFileSystem(FuncResult *funcResult)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/
void 
JLevel::InitFileSystem(FuncResult *funcResult)
{
 char		lc_path[MAX_PATH];
 jeVFile    *fileSys;

 // Init.
 funcResult->SetUndef();
 fileSys = NULL;
 

	
 fileSys = jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_DOS, ic_levelBaseDir, NULL, JE_VFILE_OPEN_DIRECTORY);
 if(!fileSys)
 {
  funcResult->SetError("Cannot init file system", __LINE__, __FILE__);
  goto ReturnOut;
 }
 
 worldManager->errorManager->Log("Virtual base directory: ", ic_levelBaseDir, " opened");

 //create resource manager
 resourceMgr = jeResource_MgrCreate();
 if(!resourceMgr)
 {
  funcResult->SetError("Could not create resource manager", __LINE__, __FILE__);
  goto ReturnOut;
 }
	
 //open file systems
 wsprintf(lc_path, "%s\\%s", ic_levelBaseDir, ic_materialDir);
 worldManager->errorManager->Log("Using material directory: ", lc_path);

 materialVFile	= jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_DOS, lc_path, NULL, JE_VFILE_OPEN_READONLY|JE_VFILE_OPEN_DIRECTORY);
 if(!materialVFile)
 {
  funcResult->SetError("Cannot find material directory", __LINE__, __FILE__);
  goto ReturnOut;
 }
	

 wsprintf(lc_path, "%s\\%s", ic_levelBaseDir, ic_soundDir);
 worldManager->errorManager->Log("Using sound directory: ", lc_path);
 soundVFile		= jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_DOS, lc_path, NULL, JE_VFILE_OPEN_READONLY|JE_VFILE_OPEN_DIRECTORY);
 if(!soundVFile)
 {
  funcResult->SetError("Cannot find sound directory", __LINE__, __FILE__);
  goto ReturnOut;
 }
 
 
 wsprintf(lc_path, "%s\\%s", ic_levelBaseDir, ic_actorDir);
 worldManager->errorManager->Log("Using actor directory: ", lc_path);
 actorVFile		= jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_DOS, lc_path, NULL, JE_VFILE_OPEN_READONLY|JE_VFILE_OPEN_DIRECTORY);
 if(!actorVFile)
 {
  funcResult->SetError("Cannot find actor directory", __LINE__, __FILE__);
  goto ReturnOut;
 }
 

 wsprintf(lc_path, "%s\\%s", ic_levelBaseDir, ic_levelDir);
 worldManager->errorManager->Log("Using level directory: ", lc_path);
 levelVFile	= jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_DOS, lc_path, NULL, JE_VFILE_OPEN_READONLY|JE_VFILE_OPEN_DIRECTORY);
 if(!levelVFile)
 {
  funcResult->SetError("Cannot find level directory", __LINE__, __FILE__);
  goto ReturnOut;
 }
	
 
 
 //add file systems to resourcemgr so the world loader can resolve references in a world file
 jeResource_AddVFile( resourceMgr, ic_materialDir, materialVFile);
 jeResource_AddVFile( resourceMgr, ic_soundDir, soundVFile );
 jeResource_AddVFile( resourceMgr, ic_actorDir, actorVFile );
 jeResource_AddVFile( resourceMgr, ic_levelDir, levelVFile);

 worldManager->errorManager->Log("Resource Manager created");

 //create pointer manager (for world loader)
 ptrMgr = jePtrMgr_Create();
 if(!ptrMgr)
 {
  funcResult->SetError("Could not create pointer manager", __LINE__, __FILE__);
  goto ReturnOut;
 }



 // Ok.
 funcResult->SetOk();

ReturnOut:
 if(fileSys)
 {
  jeVFile_Close(fileSys);
  fileSys = NULL;
 }
}





/******************************************************************************/
/*									INTERFACE FUNCTIONS		                  */
/******************************************************************************/
JLevel::JLevel(void)
{
 resourceMgr = NULL;
 ptrMgr = NULL;
 soundSys = NULL;

 materialVFile = actorVFile = soundVFile = levelVFile = NULL;

 ib_initialized = false;
}

JLevel::~JLevel(void)
{
 if(materialVFile)
 {
  jeVFile_Close(materialVFile);
  materialVFile = NULL;
 }
 
 if(actorVFile)
 {
  jeVFile_Close(actorVFile);
  actorVFile = NULL;
 }
 
 if(soundVFile)
 {
  jeVFile_Close(soundVFile);
  soundVFile = NULL;
 }
 
 if(levelVFile)
 {
  jeVFile_Close(levelVFile);
  levelVFile = NULL;
 }
}

   
 
/*----------------------------------------------------------------------------
  Name:		Initialize(FuncResult *funcResult, char *ac_levelBase)
  Purpose:
  Notes:	  

  1.		level_base = the base directory stucture for the level to be loaded later
			ie global mats, actors and sounds.  
----------------------------------------------------------------------------*/
void
JLevel::Initialize(FuncResult *funcResult, char *ac_levelBase)
{
 char		lc_path[MAX_PATH];


 if(ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTALREADYINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Init.
 funcResult->SetUndef();
 
 
 
 // The objects dir which contains engine specific stuff should be determined
 // using the exe dir.
 GetAppPath(ic_exeBaseDir, strlen(ic_exeBaseDir));
 strcpy(ic_objectDir, "Objects");
  
 strcpy(ic_levelBaseDir, ac_levelBase);
 strcpy(ic_materialDir, "GlobalMaterials");
 strcpy(ic_soundDir, "Sounds");
 strcpy(ic_actorDir, "Actors");
 strcpy(ic_levelDir, "Levels");


 
 InitFileSystem(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;


 //create soundsystem
 soundSys = jeSound_CreateSoundSystem(worldManager->GetAppWnd());
 if(!soundSys) 
 {
  funcResult->SetError("Cannot init sound system", __LINE__, __FILE__);
  goto ReturnOut;
 }


 //log("Registering objects");
 wsprintf(lc_path, "%s\\%s", ic_exeBaseDir, ic_objectDir);
 if(jeEngine_RegisterObjects(lc_path) == JE_FALSE)
 {
  funcResult->SetError("Could not register objects", __LINE__, __FILE__);
  goto ReturnOut;
 }


 // Ok.
 ib_initialized = true;
 funcResult->SetOk();


ReturnOut:
 // All errors are init errors.
 if(funcResult->GetFailed())
  funcResult->SetInitError();
}

/*----------------------------------------------------------------------------
  Name:		Load(FuncResult *funcResult, char *ac_levelPath)
  Purpose:	Creates our world based on the level you ask it to load.
  Notes:      

  1.  
----------------------------------------------------------------------------*/
jeWorld* 
JLevel::Load(FuncResult *funcResult, char *ac_levelPath)
{
 jeVFile *file, *j3dFork;
 jeWorld *world;
 
 // Init.
 funcResult->SetUndef();
 world = NULL;
 file = j3dFork = NULL;

 if(!ib_initialized)
 {
  funcResult->SetError(FUNCR_OBJECTNOTINITIALIZED, __LINE__, __FILE__);
  goto ReturnOut;
 }


 worldManager->errorManager->Log("Loading world: ", ac_levelPath);

 //open the world file (which is a virtual directory)
 file = jeVFile_OpenNewSystem(NULL, JE_VFILE_TYPE_VIRTUAL, ac_levelPath, NULL, JE_VFILE_OPEN_READONLY|JE_VFILE_OPEN_DIRECTORY);
 if(!file) 
 {
  funcResult->SetError("Could not find level file", __LINE__, __FILE__);
  goto ReturnOut;
 }

 worldManager->errorManager->Log("World opened");


 //get the J3D vfile from the world file
 j3dFork = jeVFile_Open( file, "Jet3D", JE_VFILE_OPEN_READONLY);
 if(!j3dFork)
 {
  funcResult->SetError("Level file has no J3D world!", __LINE__, __FILE__);
  goto ReturnOut;
 }

 worldManager->errorManager->Log("Creating world");
 

 //create a world object from the world file.
 world = jeWorld_CreateFromFile( j3dFork, ptrMgr, resourceMgr);
 if(!world)
 {
  funcResult->SetError("Could create world from file", __LINE__, __FILE__);
  goto ReturnOut;
 }
 
 worldManager->errorManager->Log("World created succesfully");

 worldManager->errorManager->Log("Setting up world");


 //setup the world
 jeWorld_SetEngine(world, worldManager->m_pEngine);
 jeWorld_AttachSoundSystem(world, soundSys);


 worldManager->errorManager->Log("Compiling BSP");

 //compile the world
 if(jeWorld_RebuildBSP(world, BSP_OPTIONS_CSG_BRUSHES, Logic_Smart, 3) == JE_FALSE)
 {
  funcResult->SetError("Could not compile BSP", __LINE__, __FILE__);
  goto ReturnOut;
 }

 worldManager->errorManager->Log("BSP compiled");	


 worldManager->errorManager->Log("Building lights");
 if(jeWorld_RebuildLights(world) == JE_FALSE)
 {
  funcResult->SetError("Could not build lights", __LINE__, __FILE__);
  goto ReturnOut;
 }

 worldManager->errorManager->Log("Lights Built");
 
 // All done.
 worldManager->errorManager->Log("Finished loading world: ", ac_levelPath);

 // Ok.
 funcResult->SetOk();

ReturnOut:
 //close the world file
 if(j3dFork)
 {
  jeVFile_Close(j3dFork);
  j3dFork = NULL;
 }

 if(file)
 {
  jeVFile_Close(file);
  file = NULL;
 }


 return world;
}