2005-08-15 01:34:37 +02:00
# include "precompiled.h"
# include "lib.h"
# include "lib/sdl.h"
# include "lib/ogl.h"
# include "lib/detect.h"
# include "lib/timer.h"
# include "lib/input.h"
2005-09-20 06:05:23 +02:00
# if CPU_IA32
# include "lib / sysdep / ia32.h"
# endif
2005-08-15 01:34:37 +02:00
# include "lib/res/res.h"
# include "lib/res/sound/snd.h"
# include "lib/res/graphics/tex.h"
# include "lib/res/graphics/cursor.h"
# include "ps/Profile.h"
# include "ps/ProfileViewer.h"
# include "ps/Loader.h"
# include "ps/Font.h"
# include "ps/CConsole.h"
# include "ps/Game.h"
# include "ps/Interact.h"
# include "ps/Hotkey.h"
# include "ps/ConfigDB.h"
# include "ps/CLogger.h"
# include "ps/i18n.h"
# include "ps/Overlay.h"
# include "ps/StringConvert.h"
# include "graphics/MapReader.h"
# include "graphics/Terrain.h"
# include "graphics/TextureManager.h"
# include "graphics/ObjectManager.h"
# include "graphics/SkeletonAnimManager.h"
# include "graphics/LightEnv.h"
# include "graphics/Model.h"
# include "graphics/UnitManager.h"
# include "graphics/MaterialManager.h"
# include "graphics/MeshManager.h"
# include "renderer/Renderer.h"
2005-09-30 02:59:42 +02:00
# include "maths/MathUtil.h"
2005-08-15 01:34:37 +02:00
# include "simulation/BaseEntityCollection.h"
# include "simulation/Entity.h"
# include "simulation/EntityHandles.h"
# include "simulation/EntityManager.h"
# include "simulation/PathfindEngine.h"
# include "simulation/Scheduler.h"
# include "simulation/Projectile.h"
# include "scripting/ScriptingHost.h"
# include "scripting/GameEvents.h"
# include "scripting/JSInterface_Entity.h"
# include "scripting/JSInterface_BaseEntity.h"
# include "scripting/JSInterface_Vector3D.h"
# include "scripting/JSInterface_Camera.h"
# include "scripting/JSInterface_Selection.h"
# include "scripting/JSInterface_Console.h"
# include "scripting/JSCollection.h"
# include "scripting/DOMEvent.h"
# ifndef NO_GUI
# include "gui / scripting / JSInterface_IGUIObject.h"
# include "gui / scripting / JSInterface_GUITypes.h"
# include "gui / GUI.h"
# endif
# include "sound/CMusicPlayer.h"
# include "sound/JSI_Sound.h"
# include "Network/SessionManager.h"
# include "Network/Server.h"
# include "Network/Client.h"
# include "Atlas.h"
# include "Config.h"
2005-08-15 01:50:37 +02:00
# include "ps/Util.h"
2005-08-15 01:34:37 +02:00
ERROR_GROUP ( System ) ;
ERROR_TYPE ( System , SDLInitFailed ) ;
ERROR_TYPE ( System , VmodeFailed ) ;
ERROR_TYPE ( System , RequiredExtensionsMissing ) ;
# define LOG_CATEGORY "gamesetup"
static int SetVideoMode ( int w , int h , int bpp , bool fullscreen )
{
SDL_GL_SetAttribute ( SDL_GL_DEPTH_SIZE , 24 ) ;
SDL_GL_SetAttribute ( SDL_GL_DOUBLEBUFFER , 1 ) ;
ulong flags = SDL_OPENGL ;
if ( fullscreen )
flags | = SDL_FULLSCREEN ;
if ( ! SDL_SetVideoMode ( w , h , bpp , flags ) )
return - 1 ;
glViewport ( 0 , 0 , w , h ) ;
# ifndef NO_GUI
g_GUI . UpdateResolution ( ) ;
# endif
oglInit ( ) ; // required after each mode change
if ( SDL_SetGamma ( g_Gamma , g_Gamma , g_Gamma ) < 0 )
debug_warn ( " SDL_SetGamma failed " ) ;
return 0 ;
}
//----------------------------------------------------------------------------
// GUI integration
//----------------------------------------------------------------------------
void GUI_Init ( )
{
# ifndef NO_GUI
{ TIMER ( ps_gui_init ) ;
g_GUI . Initialize ( ) ; }
{ TIMER ( ps_gui_setup_xml ) ;
g_GUI . LoadXMLFile ( " gui/test/setup.xml " ) ; }
{ TIMER ( ps_gui_styles_xml ) ;
g_GUI . LoadXMLFile ( " gui/test/styles.xml " ) ; }
{ TIMER ( ps_gui_sprite1_xml ) ;
g_GUI . LoadXMLFile ( " gui/test/sprite1.xml " ) ; }
// Atlas is running, we won't need these GUI pages (for now!
// what if Atlas switches to in-game mode?!)
// TODO: temporary hack until revised GUI structure is completed.
// if(ATLAS_IsRunning())
// return;
{ TIMER ( ps_gui_1 ) ;
g_GUI . LoadXMLFile ( " gui/test/1_init.xml " ) ; }
{ TIMER ( ps_gui_2 ) ;
g_GUI . LoadXMLFile ( " gui/test/2_mainmenu.xml " ) ; }
{ TIMER ( ps_gui_3 ) ;
g_GUI . LoadXMLFile ( " gui/test/3_loading.xml " ) ; }
{ TIMER ( ps_gui_4 ) ;
g_GUI . LoadXMLFile ( " gui/test/4_session.xml " ) ; }
{ TIMER ( ps_gui_6 ) ;
g_GUI . LoadXMLFile ( " gui/test/6_subwindows.xml " ) ; }
{ TIMER ( ps_gui_6_1 ) ;
g_GUI . LoadXMLFile ( " gui/test/6_1_manual.xml " ) ; }
{ TIMER ( ps_gui_6_2 ) ;
g_GUI . LoadXMLFile ( " gui/test/6_2_jukebox.xml " ) ; }
{ TIMER ( ps_gui_7 ) ;
g_GUI . LoadXMLFile ( " gui/test/7_atlas.xml " ) ; }
{ TIMER ( ps_gui_9 ) ;
g_GUI . LoadXMLFile ( " gui/test/9_global.xml " ) ; }
# endif
}
void GUI_Shutdown ( )
{
# ifndef NO_GUI
g_GUI . Destroy ( ) ;
delete & g_GUI ;
# endif
}
void GUI_ShowMainMenu ( )
{
}
// display progress / description in loading screen
void GUI_DisplayLoadProgress ( int percent , const wchar_t * pending_task )
{
# ifndef NO_GUI
CStrW i18n_description = I18n : : translate ( pending_task ) ;
JSString * js_desc = StringConvert : : wstring_to_jsstring ( g_ScriptingHost . getContext ( ) , i18n_description ) ;
g_ScriptingHost . SetGlobal ( " g_Progress " , INT_TO_JSVAL ( percent ) ) ;
g_ScriptingHost . SetGlobal ( " g_LoadDescription " , STRING_TO_JSVAL ( js_desc ) ) ;
g_GUI . SendEventToAll ( " progress " ) ;
# endif
}
/////////////////////////////////////////////////////////////////////////////////////////////
// RenderNoCull: render absolutely everything to a blank frame to force renderer
// to load required assets
static void RenderNoCull ( )
{
g_Renderer . BeginFrame ( ) ;
if ( g_Game )
g_Game - > GetView ( ) - > RenderNoCull ( ) ;
g_Renderer . FlushFrame ( ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
g_Renderer . EndFrame ( ) ;
}
void Render ( )
{
MICROLOG ( L " begin frame " ) ;
oglCheck ( ) ;
# ifndef NO_GUI // HACK: because colour-parsing requires the GUI
CStr skystring = " 61 193 255 " ;
CFG_GET_USER_VAL ( " skycolor " , String , skystring ) ;
CColor skycol ;
GUI < CColor > : : ParseString ( skystring , skycol ) ;
g_Renderer . SetClearColor ( skycol . Int ( ) ) ;
# endif
// start new frame
g_Renderer . BeginFrame ( ) ;
oglCheck ( ) ;
if ( g_Game & & g_Game - > IsGameStarted ( ) )
{
g_Game - > GetView ( ) - > Render ( ) ;
oglCheck ( ) ;
MICROLOG ( L " flush frame " ) ;
PROFILE_START ( " flush frame " ) ;
g_Renderer . FlushFrame ( ) ;
PROFILE_END ( " flush frame " ) ;
glPushAttrib ( GL_ENABLE_BIT ) ;
glDisable ( GL_LIGHTING ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_DEPTH_TEST ) ;
if ( g_EntGraph )
{
PROFILE ( " render entity overlays " ) ;
glColor3f ( 1.0f , 0.0f , 1.0f ) ;
MICROLOG ( L " render entities " ) ;
g_EntityManager . renderAll ( ) ; // <-- collision outlines, pathing routes
}
PROFILE_START ( " render selection " ) ;
2005-09-05 21:48:28 +02:00
glEnable ( GL_DEPTH_TEST ) ;
2005-08-15 01:34:37 +02:00
g_Mouseover . renderSelectionOutlines ( ) ;
g_Selection . renderSelectionOutlines ( ) ;
2005-09-05 21:48:28 +02:00
glDisable ( GL_DEPTH_TEST ) ;
2005-08-15 01:34:37 +02:00
PROFILE_END ( " render selection " ) ;
2005-09-05 21:48:28 +02:00
PROFILE_START ( " render building placement cursor " ) ;
if ( g_BuildingPlacer . m_active )
{
//glEnable( GL_DEPTH_TEST );
g_BuildingPlacer . render ( ) ;
//glDisable( GL_DEPTH_TEST );
}
PROFILE_END ( " render building placement cursor " ) ;
2005-09-05 23:45:26 +02:00
2005-09-06 21:30:41 +02:00
PROFILE_START ( " render health bars " ) ;
2005-09-05 23:45:26 +02:00
glMatrixMode ( GL_PROJECTION ) ;
glPushMatrix ( ) ;
glLoadIdentity ( ) ;
glOrtho ( 0.f , ( float ) g_xres , 0.f , ( float ) g_yres , - 1.f , 1000.f ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPushMatrix ( ) ;
glLoadIdentity ( ) ;
2005-09-06 21:30:41 +02:00
g_Mouseover . renderHealthBars ( ) ;
g_Selection . renderHealthBars ( ) ;
2005-09-05 23:45:26 +02:00
glPopMatrix ( ) ;
glMatrixMode ( GL_PROJECTION ) ;
glPopMatrix ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
2005-09-06 21:30:41 +02:00
PROFILE_END ( " render health bars " ) ;
2005-09-05 23:45:26 +02:00
2005-08-15 01:34:37 +02:00
glPopAttrib ( ) ;
}
else
{
PROFILE_START ( " flush frame " ) ;
g_Renderer . FlushFrame ( ) ;
PROFILE_END ( " flush frame " ) ;
}
oglCheck ( ) ;
PROFILE_START ( " render fonts " ) ;
MICROLOG ( L " render fonts " ) ;
// overlay mode
glPushAttrib ( GL_ENABLE_BIT ) ;
glEnable ( GL_TEXTURE_2D ) ;
glDisable ( GL_CULL_FACE ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable ( GL_BLEND ) ;
glMatrixMode ( GL_PROJECTION ) ;
glPushMatrix ( ) ;
glLoadIdentity ( ) ;
glOrtho ( 0.f , ( float ) g_xres , 0.f , ( float ) g_yres , - 1.f , 1000.f ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPushMatrix ( ) ;
PROFILE_END ( " render fonts " ) ;
oglCheck ( ) ;
# ifndef NO_GUI
// Temp GUI message GeeTODO
glLoadIdentity ( ) ;
MICROLOG ( L " render GUI " ) ;
PROFILE_START ( " render gui " ) ;
g_GUI . Draw ( ) ;
PROFILE_END ( " render gui " ) ;
# endif
oglCheck ( ) ;
// Text:
// Use the GL_ALPHA texture as the alpha channel with a flat colouring
glDisable ( GL_ALPHA_TEST ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
// Added --
glEnable ( GL_TEXTURE_2D ) ;
// -- GL
oglCheck ( ) ;
{
PROFILE ( " render console " ) ;
glLoadIdentity ( ) ;
MICROLOG ( L " render console " ) ;
CFont font ( " console " ) ;
font . Bind ( ) ;
g_Console - > Render ( ) ;
}
oglCheck ( ) ;
// Profile information
PROFILE_START ( " render profiling " ) ;
RenderProfile ( ) ;
PROFILE_END ( " render profiling " ) ;
oglCheck ( ) ;
if ( g_Game & & g_Game - > IsGameStarted ( ) )
{
PROFILE ( " render selection overlays " ) ;
g_Mouseover . renderOverlays ( ) ;
g_Selection . renderOverlays ( ) ;
}
oglCheck ( ) ;
// Draw the cursor (or set the Windows cursor, on Windows)
2005-09-06 10:25:41 +02:00
CStr8 cursorName = g_BuildingPlacer . m_active ? " action-build " : g_CursorName ;
cursor_draw ( cursorName , g_mouse_x , g_mouse_y ) ;
2005-08-15 01:34:37 +02:00
// restore
glMatrixMode ( GL_PROJECTION ) ;
glPopMatrix ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glPopMatrix ( ) ;
glPopAttrib ( ) ;
MICROLOG ( L " end frame " ) ;
g_Renderer . EndFrame ( ) ;
oglCheck ( ) ;
}
static void InitScripting ( )
{
TIMER ( InitScripting ) ;
// Create the scripting host. This needs to be done before the GUI is created.
new ScriptingHost ;
// It would be nice for onLoad code to be able to access the setTimeout() calls.
new CScheduler ;
// Register the JavaScript interfaces with the runtime
CEntity : : ScriptingInit ( ) ;
CBaseEntity : : ScriptingInit ( ) ;
JSI_Sound : : ScriptingInit ( ) ;
CProfileNode : : ScriptingInit ( ) ;
# ifndef NO_GUI
JSI_IGUIObject : : init ( ) ;
JSI_GUITypes : : init ( ) ;
# endif
JSI_Vector3D : : init ( ) ;
EntityCollection : : Init ( " EntityCollection " ) ;
SColour : : ScriptingInit ( ) ;
CPlayer : : ScriptingInit ( ) ;
PlayerCollection : : Init ( " PlayerCollection " ) ;
CDamageType : : ScriptingInit ( ) ;
CJSComplexPropertyAccessor < CEntity > : : ScriptingInit ( ) ; // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor<T> is already being compiled for T = CEntity.
CScriptEvent : : ScriptingInit ( ) ;
CJSProgressTimer : : ScriptingInit ( ) ;
CProjectile : : ScriptingInit ( ) ;
g_ScriptingHost . DefineConstant ( " ORDER_NONE " , - 1 ) ;
g_ScriptingHost . DefineConstant ( " ORDER_GOTO " , CEntityOrder : : ORDER_GOTO ) ;
g_ScriptingHost . DefineConstant ( " ORDER_PATROL " , CEntityOrder : : ORDER_PATROL ) ;
g_ScriptingHost . DefineConstant ( " ORDER_ATTACK " , CEntityOrder : : ORDER_ATTACK_MELEE ) ;
g_ScriptingHost . DefineConstant ( " ORDER_GATHER " , CEntityOrder : : ORDER_GATHER ) ;
# define REG_JS_CONSTANT(_name) g_ScriptingHost.DefineConstant(#_name, _name)
REG_JS_CONSTANT ( SDL_BUTTON_LEFT ) ;
REG_JS_CONSTANT ( SDL_BUTTON_MIDDLE ) ;
REG_JS_CONSTANT ( SDL_BUTTON_RIGHT ) ;
REG_JS_CONSTANT ( SDL_BUTTON_WHEELUP ) ;
REG_JS_CONSTANT ( SDL_BUTTON_WHEELDOWN ) ;
# undef REG_JS_CONSTANT
CNetMessage : : ScriptingInit ( ) ;
JSI_Camera : : init ( ) ;
JSI_Console : : init ( ) ;
new CGameEvents ;
}
static void InitVfs ( const char * argv0 )
{
TIMER ( InitVfs ) ;
// set current directory to "$game_dir/data".
// this is necessary because it is otherwise unknown,
// especially if run from a shortcut / symlink.
//
// "../data" is relative to the executable (in "$game_dir/system").
//
// rationale for data/ being root: untrusted scripts must not be
// allowed to overwrite critical game (or worse, OS) files.
// the VFS prevents any accesses to files above this directory.
int err = file_rel_chdir ( argv0 , " ../data " ) ;
2005-09-08 03:48:57 +02:00
WARN_ERR ( err ) ;
vfs_init ( ) ;
vfs_mount ( " " , " mods/official " , VFS_MOUNT_RECURSIVE | VFS_MOUNT_ARCHIVES | VFS_MOUNT_WATCH ) ;
vfs_mount ( " screenshots/ " , " screenshots " ) ;
vfs_mount ( " profiles/ " , " profiles " , VFS_MOUNT_RECURSIVE ) ;
2005-08-15 01:34:37 +02:00
extern void vfs_dump_stats ( ) ;
vfs_dump_stats ( ) ;
// don't try vfs_display yet: SDL_Init hasn't yet redirected stdout
}
2005-08-20 17:44:50 +02:00
static void InitPs ( bool setup_gui )
2005-08-15 01:34:37 +02:00
{
// console
{
TIMER ( ps_console ) ;
g_Console - > UpdateScreenSize ( g_xres , g_yres ) ;
// Calculate and store the line spacing
CFont font ( " console " ) ;
g_Console - > m_iFontHeight = font . GetLineSpacing ( ) ;
// Offset by an arbitrary amount, to make it fit more nicely
g_Console - > m_iFontOffset = 9 ;
}
// language and hotkeys
{
TIMER ( ps_lang_hotkeys ) ;
std : : string lang = " english " ;
CFG_GET_SYS_VAL ( " language " , String , lang ) ;
I18n : : LoadLanguage ( lang . c_str ( ) ) ;
loadHotkeys ( ) ;
}
// GUI uses VFS, so this must come after VFS init.
2005-08-20 17:44:50 +02:00
if ( setup_gui )
GUI_Init ( ) ;
2005-08-15 01:34:37 +02:00
}
static void InitInput ( )
{
// register input handlers
// This stack is constructed so the first added, will be the last
// one called. This is important, because each of the handlers
// has the potential to block events to go further down
// in the chain. I.e. the last one in the list added, is the
// only handler that can block all messages before they are
// processed.
in_add_handler ( game_view_handler ) ;
in_add_handler ( interactInputHandler ) ;
in_add_handler ( conInputHandler ) ;
in_add_handler ( profilehandler ) ;
in_add_handler ( hotkeyInputHandler ) ;
}
static void ShutdownPs ( )
{
GUI_Shutdown ( ) ;
delete g_Console ;
// disable the special Windows cursor, or free textures for OGL cursors
cursor_draw ( 0 , g_mouse_x , g_mouse_y ) ;
// close down Xerces if it was loaded
CXeromyces : : Terminate ( ) ;
// Unload the real language (since it depends on the scripting engine,
// which is going to be killed later) and use the English fallback messages
I18n : : LoadLanguage ( NULL ) ;
}
static void InitRenderer ( )
{
TIMER ( InitRenderer ) ;
// create renderer
new CRenderer ;
// set renderer options from command line options - NOVBO must be set before opening the renderer
g_Renderer . SetOptionBool ( CRenderer : : OPT_NOVBO , g_NoGLVBO ) ;
g_Renderer . SetOptionBool ( CRenderer : : OPT_SHADOWS , g_Shadows ) ;
g_Renderer . SetOptionBool ( CRenderer : : OPT_NOPBUFFER , g_NoPBuffer ) ;
g_Renderer . SetOptionFloat ( CRenderer : : OPT_LODBIAS , g_LodBias ) ;
// create terrain related stuff
new CTextureManager ;
// create the material manager
new CMaterialManager ;
new CMeshManager ;
// create actor related stuff
new CSkeletonAnimManager ;
new CObjectManager ;
new CUnitManager ;
MICROLOG ( L " init renderer " ) ;
g_Renderer . Open ( g_xres , g_yres , g_bpp ) ;
// Setup default lighting environment. Since the Renderer accesses the
// lighting environment through a pointer, this has to be done before
// the first Frame.
g_LightEnv . m_SunColor = RGBColor ( 1 , 1 , 1 ) ;
g_LightEnv . SetRotation ( DEGTORAD ( 270 ) ) ;
g_LightEnv . SetElevation ( DEGTORAD ( 45 ) ) ;
g_LightEnv . m_TerrainAmbientColor = RGBColor ( 0 , 0 , 0 ) ;
g_LightEnv . m_UnitsAmbientColor = RGBColor ( 0.4f , 0.4f , 0.4f ) ;
g_Renderer . SetLightEnv ( & g_LightEnv ) ;
// I haven't seen the camera affecting GUI rendering and such, but the
// viewport has to be updated according to the video mode
SViewPort vp ;
vp . m_X = 0 ;
vp . m_Y = 0 ;
vp . m_Width = g_xres ;
vp . m_Height = g_yres ;
g_Renderer . SetViewport ( vp ) ;
}
static void InitSDL ( )
{
MICROLOG ( L " init sdl " ) ;
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE ) < 0 )
{
LOG ( ERROR , LOG_CATEGORY , " SDL library initialization failed: %s " , SDL_GetError ( ) ) ;
throw PSERROR_System_SDLInitFailed ( ) ;
}
atexit ( SDL_Quit ) ;
SDL_EnableUNICODE ( 1 ) ;
}
2005-09-29 07:00:20 +02:00
static const uint SANE_TEX_QUALITY_DEFAULT = 5 ; // keep in sync with code
static void SetTextureQuality ( uint quality )
{
uint q_flags ;
GLint filter ;
retry :
// keep this in sync with SANE_TEX_QUALITY_DEFAULT
switch ( quality )
{
// worst quality
case 0 :
q_flags = OGL_TEX_HALF_RES | OGL_TEX_HALF_BPP ;
filter = GL_NEAREST ;
break ;
// [perf] add bilinear filtering
case 1 :
q_flags = OGL_TEX_HALF_RES | OGL_TEX_HALF_BPP ;
filter = GL_LINEAR ;
break ;
// [vmem] no longer reduce resolution
case 2 :
q_flags = OGL_TEX_HALF_BPP ;
filter = GL_LINEAR ;
break ;
// [vmem] add mipmaps
case 3 :
q_flags = OGL_TEX_HALF_BPP ;
filter = GL_NEAREST_MIPMAP_LINEAR ;
break ;
// [perf] better filtering
case 4 :
q_flags = OGL_TEX_HALF_BPP ;
filter = GL_LINEAR_MIPMAP_LINEAR ;
break ;
// [vmem] no longer reduce bpp
case SANE_TEX_QUALITY_DEFAULT :
q_flags = OGL_TEX_FULL_QUALITY ;
filter = GL_LINEAR_MIPMAP_LINEAR ;
break ;
// [perf] add anisotropy
case 6 :
// TODO: add anisotropic filtering
q_flags = OGL_TEX_FULL_QUALITY ;
filter = GL_LINEAR_MIPMAP_LINEAR ;
break ;
// invalid
default :
debug_warn ( " SetTextureQuality: invalid quality " ) ;
quality = SANE_TEX_QUALITY_DEFAULT ;
// careful: recursion doesn't work and we don't want to duplicate
// the "sane" default values.
goto retry ;
}
ogl_tex_set_defaults ( q_flags , filter ) ;
}
2005-08-15 01:34:37 +02:00
void EndGame ( )
{
if ( g_NetServer )
{
delete g_NetServer ;
g_NetServer = NULL ;
}
else if ( g_NetClient )
{
delete g_NetClient ;
g_NetClient = NULL ;
}
delete g_Game ;
g_Game = NULL ;
}
void Shutdown ( )
{
MICROLOG ( L " Shutdown " ) ;
ShutdownPs ( ) ; // Must delete g_GUI before g_ScriptingHost
if ( g_Game )
EndGame ( ) ;
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown Scheduler " ) ;
2005-08-15 01:34:37 +02:00
delete & g_Scheduler ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown Scheduler " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown SessionManager " ) ;
2005-08-15 01:34:37 +02:00
delete & g_SessionManager ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown SessionManager " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown mouse stuff " ) ;
2005-08-15 01:34:37 +02:00
delete & g_Mouseover ;
delete & g_Selection ;
2005-09-07 00:44:48 +02:00
delete & g_BuildingPlacer ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown mouse stuff " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown Pathfinder " ) ;
2005-08-15 01:34:37 +02:00
delete & g_Pathfinder ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown Pathfinder " ) ;
2005-09-07 00:44:48 +02:00
2005-08-15 01:34:37 +02:00
// Managed by CWorld
// delete &g_EntityManager;
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown scripting stuff " ) ;
2005-08-15 01:34:37 +02:00
delete & g_GameAttributes ;
delete & g_JSGameEvents ;
delete & g_EntityTemplateCollection ;
delete & g_ScriptingHost ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown scripting stuff " ) ;
2005-08-15 01:34:37 +02:00
// destroy actor related stuff
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown actor stuff " ) ;
2005-08-15 01:34:37 +02:00
delete & g_UnitMan ;
delete & g_ObjMan ;
delete & g_SkelAnimMan ;
delete & g_MaterialManager ;
delete & g_MeshManager ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown actor stuff " ) ;
2005-08-15 01:34:37 +02:00
// destroy terrain related stuff
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown TexMan " ) ;
2005-08-15 01:34:37 +02:00
delete & g_TexMan ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown TexMan " ) ;
2005-08-15 01:34:37 +02:00
// destroy renderer
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown Renderer " ) ;
2005-08-15 01:34:37 +02:00
delete & g_Renderer ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown Renderer " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown ConfigDB " ) ;
2005-08-15 01:34:37 +02:00
delete & g_ConfigDB ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown ConfigDB " ) ;
2005-08-15 01:34:37 +02:00
// Shut down the network loop
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown CSocketBase " ) ;
2005-08-15 01:34:37 +02:00
CSocketBase : : Shutdown ( ) ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown CSocketBase " ) ;
2005-08-15 01:34:37 +02:00
// Really shut down the i18n system. Any future calls
// to translate() will crash.
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown I18N " ) ;
2005-08-15 01:34:37 +02:00
I18n : : Shutdown ( ) ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown I18N " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown sound " ) ;
2005-08-15 01:34:37 +02:00
snd_shutdown ( ) ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown sound " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown vfs " ) ;
2005-08-15 01:34:37 +02:00
vfs_shutdown ( ) ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown vfs " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 04:30:30 +02:00
TIMER_START ( " shutdown misc " ) ;
2005-08-15 01:34:37 +02:00
h_mgr_shutdown ( ) ;
mem_shutdown ( ) ;
debug_shutdown ( ) ;
delete & g_Logger ;
delete & g_Profiler ;
2005-09-29 04:30:30 +02:00
TIMER_END ( " shutdown misc " ) ;
2005-08-15 01:34:37 +02:00
}
// workaround for VC7 EBP-trashing bug, which confuses the stack trace code.
# if MSC_VERSION
# pragma optimize("", off)
# endif
2005-08-20 17:44:50 +02:00
void Init ( int argc , char * argv [ ] , bool setup_gfx , bool setup_gui )
2005-08-15 01:34:37 +02:00
{
debug_printf ( " INIT &argc=%p &argv=%p \n " , & argc , & argv ) ;
MICROLOG ( L " Init " ) ;
debug_set_thread_name ( " main " ) ;
2005-09-20 06:05:23 +02:00
# if CPU_IA32
ia32_init ( ) ;
# endif
2005-08-15 01:34:37 +02:00
// If you ever want to catch a particular allocation:
//_CrtSetBreakAlloc(187);
// no longer set 24 bit (float) precision by default: for
// very long game uptimes (> 1 day; e.g. dedicated server),
// we need full precision when calculating the time.
// if there's a spot where we want to speed up divides|sqrts,
// we can temporarily change precision there.
// _control87(_PC_24, _MCW_PC);
// detects CPU clock frequency and capabilities, which are prerequisites
// for using the TSC as a timer (desirable due to its high resolution).
// do this before lengthy init so we can time those accurately.
get_cpu_info ( ) ;
// Do this as soon as possible, because it chdirs
// and will mess up the error reporting if anything
// crashes before the working directory is set.
MICROLOG ( L " init vfs " ) ;
const char * argv0 = argc ? argv [ 0 ] : NULL ;
// ScEd doesn't have a main(argc, argv), and so it has no argv. In that
// case, just pass NULL to InitVfs, which will work out the current
// directory for itself.
InitVfs ( argv0 ) ;
// This must come after VFS init, which sets the current directory
// (required for finding our output log files).
new CLogger ;
// Call LoadLanguage(NULL) to initialise the I18n system, but
// without loading an actual language file - translate() will
// just show the English key text, which is better than crashing
// from a null pointer when attempting to translate e.g. error messages.
// Real languages can only be loaded when the scripting system has
// been initialised.
//
// this uses LOG and must therefore come after CLogger init.
MICROLOG ( L " init i18n " ) ;
I18n : : LoadLanguage ( NULL ) ;
// Set up the console early, so that debugging
// messages can be logged to it. (The console's size
// and fonts are set later in InitPs())
g_Console = new CConsole ( ) ;
if ( setup_gfx )
InitSDL ( ) ;
// preferred video mode = current desktop settings
// (command line params may override these)
get_cur_vmode ( & g_xres , & g_yres , & g_bpp , & g_freq ) ;
new CProfileManager ; // before any script code
MICROLOG ( L " init scripting " ) ;
InitScripting ( ) ; // before GUI
// g_ConfigDB, command line args, globals
CONFIG_Init ( argc , argv ) ;
// GUI is notified in SetVideoMode, so this must come before that.
# ifndef NO_GUI
new CGUI ;
# endif
bool windowed = false ;
CFG_GET_SYS_VAL ( " windowed " , Bool , windowed ) ;
if ( setup_gfx )
{
2005-09-29 07:00:20 +02:00
SDL_WM_SetCaption ( " 0 A.D. " , " 0 A.D. " ) ;
2005-08-15 01:34:37 +02:00
2005-09-29 07:00:20 +02:00
MICROLOG ( L " SetVideoMode " ) ;
2005-08-15 01:34:37 +02:00
if ( SetVideoMode ( g_xres , g_yres , 32 , ! windowed ) < 0 )
{
LOG ( ERROR , LOG_CATEGORY , " Could not set %dx%d graphics mode: %s " , g_xres , g_yres , SDL_GetError ( ) ) ;
throw PSERROR_System_VmodeFailed ( ) ;
}
2005-09-29 07:00:20 +02:00
uint quality = SANE_TEX_QUALITY_DEFAULT ; // TODO: set value from config file
SetTextureQuality ( quality ) ;
2005-08-15 01:34:37 +02:00
}
oglCheck ( ) ;
if ( ! g_Quickstart )
{
WriteSystemInfo ( ) ;
2005-08-20 17:44:50 +02:00
// vfs_display(); // disabled to decrease startup time
2005-08-15 01:34:37 +02:00
}
else
{
// speed up startup by disabling all sound
// (OpenAL init will be skipped).
// must be called before first snd_open.
snd_disable ( true ) ;
}
// (must come after SetVideoMode, since it calls oglInit)
const char * missing = oglHaveExtensions ( 0 , " GL_ARB_multitexture " , " GL_ARB_texture_env_combine " , " GL_ARB_texture_env_dot3 " , 0 ) ;
if ( missing )
{
wchar_t buf [ 500 ] ;
const wchar_t * fmt =
L " The %hs extension doesn't appear to be available on your computer. "
L " The game may still work, though - you are welcome to try at your own risk. "
L " If not or it doesn't look right, upgrade your graphics card. " ;
swprintf ( buf , ARRAY_SIZE ( buf ) , fmt , missing ) ;
DISPLAY_ERROR ( buf ) ;
// TODO: i18n
}
// enable/disable VSync
// note: "GL_EXT_SWAP_CONTROL" is "historical" according to dox.
# if OS_WIN
if ( oglHaveExtension ( " WGL_EXT_swap_control " ) )
wglSwapIntervalEXT ( g_VSync ? 1 : 0 ) ;
# endif
MICROLOG ( L " init ps " ) ;
2005-08-20 17:44:50 +02:00
InitPs ( setup_gui ) ;
2005-08-15 01:34:37 +02:00
oglCheck ( ) ;
InitRenderer ( ) ;
TIMER ( init_after_InitRenderer ) ;
// This needs to be done after the renderer has loaded all its actors...
new CBaseEntityCollection ;
// CEntityManager is managed by CWorld
//new CEntityManager;
new CPathfindEngine ;
new CSelectedEntities ;
new CMouseoverEntities ;
2005-09-05 21:48:28 +02:00
new CBuildingPlacer ;
2005-08-15 01:34:37 +02:00
new CSessionManager ;
new CGameAttributes ;
// Register a few Game/Network JS globals
g_ScriptingHost . SetGlobal ( " g_GameAttributes " , OBJECT_TO_JSVAL ( g_GameAttributes . GetScript ( ) ) ) ;
// Check for heap corruption after every allocation. Very, very slowly.
// (And it highlights the allocation just after the one you care about,
// so you need to run it again and tell it to break on the one before.)
// debug_heap_enable(DEBUG_HEAP_ALL);
InitInput ( ) ;
oglCheck ( ) ;
# ifndef NO_GUI
g_GUI . SendEventToAll ( " load " ) ;
# endif
if ( setup_gfx )
{
MICROLOG ( L " render blank " ) ;
// render everything to a blank frame to force renderer to load everything
RenderNoCull ( ) ;
}
if ( g_FixedFrameTiming ) {
CCamera & g_Camera = * g_Game - > GetView ( ) - > GetCamera ( ) ;
#if 0 // TOPDOWN
g_Camera . SetProjection ( 1.0f , 10000.0f , DEGTORAD ( 90 ) ) ;
g_Camera . m_Orientation . SetIdentity ( ) ;
g_Camera . m_Orientation . RotateX ( DEGTORAD ( 90 ) ) ;
g_Camera . m_Orientation . Translate ( CELL_SIZE * 250 * 0.5 , 250 , CELL_SIZE * 250 * 0.5 ) ;
# else // std view
g_Camera . SetProjection ( 1.0f , 10000.0f , DEGTORAD ( 20 ) ) ;
g_Camera . m_Orientation . SetXRotation ( DEGTORAD ( 30 ) ) ;
g_Camera . m_Orientation . RotateY ( DEGTORAD ( - 45 ) ) ;
g_Camera . m_Orientation . Translate ( 350 , 350 , - 275 ) ;
# endif
g_Camera . UpdateFrustum ( ) ;
}
}
# if MSC_VERSION
# pragma optimize("", on) // restore; see above.
# endif