// Jet3d - JMiniApp
// Filename:world_manager.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.
*****************************************************************/


/*****************************************************************************/
/*                             COMMON VERSION                                */
/*****************************************************************************/
 


#include "jmini_app.h"







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


/*----------------------------------------------------------------------------
  Name:		UpdateFrame(void)
  Purpose:
  Notes:      

  1.  
----------------------------------------------------------------------------*/




 

void
WorldManager::UpdateFrame(void)
{
 // render World
 jeEngine_BeginFrame(m_pEngine, cameraManager->camera, JE_TRUE);
 jeWorld_Render(m_pWorld, cameraManager->camera, NULL);

 jeEngine_Printf(m_pEngine, 0, ii_versionPosHeight, ic_versionMsg);

 jeEngine_EndFrame(m_pEngine);
}





/*----------------------------------------------------------------------------
  Name:		Release(void)
  Purpose:	This will return Windows to normal (windowed) mode.
  Notes:      

  1.  
----------------------------------------------------------------------------*/
void
WorldManager::Release(void)
{
 FuncResult	funcResult;

 // Shut it all down and quit.
 if(errorManager)
 {
  if(errorManager->GetLogging())
   errorManager->StopLogging(&funcResult);
 }

 if(m_pWorld) 
 {
  jeWorld_Destroy(&m_pWorld);
  m_pWorld = NULL;
 }

 if(m_pEngine)
 {
  // This is a bit crap, have to check to see if a driver is reg with the Engine
  // before we can call this func!
  if(renderManager)
  {
   if(renderManager->GetInitialized())
    jeEngine_ShutdownDriver(m_pEngine);
  }

  jeEngine_Free(m_pEngine);
 
  m_pEngine = NULL;
 }
}

/******************************************************************************/
/*									INTERFACE FUNCTIONS		                  */
/******************************************************************************/
WorldManager::WorldManager(void)
{
 appHWnd = 0;
 errorManager = NULL;
 renderManager = NULL;
 cameraManager = NULL;

 m_pEngine = NULL;
 m_pWorld = NULL;
 m_pLevel = NULL;

 if_lastTime = 0;
 ib_initialized = ib_showStats = false;
 ii_versionPosHeight = 0;
}

WorldManager::~WorldManager(void)
{
 // Release all interfaces first.
 Release();

 if(errorManager)
 {
  delete errorManager;
  errorManager = NULL;
 } 

 if(renderManager)
 {
  delete renderManager;
  renderManager = NULL;
 }

 if(cameraManager)
 {
  delete cameraManager;
  cameraManager = NULL;
 }

 if(m_pLevel)
 {
  delete m_pLevel;
  m_pLevel = NULL;
 }
}

/*----------------------------------------------------------------------------
  Name:		InitializeWorld(FuncResult *funcResult)
  Purpose:  Main WorldManager initiliziation.
  1, Create our manager objects.
  2, Initialize our manager objects.

  Notes:      

  1. 
----------------------------------------------------------------------------*/
void
WorldManager::InitializeWorld(FuncResult *funcResult)
{
 char		lc_temp[MAX_PATH];
 char		lc_levelPath[MAX_PATH];
 char		lc_levelBase[MAX_PATH];
 long		ll_width, ll_height;
 int		i;
 bool		lb_found;
  

 // Init.
 funcResult->SetUndef();
 lb_found = false;


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

 // Create our World managers.
 errorManager = new ErrorManager();
 if(!errorManager)
 {
  funcResult->SetError(FUNCR_COULDNOTALLOCMEM, "Error Manager create failed", __LINE__, __FILE__); 
  goto ReturnOut;
 }

 renderManager = new RenderManager();
 if(!renderManager)
 {
  funcResult->SetError(FUNCR_COULDNOTALLOCMEM, "Render Manager create failed", __LINE__, __FILE__); 
  goto ReturnOut;
 }

 cameraManager = new CameraManager();
 if(!cameraManager)
 {
  funcResult->SetError(FUNCR_COULDNOTALLOCMEM, "Camera Manager create failed", __LINE__, __FILE__); 
  goto ReturnOut;
 }

 m_pLevel = new JLevel();
 if(!m_pLevel)
 {
  funcResult->SetError(FUNCR_COULDNOTALLOCMEM, "JLevel create failed", __LINE__, __FILE__); 
  goto ReturnOut;
 }
 
 
 // Start the Jet3D Engine
 m_pEngine = jeEngine_Create(appHWnd, "JMiniApp", NULL);
 if(!m_pEngine)
 {
  funcResult->SetError("Engine create failed", __LINE__, __FILE__);
  goto ReturnOut;
 }
 
 // Engine is active by default.
 jeEngine_Activate(m_pEngine, JE_TRUE);


 if(jeEngine_RegisterDriver(m_pEngine, jeEngine_SoftwareDriver()) == JE_FALSE)
 {
  funcResult->SetError("Could not register Software driver", __LINE__, __FILE__); 
  goto ReturnOut;
 }
 
 if(jeEngine_RegisterDriver(m_pEngine, jeEngine_D3DDriver()) == JE_FALSE)
 {
  funcResult->SetError("Could not register D3D driver",  __LINE__, __FILE__); 
  goto ReturnOut;
 }


 // Do we want to do some logging?
 if(NOVA_LOGGING)
 {
  errorManager->StartLogging(funcResult);
  if(funcResult->GetFailed())
   goto ReturnOut;
 }

 // First see if we have valid ini file settings.
 GetPrivateProfileString("GENERAL", "VALID", "NO", lc_temp, 255, "jminiapp.ini");
 if(strcmp(lc_temp, "YES") != 0)
 {
  funcResult->SetError(FUNCR_INVALIDINISETTINGS, __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Read the level to load from our ini.
 GetPrivateProfileString("GENERAL", "LEVEL", "NONE", lc_levelPath, 255, "jminiapp.ini");
 if(strcmp(lc_temp, "NONE") == 0)
 {
  funcResult->SetError("No level specified in INI", __LINE__, __FILE__);
  goto ReturnOut;
 }

 // Strip of name of level, so we just have the base dir (this is the root from which
 // all of the supporting files will be loaded).
 strcpy(lc_levelBase, lc_levelPath); 


 // Get the root directory.
 for(i=strlen(lc_levelBase)-1; i>0; i--)
 {
  if(lb_found)
  {
   if(lc_levelBase[i]=='\\')
   {
    lc_levelBase[i] = 0;
    break;
   }
  }

  if(lc_levelBase[i]=='\\')
   lb_found = true;  
 }


 m_pLevel->Initialize(funcResult, lc_levelBase); 
 if(funcResult->GetFailed())
  goto ReturnOut;

 
 // Initialize our render manager.
 renderManager->Initialize(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;

 
 // Initialize our camera manager.
 cameraManager->Initialize(funcResult);
 if(funcResult->GetFailed())
  goto ReturnOut;

 

 // Load requested level (this will also create our world).
 m_pWorld = m_pLevel->Load(funcResult, lc_levelPath);
 if(funcResult->GetFailed())
  goto ReturnOut;



 // Calculate pos for version text.
 renderManager->GetWidthAndHeight(funcResult, ll_width, ll_height);
 if(funcResult->GetFailed())
  goto ReturnOut;


 ii_versionPosHeight = (ll_height - 16);
 

 // Don't display fps by default.
 jeEngine_EnableFrameRateCounter(m_pEngine, JE_FALSE); 

 
 // Record the current time.
 if_lastTime = ((float)timeGetTime()) * 0.001f;
 

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

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


/*----------------------------------------------------------------------------
  Name:		UpdateWorld(void)
  Purpose:	Controls the updating and drawing of the m_pWorld.
  Notes:      

  1.  
----------------------------------------------------------------------------*/
void
WorldManager::UpdateWorld(void)
{
 float lf_deltaTime, lf_currTime;
 
 lf_currTime = ((float)timeGetTime()) * 0.001f;

 lf_deltaTime = lf_currTime - if_lastTime;
 if_lastTime = lf_currTime;
 
 // update objects
 jeWorld_Frame(m_pWorld, lf_deltaTime);

 // Move camera.
 cameraManager->DoSomething(lf_deltaTime);


 UpdateFrame();
}



/*----------------------------------------------------------------------------
  Name:		QuitWithError(void)
  Purpose:	Quits application with a user message.
		

  Notes:      


----------------------------------------------------------------------------*/
void
WorldManager::QuitWithError(char *ac_errorTxt, bool ab_initError)
{
 // Stop main loop.
 gi_appActive = FALSE;
 
  
 // Must change to normal windows mode before displaying messagebox.
 Release();

 if(ab_initError)
  strcat(ic_appName, ":Initialization Error");
 else
  strcat(ic_appName, ":Runtime Error");

 MessageBox(appHWnd, ac_errorTxt, ic_appName, MB_OK | MB_ICONSTOP);
  
 // Make a request to destroy the application.
 DestroyWindow(appHWnd);
}








