diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 5aa9dc6a27..e4ca912cfc 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -490,7 +490,7 @@ Just commented out to make it more obvious it's not in use. CVector3D rightwards = upwards.Cross(forwards); // Click and drag to look around - if (mouseButtons[0]) + if (mouse_buttons[0]) { // Untranslate the camera, so it rotates around the correct point CVector3D position = m_Camera.m_Orientation.GetTranslation(); @@ -532,9 +532,9 @@ Just commented out to make it more obvious it's not in use. static float height_delta = 0.0f; - if (mouseButtons[SDL_BUTTON_WHEELUP]) + if (mouse_buttons[SDL_BUTTON_WHEELUP]) height_delta -= 4.0f; - else if (mouseButtons[SDL_BUTTON_WHEELDOWN]) + else if (mouse_buttons[SDL_BUTTON_WHEELDOWN]) height_delta += 4.0f; const float height_speed = 0.2f; @@ -566,8 +566,8 @@ Just commented out to make it more obvious it's not in use. // RC - added ScEd style zoom in and out (actually moving camera, rather than fudging fov) float dir=0; - if (mouseButtons[SDL_BUTTON_WHEELUP]) dir=-1; - else if (mouseButtons[SDL_BUTTON_WHEELDOWN]) dir=1; + if (mouse_buttons[SDL_BUTTON_WHEELUP]) dir=-1; + else if (mouse_buttons[SDL_BUTTON_WHEELDOWN]) dir=1; float factor=dir*dir; if (factor) { diff --git a/source/graphics/GameView.h b/source/graphics/GameView.h index a76a061537..3966ae6be5 100755 --- a/source/graphics/GameView.h +++ b/source/graphics/GameView.h @@ -6,6 +6,11 @@ #include "scripting/ScriptableObject.h" +// note: cannot forward declare "struct SDL_Event" - that triggers an +// internal error in VC7.1 at msc1.cpp(2701). +// we include the full header instead. *sigh* +#include "sdl.h" + class CGame; class CGameAttributes; class CWorld; @@ -97,4 +102,6 @@ public: { return &m_Camera; } }; +extern int game_view_handler(const SDL_Event* ev); + #endif diff --git a/source/gui/CInput.cpp b/source/gui/CInput.cpp index 818cb5091d..43810bd882 100755 --- a/source/gui/CInput.cpp +++ b/source/gui/CInput.cpp @@ -21,7 +21,7 @@ gee@pyro.nu #define LOG_CATEGORY "gui" extern bool keys[SDLK_LAST]; -extern bool mouseButtons[5]; +extern bool mouse_buttons[5]; using namespace std; @@ -562,7 +562,7 @@ void CInput::HandleMessage(const SGUIMessage &Message) { // Actually, first we need to re-check that the mouse button is // really pressed (it can be released while outside the control. - if (!mouseButtons[SDL_BUTTON_LEFT]) + if (!mouse_buttons[SDL_BUTTON_LEFT]) m_SelectingText = false; else m_iBufferPos = GetMouseHoveringTextPosition(); diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp index 6a17d7645b..9e7c0aa52c 100755 --- a/source/gui/MiniMap.cpp +++ b/source/gui/MiniMap.cpp @@ -15,7 +15,7 @@ -extern bool mouseButtons[5]; +extern bool mouse_buttons[5]; extern int g_mouse_x, g_mouse_y; bool HasClicked=false; @@ -124,13 +124,13 @@ void CMiniMap::Draw() CCamera &g_Camera=*g_Game->GetView()->GetCamera(); //Check for a click - if(mouseButtons[0]==true) + if(mouse_buttons[0]==true) { HasClicked=true; } //Check to see if left button is false (meaning it's been lifted) - if (mouseButtons[0]==false && HasClicked==true) + if (mouse_buttons[0]==false && HasClicked==true) { diff --git a/source/lib/input.cpp b/source/lib/input.cpp index 51b3944626..493b111cea 100755 --- a/source/lib/input.cpp +++ b/source/lib/input.cpp @@ -49,7 +49,7 @@ int in_add_handler(EventHandler handler) // send event to each handler (newest first) until one returns true -static void dispatch_event(const SDL_Event* event) +void dispatch_event(const SDL_Event* event) { for(int i = handler_stack_top-1; i >= 0; i--) { @@ -140,7 +140,20 @@ int in_playback(const char* fn) } -void in_get_events() + +void in_dispatch_event(const SDL_Event* event) +{ + if(state == RECORD) + { + fwrite(&game_ticks, sizeof(u32), 1, f); + fwrite(event, sizeof(SDL_Event), 1, f); + } + + dispatch_event(event); +} + + +void in_dispatch_recorded_events() { SDL_Event event; @@ -158,22 +171,6 @@ exit(0x73c07d); } next_event_time += time_adjust; - dispatch_event(&event); - } - - // get new events - while(SDL_PollEvent(&event)) - { - if(state == RECORD) - { - fwrite(&game_ticks, sizeof(u32), 1, f); - fwrite(&event, sizeof(SDL_Event), 1, f); - } - - if(state == PLAYBACK) - if(event.type == SDL_KEYDOWN) - in_stop(); - - dispatch_event(&event); + in_dispatch_event(&event); } } diff --git a/source/lib/input.h b/source/lib/input.h index 0f14d24366..ca7b16ec2c 100755 --- a/source/lib/input.h +++ b/source/lib/input.h @@ -49,7 +49,10 @@ typedef int (*EventHandler)(const SDL_Event*); // events are passed to other handlers if handler returns EV_PASS. extern int in_add_handler(EventHandler handler); -extern void in_get_events(void); +// send event to each handler (newest first) until one returns true +extern void in_dispatch_event(const SDL_Event* event); + +extern void in_dispatch_recorded_events(); extern int in_record(const char* fn); extern int in_playback(const char* fn); diff --git a/source/main.cpp b/source/main.cpp index d4ea8247da..25d0dfec60 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,3 +1,14 @@ +/* + +This module drives the game when running without Atlas (our integrated +map editor). It receives input and OS messages via SDL and feeds them +into the input dispatcher, where they are passed on to the game GUI and +simulation. +It also contains main(), which either runs the above controller or +that of Atlas depending on commandline parameters. + +*/ + #include "precompiled.h" #ifdef SCED @@ -5,693 +16,48 @@ # undef ERROR #endif // SCED -#include -#include -#include -#include -#include - -#include "lib.h" -#include "lib/sdl.h" -#include "lib/ogl.h" -#include "lib/detect.h" -#include "lib/timer.h" #include "lib/input.h" -#include "lib/res/res.h" +#include "lib/sdl.h" +#include "lib/timer.h" +#include "lib/res/file/vfs.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/GameSetup/GameSetup.h" +#include "ps/GameSetup/Atlas.h" +#include "ps/GameSetup/Config.h" #include "ps/Loader.h" -#include "ps/Font.h" +#include "gui/GUI.h" #include "ps/CConsole.h" +#include "ps/Profile.h" +#include "ps/System.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" - -#include "simulation/BaseEntityCollection.h" -#include "simulation/Entity.h" -#include "simulation/EntityHandles.h" -#include "simulation/EntityManager.h" -#include "simulation/PathfindEngine.h" +#include "ps/Interact.h" +#include "ps/Network/SessionManager.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" - - - #define LOG_CATEGORY "main" -extern int conInputHandler(const SDL_Event* ev); -// Globals +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void kill_mainloop(); +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + +// +// main app message handler +// bool keys[SDLK_LAST]; -bool mouseButtons[5]; -int g_mouse_x=50, g_mouse_y=50; +bool mouse_buttons[5]; // CAN REMOVE AFTER MOVING RESET TO WSDL -int g_xres, g_yres; -int g_bpp; -int g_freq; bool g_active = true; +int g_mouse_x = 50, g_mouse_y = 50; -// flag to disable extended GL extensions until fix found - specifically, crashes -// using VBOs on laptop Radeon cards -static bool g_NoGLVBO=false; -// flag to switch on shadows -static bool g_Shadows=false; -// flag to switch off pbuffers -static bool g_NoPBuffer=true; -// flag to switch on fixed frame timing (RC: I'm using this for profiling purposes) -static bool g_FixedFrameTiming=false; -static bool g_VSync = false; -static float g_LodBias = 0.0f; - -static bool g_Quickstart=false; - -extern CLightEnv g_LightEnv; - -static bool g_EntGraph = false; - -static float g_Gamma = 1.0f; - -extern int game_view_handler(const SDL_Event* ev); - -static CMusicPlayer MusicPlayer; - -CStr g_CursorName = "test"; -CStr g_ActiveProfile = "default"; - -extern size_t frameCount; -static bool quit = false; // break out of main loop - - -const wchar_t* HardcodedErrorString(int err) -{ -#define E(sym) case sym: return L ## #sym; - - switch(err) - { - E(ERR_NO_MEM) - E(ERR_FILE_NOT_FOUND) - E(ERR_INVALID_HANDLE) - E(ERR_INVALID_PARAM) - E(ERR_EOF) - E(ERR_PATH_NOT_FOUND) - E(ERR_PATH_LENGTH) - default: - return 0; - } -} - -const wchar_t* ErrorString(int err) -{ - // language file not available (yet) - return HardcodedErrorString(err); - - // TODO: load from language file -} - - -ERROR_GROUP(System); -ERROR_TYPE(System, SDLInitFailed); -ERROR_TYPE(System, VmodeFailed); -ERROR_TYPE(System, RequiredExtensionsMissing); - - -//---------------------------------------------------------------------------- -// Atlas (map editor) integration -//---------------------------------------------------------------------------- - -static void* const ATLAS_SO_UNAVAILABLE = (void*)-1; -static void* atlas_so_handle; - - -// free reference to Atlas UI SO (avoids resource leak report) -static void ATLAS_Shutdown() -{ - // (avoid dlclose warnings) - if(atlas_so_handle != 0 && atlas_so_handle != ATLAS_SO_UNAVAILABLE) - dlclose(atlas_so_handle); -} - - -// return true if the Atlas UI shared object is available; -// used to disable the main menu editor button if not. -// note: this actually loads the SO, but that isn't expected to be slow. -// call ATLAS_Shutdown at exit to avoid leaking it. -static bool ATLAS_IsAvailable() -{ - // first time: try to open Atlas UI shared object - // postcondition: atlas_so_handle valid or == ATLAS_SO_UNAVAILABLE. - if(atlas_so_handle == 0) - { - // since this SO exports a C++ interface, it is critical that - // compiler options are the same between app and SO; therefore, - // we need to go with the debug version in debug builds. - // note: on Windows, the extension is replaced with .dll by dlopen. -#ifndef NDEBUG - const char* so_name = "AtlasUI_d.so"; -#else - const char* so_name = "AtlasUI.so"; -#endif - // we don't care when relocations take place because this SO contains - // very few symbols, so RTLD_LAZY or RTLD_NOW aren't needed. - const int flags = RTLD_LOCAL; - atlas_so_handle = dlopen(so_name, flags); - // open failed (mostly likely SO not found) - if(!atlas_so_handle) - atlas_so_handle = ATLAS_SO_UNAVAILABLE; - } - - return atlas_so_handle != ATLAS_SO_UNAVAILABLE; -} - - -static bool atlas_is_running; - -// if Atlas is running, some parts of the GUI need not be loaded -// (reduces startup time). -static bool ATLAS_IsRunning() -{ - return atlas_is_running; -} - - -enum AtlasRunFlags -{ - // used by ATLAS_RunIfOnCmdLine; makes any error output go through - // DISPLAY_ERROR rather than a GUI dialog box (because GUI init was - // skipped to reduce load time). - ATLAS_NO_GUI = 1 -}; - -// starts the Atlas UI. -static void ATLAS_Run(int argc, char* argv[], int flags = 0) -{ - // first check if we can run at all - if(!ATLAS_IsAvailable()) - { - if(flags & ATLAS_NO_GUI) - DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested."); - else - DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested.");// TODO: implement GUI error message - return; - } - - void(*pStartWindow)(int argc, char* argv[]); - *(void**)&pStartWindow = dlsym(atlas_so_handle, "_StartWindow"); - pStartWindow(argc, argv); - - atlas_is_running = true; -} - - -// starts the Atlas UI if an "-editor" switch is found on the command line. -// this is the alternative to starting the main menu and clicking on -// the editor button; it is much faster because it's called during early -// init and therefore skips GUI setup. -// notes: -// - GUI init still runs, but some GUI setup will be skipped since -// ATLAS_IsRunning() will return true. -// - could be merged into CFG_ParseCommandLineArgs, because that appears -// to be called early enough. it's not really worth it because this -// code is quite simple and we thus avoid startup order dependency. -static void ATLAS_RunIfOnCmdLine(int argc, char* argv[]) -{ - for(int i = 1; i < argc; i++) // skip program name argument - { - if(!strcmp(argv[i], "-editor")) - { - // don't bother removing this param (unnecessary) - - ATLAS_Run(argc, argv, ATLAS_NO_GUI); - break; - } - } -} - - -//---------------------------------------------------------------------------- -// GUI integration -//---------------------------------------------------------------------------- - - -static 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 -} - - -static void GUI_Shutdown() -{ -#ifndef NO_GUI - g_GUI.Destroy(); - delete &g_GUI; -#endif -} - - -// display progress / description in loading screen -static 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 -} - - -//---------------------------------------------------------------------------- -// config and profile -//---------------------------------------------------------------------------- - -static void CFG_LoadProfile( CStr profile ) -{ - CStr base = CStr( "profiles/" ) + profile; - g_ConfigDB.SetConfigFile(CFG_USER, true, base + "/settings/user.cfg"); - g_ConfigDB.Reload(CFG_USER); - - int max_history_lines = 50; - CFG_GET_USER_VAL("console.history.size", Int, max_history_lines); - g_Console->UseHistoryFile(base+"/settings/history", max_history_lines); -} - - -// Fill in the globals from the config files. -static void CFG_LoadGlobals() -{ - CFG_GET_SYS_VAL("profile", String, g_ActiveProfile); - - // Now load the profile before trying to retrieve the values of the rest of these. - - CFG_LoadProfile( g_ActiveProfile ); - - CFG_GET_USER_VAL("xres", Int, g_xres); - CFG_GET_USER_VAL("yres", Int, g_yres); - - CFG_GET_USER_VAL("vsync", Bool, g_VSync); - CFG_GET_USER_VAL("novbo", Bool, g_NoGLVBO); - CFG_GET_USER_VAL("shadows", Bool, g_Shadows); - - CFG_GET_USER_VAL("lodbias", Float, g_LodBias); - - float gain = -1.0f; - CFG_GET_USER_VAL("sound.mastergain", Float, gain); - if(gain > 0.0f) - WARN_ERR(snd_set_master_gain(gain)); - - LOG(NORMAL, LOG_CATEGORY, "g_x/yres is %dx%d", g_xres, g_yres); - LOG(NORMAL, LOG_CATEGORY, "Active profile is %s", g_ActiveProfile.c_str()); -} - - -static void CFG_ParseCommandLineArgs(int argc, char* argv[]) -{ - for(int i = 1; i < argc; i++) - { - // this arg isn't an option; skip - if(argv[i][0] != '-') - continue; - - char* name = argv[i]+1; // no leading '-' - - // switch first letter of option name - switch(argv[i][1]) - { - case 'c': - if(strcmp(name, "conf") == 0) - { - if(argc-i >= 1) // at least one arg left - { - i++; - char* arg = argv[i]; - char* equ = strchr(arg, '='); - if(equ) - { - *equ = 0; - g_ConfigDB.CreateValue(CFG_COMMAND, arg) - ->m_String = (equ+1); - } - } - } - break; - case 'e': - g_EntGraph = true; - break; - case 'f': - if(strncmp(name, "fixedframe", 10) == 0) - g_FixedFrameTiming=true; - break; - case 'g': - if(strncmp(name, "g=", 2) == 0) - { - g_Gamma = (float)atof(argv[i] + 3); - if(g_Gamma == 0.0f) - g_Gamma = 1.0f; - } - break; - case 'l': - if(strncmp(name, "listfiles", 9) == 0) - vfs_enable_file_listing(true); - break; - case 'n': - if(strncmp(name, "novbo", 5) == 0) - g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String="true"; - else if(strncmp(name, "nopbuffer", 9) == 0) - g_NoPBuffer = true; - break; - case 'q': - if(strncmp(name, "quickstart", 10) == 0) - g_Quickstart = true; - break; - case 's': - if(strncmp(name, "shadows", 7) == 0) - g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String="true"; - break; - case 'v': - g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String="true"; - break; - case 'x': - if(strncmp(name, "xres=", 6) == 0) - g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String=argv[i]+6; - break; - case 'y': - if(strncmp(name, "yres=", 6) == 0) - g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String=argv[i]+6; - break; - case 'p': - if(strncmp(name, "profile=", 8) == 0 ) - g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = argv[i]+9; - break; - } // switch - } -} - - -static void CFG_Init(int argc, char* argv[]) -{ - debug_printf("CFG_Init &argc=%p &argv=%p\n", &argc, &argv); - - TIMER(CFG_Init); - MICROLOG(L"init config"); - - new CConfigDB; - - g_ConfigDB.SetConfigFile(CFG_SYSTEM, false, "config/system.cfg"); - g_ConfigDB.Reload(CFG_SYSTEM); - - g_ConfigDB.SetConfigFile(CFG_MOD, true, "config/mod.cfg"); - // No point in reloading mod.cfg here - we haven't mounted mods yet - - CFG_ParseCommandLineArgs(argc, argv); - - // Collect information from system.cfg, the profile file, - // and any command-line overrides to fill in the globals. - CFG_LoadGlobals(); -} - -//---------------------------------------------------------------------------- - - - - -static std::string SplitExts(const char *exts) -{ - std::string str = exts; - std::string ret = ""; - size_t idx = str.find_first_of(" "); - while(idx != std::string::npos) - { - if(idx >= str.length() - 1) - { - ret += str; - break; - } - - ret += str.substr(0, idx); - ret += "\n"; - str = str.substr(idx + 1); - idx = str.find_first_of(" "); - } - - return ret; -} - - -static void WriteSystemInfo() -{ -TIMER(write_sys_info); - - get_gfx_info(); - // get_cpu_info already called during init - see call site - get_snd_info(); - get_mem_status(); - - struct utsname un; - uname(&un); - - FILE* f = fopen("../logs/system_info.txt", "w"); - if(!f) - return; - - // .. OS - fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version); - - // .. CPU - fprintf(f, "CPU : %s, %s", un.machine, cpu_type); - if(cpus > 1) - fprintf(f, " (x%d)", cpus); - if(cpu_freq != 0.0f) - { - if(cpu_freq < 1e9) - fprintf(f, ", %.2f MHz\n", cpu_freq*1e-6); - else - fprintf(f, ", %.2f GHz\n", cpu_freq*1e-9); - } - else - fprintf(f, "\n"); - - // .. memory - fprintf(f, "Memory : %lu MiB; %lu MiB free\n", tot_mem/MiB, avl_mem/MiB); - - // .. graphics - fprintf(f, "Graphics Card : %s\n", gfx_card); - fprintf(f, "OpenGL Drivers : %s; %s\n", glGetString(GL_VERSION), gfx_drv_ver); - fprintf(f, "Video Mode : %dx%d:%d@%d\n", g_xres, g_yres, g_bpp, g_freq); - - // .. sound - fprintf(f, "Sound Card : %s\n", snd_card); - fprintf(f, "Sound Drivers : %s\n", snd_drv_ver); - - - // - // .. network name / ips - // - - // note: can't use un.nodename because it is for an - // "implementation-defined communications network". - char hostname[128] = "(unknown)"; - (void)gethostname(hostname, sizeof(hostname)-1); - // -1 makes sure it's 0-terminated. if the function fails, - // we display "(unknown)" and will skip IP output below. - fprintf(f, "Network Name : %s", hostname); - - { - hostent* host = gethostbyname(hostname); - if(!host) - goto no_ip; - struct in_addr** ips = (struct in_addr**)host->h_addr_list; - if(!ips) - goto no_ip; - - // output all IPs (> 1 if using VMware or dual ethernet) - fprintf(f, " ("); - for(uint i = 0; i < 256 && ips[i]; i++) // safety - { - // separate entries but avoid trailing comma - if(i != 0) - fprintf(f, ", "); - fprintf(f, "%s", inet_ntoa(*ips[i])); - } - fprintf(f, ")"); - } - -no_ip: - fprintf(f, "\n"); - - - // .. OpenGL extensions (write them last, since it's a lot of text) - const char* exts = oglExtList(); - if (!exts) exts = "{unknown}"; - fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str()); - - fclose(f); - f = 0; -} - - -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; -} - - -// identifies the file format that is to be written -// (case-insensitive). examples: "bmp", "png", "jpg". -// BMP is good for quick output at the expense of large files. -static void WriteScreenshot(const char* extension = "png") -{ - // determine next screenshot number. - // - // current approach: increment number until that file doesn't yet exist. - // this is fairly slow, but it's typically only done once, since the last - // number is cached. binary search shouldn't be necessary. - // - // known bug: after program restart, holes in the number series are - // filled first. example: add 1st and 2nd; [exit] delete 1st; [restart] - // add 3rd -> it gets number 1, not 3. - // could fix via enumerating all files, but it's not worth it ATM. - char fn[VFS_MAX_PATH]; - - const char* file_format_string = "screenshots/screenshot%04d.%s"; - // %04d -> always 4 digits, so sorting by filename works correctly. - - static int next_num = 1; - do - sprintf(fn, file_format_string, next_num++, extension); - while(vfs_exists(fn)); - - const int w = g_xres, h = g_yres; - const int bpp = 24; - GLenum fmt = GL_RGB; - int flags = TEX_BOTTOM_UP; - // we want writing BMP to be as fast as possible, - // so read data from OpenGL in BMP format to obviate conversion. - if(!stricmp(extension, "bmp")) - { - fmt = GL_BGR; - flags |= TEX_BGR; - } - - const size_t size = w * h * bpp; - void* img = mem_alloc(size); - - glReadPixels(0, 0, w, h, fmt, GL_UNSIGNED_BYTE, img); - - if(tex_write(fn, w, h, bpp, flags, img) < 0) - debug_warn("WriteScreenshot: tex_write failed"); - - mem_free(img); -} - - - -// HACK: Let code from other files (i.e. the scripting system) quit -void kill_mainloop() -{ - quit = true; -} static int MainInputHandler(const SDL_Event* ev) { @@ -700,7 +66,22 @@ static int MainInputHandler(const SDL_Event* ev) switch(ev->type) { case SDL_ACTIVEEVENT: - g_active = ev->active.gain != 0; + g_active = (ev->active.gain != 0); + break; + + case SDL_KEYDOWN: + case SDL_KEYUP: + c = ev->key.keysym.sym; + keys[c] = (ev->type == SDL_KEYDOWN); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + c = ev->button.button; + if(c < ARRAY_SIZE(mouse_buttons)) + mouse_buttons[c] = (ev->type == SDL_MOUSEBUTTONDOWN); + else + debug_warn("MainInputHandler: invalid mouse button"); break; case SDL_MOUSEMOTION: @@ -708,471 +89,40 @@ static int MainInputHandler(const SDL_Event* ev) g_mouse_y = ev->motion.y; break; - case SDL_KEYDOWN: - c = ev->key.keysym.sym; - keys[c] = true; - break; - case SDL_HOTKEYDOWN: - - switch( ev->user.code ) + switch(ev->user.code) { case HOTKEY_EXIT: - quit = true; + kill_mainloop(); break; case HOTKEY_SCREENSHOT: - WriteScreenshot(); + WriteScreenshot("png"); break; case HOTKEY_PLAYMUSIC: - { -// MusicPlayer.open("audio/music/germanic peace 3.ogg"); -// MusicPlayer.play(); - Handle hs = snd_open( - //"audio/music/germanic peace 3.ogg" - "audio/voice/hellenes/soldier/Attack-ZeusSaviourandVictory.ogg" - ); - - - snd_set_pos(hs, 0,0,0, true); - snd_play(hs); - } break; default: - return( EV_PASS ); + return EV_PASS; } - return( EV_HANDLED ); - - case SDL_KEYUP: - c = ev->key.keysym.sym; - keys[c] = false; - break; - case SDL_MOUSEBUTTONDOWN: - c = ev->button.button; - if( c < 5 ) - mouseButtons[c] = true; - else - debug_warn("SDL mouse button defs changed; fix mouseButton array def"); - break; - case SDL_MOUSEBUTTONUP: - c = ev->button.button; - if( c < 5 ) - mouseButtons[c] = false; - else - debug_warn("SDL mouse button defs changed; fix mouseButton array def"); - break; + return EV_HANDLED; } return EV_PASS; } -void EndGame() +// dispatch all pending events to the various receivers. +static void PumpEvents() { - if (g_NetServer) - { - delete g_NetServer; - g_NetServer=NULL; - } - else if (g_NetClient) - { - delete g_NetClient; - g_NetClient=NULL; - } + in_dispatch_recorded_events(); - delete g_Game; - g_Game=NULL; + SDL_Event event; + while(SDL_PollEvent(&event)) + in_dispatch_event(&event); } -///////////////////////////////////////////////////////////////////////////////////////////// -// 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(); -} - - -static 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::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" ); - g_Mouseover.renderSelectionOutlines(); - g_Selection.renderSelectionOutlines(); - PROFILE_END( "render selection" ); - - 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) - cursor_draw(g_CursorName, g_mouse_x, g_mouse_y); - - // 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::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor 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"); - if(err < 0) - throw 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); - } -extern void vfs_dump_stats(); -vfs_dump_stats(); - // don't try vfs_display yet: SDL_Init hasn't yet redirected stdout -} - - -static void InitPs() -{ - // 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. - GUI_Init(); -} - - -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); - - // gui_handler needs to be after (i.e. called before!) the hotkey handler - // so that input boxes can be typed in without setting off hotkeys. -#ifndef NO_GUI - in_add_handler(gui_handler); -#endif - - // must be after gui_handler. Should mayhap even be last. - in_add_handler(MainInputHandler); -} - - -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(); - - MusicPlayer.release(); - - // 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); -} static int ProgressiveLoad() @@ -1182,24 +132,24 @@ static int ProgressiveLoad() int ret = LDR_ProgressiveLoad(10e-3, description, ARRAY_SIZE(description), &progress_percent); switch(ret) { - // no load active => no-op (skip code below) + // no load active => no-op (skip code below) case 0: return 0; - // current task didn't complete. we only care about this insofar as the - // load process is therefore not yet finished. + // current task didn't complete. we only care about this insofar as the + // load process is therefore not yet finished. case ERR_TIMED_OUT: break; - // just finished loading + // just finished loading case LDR_ALL_FINISHED: g_Game->ReallyStartGame(); wcscpy_s(description, ARRAY_SIZE(description), L"Game is starting.."); - // LDR_ProgressiveLoad returns L""; set to valid text to - // avoid problems in converting to JSString + // LDR_ProgressiveLoad returns L""; set to valid text to + // avoid problems in converting to JSString break; - // error! + // error! default: CHECK_ERR(ret); - // can't do this above due to legit ERR_TIMED_OUT + // can't do this above due to legit ERR_TIMED_OUT break; } @@ -1207,282 +157,15 @@ static int ProgressiveLoad() return 0; } - - -static void Shutdown() -{ - MICROLOG(L"Shutdown"); - - ATLAS_Shutdown(); - - ShutdownPs(); // Must delete g_GUI before g_ScriptingHost - - if (g_Game) - EndGame(); - - delete &g_Scheduler; - - delete &g_SessionManager; - - delete &g_Mouseover; - delete &g_Selection; - - delete &g_Pathfinder; - // Managed by CWorld - // delete &g_EntityManager; - - delete &g_GameAttributes; - delete &g_JSGameEvents; - - delete &g_EntityTemplateCollection; - - delete &g_ScriptingHost; - - // destroy actor related stuff - delete &g_UnitMan; - delete &g_ObjMan; - delete &g_SkelAnimMan; - - delete &g_MaterialManager; - delete &g_MeshManager; - - // destroy terrain related stuff - delete &g_TexMan; - - // destroy renderer - delete &g_Renderer; - - delete &g_ConfigDB; - - // Shut down the network loop - CSocketBase::Shutdown(); - - // Really shut down the i18n system. Any future calls - // to translate() will crash. - I18n::Shutdown(); - - snd_shutdown(); - - vfs_shutdown(); - - h_mgr_shutdown(); - mem_shutdown(); - - debug_shutdown(); - - delete &g_Logger; - - delete &g_Profiler; -} - - -// workaround for VC7 EBP-trashing bug, which confuses the stack trace code. -#if MSC_VERSION -# pragma optimize("", off) -#endif - -static void Init(int argc, char* argv[], bool setup_gfx = true) -{ -debug_printf("INIT &argc=%p &argv=%p\n", &argc, &argv); - - MICROLOG(L"Init"); - - debug_set_thread_name("main"); - - // 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); - - // should be done before the bulk of GUI init because it prevents - // most loads from happening (since ATLAS_IsRunning will return true). - ATLAS_RunIfOnCmdLine(argc, argv); - - // 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 - CFG_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) - { - MICROLOG(L"set vmode"); - - 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(); - } - SDL_WM_SetCaption("0 A.D.", "0 A.D."); - } - - oglCheck(); - - if(!g_Quickstart) - { - WriteSystemInfo(); - vfs_display(); - } - 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"); - InitPs(); - - 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; - - 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 - - +CMusicPlayer music_player; static void Frame() { MICROLOG(L"Frame"); - oglCheck(); PROFILE_START( "update music" ); - MusicPlayer.update(); + music_player.update(); PROFILE_END( "update music" ); static double last_time; @@ -1498,27 +181,21 @@ static void Frame() vfs_reload_changed_files(); PROFILE_END( "reload changed files" ); - oglCheck(); - PROFILE_START( "progressive load" ); ProgressiveLoad(); PROFILE_END( "progressive load" ); PROFILE_START( "input" ); MICROLOG(L"input"); - in_get_events(); + PumpEvents(); g_SessionManager.Poll(); PROFILE_END( "input" ); - oglCheck(); - PROFILE_START( "gui tick" ); #ifndef NO_GUI g_GUI.TickObjects(); #endif PROFILE_END( "gui tick" ); - - oglCheck(); PROFILE_START( "game logic" ); if (g_Game && g_Game->IsGameStarted()) @@ -1566,22 +243,20 @@ static void Frame() g_Console->Update(TimeSinceLastFrame); PROFILE_END( "update console" ); - // ugly, but necessary. these are one-shot events, have to be reset. + // TODO: ugly, but necessary. these are one-shot events, have to be reset. // Spoof mousebuttonup events for the hotkey system SDL_Event spoof; spoof.type = SDL_MOUSEBUTTONUP; spoof.button.button = SDL_BUTTON_WHEELUP; - if( mouseButtons[SDL_BUTTON_WHEELUP] ) + if( mouse_buttons[SDL_BUTTON_WHEELUP] ) hotkeyInputHandler( &spoof ); spoof.button.button = SDL_BUTTON_WHEELDOWN; - if( mouseButtons[SDL_BUTTON_WHEELDOWN] ) + if( mouse_buttons[SDL_BUTTON_WHEELDOWN] ) hotkeyInputHandler( &spoof ); - mouseButtons[SDL_BUTTON_WHEELUP] = false; - mouseButtons[SDL_BUTTON_WHEELDOWN] = false; - - oglCheck(); + mouse_buttons[SDL_BUTTON_WHEELUP] = false; + mouse_buttons[SDL_BUTTON_WHEELDOWN] = false; PROFILE_START( "render" ); if(g_active) @@ -1603,31 +278,64 @@ static void Frame() g_Profiler.Frame(); calc_fps(); - if (g_FixedFrameTiming && frameCount==100) quit=true; + if(g_FixedFrameTiming && frameCount==100) + kill_mainloop(); +} + + +static void MainControllerInit() +{ + // add additional input handlers only needed by this controller. + + // gui_handler needs to be after (i.e. called before!) the hotkey handler + // so that input boxes can be typed in without setting off hotkeys. +#ifndef NO_GUI + in_add_handler(gui_handler); +#endif + + // must be after gui_handler. Should mayhap even be last. + in_add_handler(MainInputHandler); } +static void MainControllerShutdown() +{ + music_player.release(); +} + #ifndef SCED + +static bool quit = false; // break out of main loop + +// HACK: Let code from other files (i.e. the scripting system) quit +void kill_mainloop() +{ + quit = true; +} + + int main(int argc, char* argv[]) { debug_printf("MAIN &argc=%p &argv=%p\n", &argc, &argv); - Init(argc, argv, true); + ATLAS_RunIfOnCmdLine(argc, argv); - // Optionally, do some simple tests to ensure things aren't broken - // extern void PerformTests(); - // PerformTests(); + // ELSE + Init(argc, argv, true); + MainControllerInit(); while(!quit) Frame(); Shutdown(); + MainControllerShutdown(); exit(0); } + // Public functions for Atlas to use: // TODO: Make this far less hacky void Init_(int argc, char** argv, bool setup_gfx) diff --git a/source/ps/CConsole.h b/source/ps/CConsole.h index 7ee8e33278..efadf6f0df 100755 --- a/source/ps/CConsole.h +++ b/source/ps/CConsole.h @@ -21,6 +21,11 @@ #include "sdl.h" #include "CStr.h" +// note: cannot forward declare "struct SDL_Event" - that triggers an +// internal error in VC7.1 at msc1.cpp(2701). +// we include the full header instead. *sigh* +#include "lib/sdl.h" + #ifndef CCONSOLE_H #define CCONSOLE_H @@ -117,4 +122,6 @@ public: extern CConsole* g_Console; +extern int conInputHandler(const SDL_Event* ev); + #endif diff --git a/source/ps/CStr.cpp b/source/ps/CStr.cpp index fb308777aa..c46bf2c5ba 100755 --- a/source/ps/CStr.cpp +++ b/source/ps/CStr.cpp @@ -12,6 +12,10 @@ #define UNIDOUBLER_HEADER "CStr.cpp" #include "UniDoubler.h" +#ifndef PERFORM_SELF_TEST +#define PERFORM_SELF_TEST 0 +#endif + // Only include these function definitions in the first instance of CStr.cpp: CStrW::CStrW(const CStr8 &asciStr) : std::wstring(asciStr.begin(), asciStr.end()) {} @@ -581,4 +585,37 @@ uint CStr::GetSerializedLength() const #undef _totlower #undef _totupper + + +//---------------------------------------------------------------------------- +// built-in self test +//---------------------------------------------------------------------------- + +#if PERFORM_SELF_TEST +namespace test { + +static void test1() +{ + const wchar_t chr_utf16[] = { 0x12, 0xff, 0x1234, 0x3456, 0x5678, 0x7890, 0x9abc, 0xbcde, 0xfffe }; + const unsigned char chr_utf8[] = { 0x12, 0xc3, 0xbf, 0xe1, 0x88, 0xb4, 0xe3, 0x91, 0x96, 0xe5, 0x99, 0xb8, 0xe7, 0xa2, 0x90, 0xe9, 0xaa, 0xbc, 0xeb, 0xb3, 0x9e, 0xef, 0xbf, 0xbe }; + CStrW str_utf16 (chr_utf16, sizeof(chr_utf16)/sizeof(wchar_t)); + CStr8 str_utf8 = str_utf16.ToUTF8(); + debug_assert(str_utf8.length() == sizeof(chr_utf8)); + debug_assert(memcmp(str_utf8.data(), chr_utf8, sizeof(chr_utf8)) == 0); + debug_assert(str_utf8.FromUTF8() == str_utf16); +} + + +static int run_tests() +{ + test1(); + return 0; +} + +static int dummy = run_tests(); + +} // namespace test +#endif // #if PERFORM_SELF_TEST + + #endif // CStr_CPP_FIRST diff --git a/source/ps/GameSetup/Atlas.cpp b/source/ps/GameSetup/Atlas.cpp new file mode 100644 index 0000000000..dca257daa1 --- /dev/null +++ b/source/ps/GameSetup/Atlas.cpp @@ -0,0 +1,115 @@ +#include "precompiled.h" + +#include "lib/posix.h" +#include "lib/lib.h" +#include "Atlas.h" + +//---------------------------------------------------------------------------- +// Atlas (map editor) integration +//---------------------------------------------------------------------------- + +static void* const ATLAS_SO_UNAVAILABLE = (void*)-1; +static void* atlas_so_handle; + + +// free reference to Atlas UI SO (avoids resource leak report) +void ATLAS_Shutdown() +{ + // (avoid dlclose warnings) + if(atlas_so_handle != 0 && atlas_so_handle != ATLAS_SO_UNAVAILABLE) + dlclose(atlas_so_handle); +} + + +// return true if the Atlas UI shared object is available; +// used to disable the main menu editor button if not. +// note: this actually loads the SO, but that isn't expected to be slow. +// call ATLAS_Shutdown at exit to avoid leaking it. +static bool ATLAS_IsAvailable() +{ + // first time: try to open Atlas UI shared object + // postcondition: atlas_so_handle valid or == ATLAS_SO_UNAVAILABLE. + if(atlas_so_handle == 0) + { + // since this SO exports a C++ interface, it is critical that + // compiler options are the same between app and SO; therefore, + // we need to go with the debug version in debug builds. + // note: on Windows, the extension is replaced with .dll by dlopen. +#ifndef NDEBUG + const char* so_name = "AtlasUI_d.so"; +#else + const char* so_name = "AtlasUI.so"; +#endif + // we don't care when relocations take place because this SO contains + // very few symbols, so RTLD_LAZY or RTLD_NOW aren't needed. + const int flags = RTLD_LOCAL; + atlas_so_handle = dlopen(so_name, flags); + // open failed (mostly likely SO not found) + if(!atlas_so_handle) + atlas_so_handle = ATLAS_SO_UNAVAILABLE; + } + + return atlas_so_handle != ATLAS_SO_UNAVAILABLE; +} + + +enum AtlasRunFlags +{ + // used by ATLAS_RunIfOnCmdLine; makes any error output go through + // DISPLAY_ERROR rather than a GUI dialog box (because GUI init was + // skipped to reduce load time). + ATLAS_NO_GUI = 1 +}; + +// starts the Atlas UI. +static void ATLAS_Run(int argc, char* argv[], int flags = 0) +{ + // first check if we can run at all + if(!ATLAS_IsAvailable()) + { + if(flags & ATLAS_NO_GUI) + DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested."); + else + DISPLAY_ERROR(L"The Atlas UI was not successfully loaded and therefore cannot be started as requested.");// TODO: implement GUI error message + return; + } + + void(*pStartWindow)(int argc, char* argv[]); + *(void**)&pStartWindow = dlsym(atlas_so_handle, "_StartWindow"); + pStartWindow(argc, argv); +} + + +// starts the Atlas UI if an "-editor" switch is found on the command line. +// this is the alternative to starting the main menu and clicking on +// the editor button; it is much faster because it's called during early +// init and therefore skips GUI setup. +// notes: +// - GUI init still runs, but some GUI setup will be skipped since +// ATLAS_IsRunning() will return true. +// - could be merged into CFG_ParseCommandLineArgs, because that appears +// to be called early enough. it's not really worth it because this +// code is quite simple and we thus avoid startup order dependency. +void ATLAS_RunIfOnCmdLine(int argc, char* argv[]) +{ + for(int i = 1; i < argc; i++) // skip program name argument + { + if(!strcmp(argv[i], "-editor")) + { + // don't bother removing this param (unnecessary) + + ATLAS_Run(argc, argv, ATLAS_NO_GUI); + break; + } + } +} + + + + + + + + + + diff --git a/source/ps/GameSetup/Atlas.h b/source/ps/GameSetup/Atlas.h new file mode 100644 index 0000000000..7463abb636 --- /dev/null +++ b/source/ps/GameSetup/Atlas.h @@ -0,0 +1,8 @@ +// free reference to Atlas UI SO (avoids resource leak report) +extern void ATLAS_Shutdown(); + +// starts the Atlas UI if an "-editor" switch is found on the command line. +// this is the alternative to starting the main menu and clicking on +// the editor button; it is much faster because it's called during early +// init and therefore skips GUI setup. +extern void ATLAS_RunIfOnCmdLine(int argc, char* argv[]); diff --git a/source/ps/GameSetup/Config.cpp b/source/ps/GameSetup/Config.cpp new file mode 100644 index 0000000000..83d63635b5 --- /dev/null +++ b/source/ps/GameSetup/Config.cpp @@ -0,0 +1,186 @@ +#include "precompiled.h" + +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "ps/CConsole.h" +#include "lib/timer.h" +#include "lib/res/sound/snd.h" +#include "lib/res/file/vfs.h" +#include "Config.h" + +#define LOG_CATEGORY "config" + +CStr g_CursorName = "test"; +CStr g_ActiveProfile = "default"; + +// flag to disable extended GL extensions until fix found - specifically, crashes +// using VBOs on laptop Radeon cards +bool g_NoGLVBO=false; +// flag to switch on shadows +bool g_Shadows=false; +// flag to switch off pbuffers +bool g_NoPBuffer=true; +// flag to switch on fixed frame timing (RC: I'm using this for profiling purposes) +bool g_FixedFrameTiming=false; +bool g_VSync = false; +float g_LodBias = 0.0f; +float g_Gamma = 1.0f; +bool g_EntGraph = false; + +// graphics mode +int g_xres, g_yres; +int g_bpp; +int g_freq; + +bool g_Quickstart=false; + + + +//---------------------------------------------------------------------------- +// config and profile +//---------------------------------------------------------------------------- + +static void LoadProfile( CStr profile ) +{ + CStr base = CStr( "profiles/" ) + profile; + g_ConfigDB.SetConfigFile(CFG_USER, true, base + "/settings/user.cfg"); + g_ConfigDB.Reload(CFG_USER); + + int max_history_lines = 50; + CFG_GET_USER_VAL("console.history.size", Int, max_history_lines); + g_Console->UseHistoryFile(base+"/settings/history", max_history_lines); +} + + +// Fill in the globals from the config files. +static void LoadGlobals() +{ + CFG_GET_SYS_VAL("profile", String, g_ActiveProfile); + + // Now load the profile before trying to retrieve the values of the rest of these. + + LoadProfile( g_ActiveProfile ); + + CFG_GET_USER_VAL("xres", Int, g_xres); + CFG_GET_USER_VAL("yres", Int, g_yres); + + CFG_GET_USER_VAL("vsync", Bool, g_VSync); + CFG_GET_USER_VAL("novbo", Bool, g_NoGLVBO); + CFG_GET_USER_VAL("shadows", Bool, g_Shadows); + + CFG_GET_USER_VAL("lodbias", Float, g_LodBias); + + float gain = -1.0f; + CFG_GET_USER_VAL("sound.mastergain", Float, gain); + if(gain > 0.0f) + WARN_ERR(snd_set_master_gain(gain)); + + LOG(NORMAL, LOG_CATEGORY, "g_x/yres is %dx%d", g_xres, g_yres); + LOG(NORMAL, LOG_CATEGORY, "Active profile is %s", g_ActiveProfile.c_str()); +} + + +static void ParseCommandLineArgs(int argc, char* argv[]) +{ + for(int i = 1; i < argc; i++) + { + // this arg isn't an option; skip + if(argv[i][0] != '-') + continue; + + char* name = argv[i]+1; // no leading '-' + + // switch first letter of option name + switch(argv[i][1]) + { + case 'c': + if(strcmp(name, "conf") == 0) + { + if(argc-i >= 1) // at least one arg left + { + i++; + char* arg = argv[i]; + char* equ = strchr(arg, '='); + if(equ) + { + *equ = 0; + g_ConfigDB.CreateValue(CFG_COMMAND, arg) + ->m_String = (equ+1); + } + } + } + break; + case 'e': + g_EntGraph = true; + break; + case 'f': + if(strncmp(name, "fixedframe", 10) == 0) + g_FixedFrameTiming=true; + break; + case 'g': + if(strncmp(name, "g=", 2) == 0) + { + g_Gamma = (float)atof(argv[i] + 3); + if(g_Gamma == 0.0f) + g_Gamma = 1.0f; + } + break; + case 'l': + if(strncmp(name, "listfiles", 9) == 0) + vfs_enable_file_listing(true); + break; + case 'n': + if(strncmp(name, "novbo", 5) == 0) + g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String="true"; + else if(strncmp(name, "nopbuffer", 9) == 0) + g_NoPBuffer = true; + break; + case 'q': + if(strncmp(name, "quickstart", 10) == 0) + g_Quickstart = true; + break; + case 's': + if(strncmp(name, "shadows", 7) == 0) + g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String="true"; + break; + case 'v': + g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String="true"; + break; + case 'x': + if(strncmp(name, "xres=", 6) == 0) + g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String=argv[i]+6; + break; + case 'y': + if(strncmp(name, "yres=", 6) == 0) + g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String=argv[i]+6; + break; + case 'p': + if(strncmp(name, "profile=", 8) == 0 ) + g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = argv[i]+9; + break; + } // switch + } +} + + +void CONFIG_Init(int argc, char* argv[]) +{ + debug_printf("CFG_Init &argc=%p &argv=%p\n", &argc, &argv); + + TIMER(CONFIG_Init); + MICROLOG(L"init config"); + + new CConfigDB; + + g_ConfigDB.SetConfigFile(CFG_SYSTEM, false, "config/system.cfg"); + g_ConfigDB.Reload(CFG_SYSTEM); + + g_ConfigDB.SetConfigFile(CFG_MOD, true, "config/mod.cfg"); + // No point in reloading mod.cfg here - we haven't mounted mods yet + + ParseCommandLineArgs(argc, argv); + + // Collect information from system.cfg, the profile file, + // and any command-line overrides to fill in the globals. + LoadGlobals(); +} diff --git a/source/ps/GameSetup/Config.h b/source/ps/GameSetup/Config.h new file mode 100644 index 0000000000..0485fc9e13 --- /dev/null +++ b/source/ps/GameSetup/Config.h @@ -0,0 +1,27 @@ +#include "CStr.h" + +// flag to disable extended GL extensions until fix found - specifically, crashes +// using VBOs on laptop Radeon cards +extern bool g_NoGLVBO; +// flag to switch on shadows +extern bool g_Shadows; +// flag to switch off pbuffers +extern bool g_NoPBuffer; +// flag to switch on fixed frame timing (RC: I'm using this for profiling purposes) +extern bool g_FixedFrameTiming; +extern bool g_VSync; +extern float g_LodBias; +extern float g_Gamma; +extern bool g_EntGraph; + + +extern int g_xres, g_yres; +extern int g_bpp; +extern int g_freq; +extern bool g_active; +extern bool g_Quickstart; + +extern CStr g_CursorName; + + +extern void CONFIG_Init(int argc, char* argv[]); diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp new file mode 100644 index 0000000000..b48a1b3a75 --- /dev/null +++ b/source/ps/GameSetup/GameSetup.cpp @@ -0,0 +1,847 @@ +#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" +#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" + +#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" +#include "ps/System.h" + +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::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" ); + g_Mouseover.renderSelectionOutlines(); + g_Selection.renderSelectionOutlines(); + PROFILE_END( "render selection" ); + + 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) + cursor_draw(g_CursorName, g_mouse_x, g_mouse_y); + + // 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::ScriptingInit(); // <-- Doesn't really matter which we use, but we know CJSPropertyAccessor 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"); + if(err < 0) + throw 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); + } + extern void vfs_dump_stats(); + vfs_dump_stats(); + // don't try vfs_display yet: SDL_Init hasn't yet redirected stdout +} + + +static void InitPs() +{ + // 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. + GUI_Init(); +} + + +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); +} + + + +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"); + + ATLAS_Shutdown(); + + ShutdownPs(); // Must delete g_GUI before g_ScriptingHost + + if (g_Game) + EndGame(); + + delete &g_Scheduler; + + delete &g_SessionManager; + + delete &g_Mouseover; + delete &g_Selection; + + delete &g_Pathfinder; + // Managed by CWorld + // delete &g_EntityManager; + + delete &g_GameAttributes; + delete &g_JSGameEvents; + + delete &g_EntityTemplateCollection; + + delete &g_ScriptingHost; + + // destroy actor related stuff + delete &g_UnitMan; + delete &g_ObjMan; + delete &g_SkelAnimMan; + + delete &g_MaterialManager; + delete &g_MeshManager; + + // destroy terrain related stuff + delete &g_TexMan; + + // destroy renderer + delete &g_Renderer; + + delete &g_ConfigDB; + + // Shut down the network loop + CSocketBase::Shutdown(); + + // Really shut down the i18n system. Any future calls + // to translate() will crash. + I18n::Shutdown(); + + snd_shutdown(); + + vfs_shutdown(); + + h_mgr_shutdown(); + mem_shutdown(); + + debug_shutdown(); + + delete &g_Logger; + + delete &g_Profiler; +} + + +// workaround for VC7 EBP-trashing bug, which confuses the stack trace code. +#if MSC_VERSION +# pragma optimize("", off) +#endif + +void Init(int argc, char* argv[], bool setup_gfx = true) +{ + debug_printf("INIT &argc=%p &argv=%p\n", &argc, &argv); + + MICROLOG(L"Init"); + + debug_set_thread_name("main"); + + // 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); + + // should be done before the bulk of GUI init because it prevents + // most loads from happening (since ATLAS_IsRunning will return true). + ATLAS_RunIfOnCmdLine(argc, argv); + + // 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) + { + MICROLOG(L"set vmode"); + + 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(); + } + SDL_WM_SetCaption("0 A.D.", "0 A.D."); + } + + oglCheck(); + + if(!g_Quickstart) + { + WriteSystemInfo(); + vfs_display(); + } + 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"); + InitPs(); + + 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; + + 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 + + diff --git a/source/ps/GameSetup/GameSetup.h b/source/ps/GameSetup/GameSetup.h new file mode 100644 index 0000000000..c7af41f254 --- /dev/null +++ b/source/ps/GameSetup/GameSetup.h @@ -0,0 +1,22 @@ + +//---------------------------------------------------------------------------- +// GUI integration +//---------------------------------------------------------------------------- + + +extern void GUI_Init(); + +extern void GUI_Shutdown(); + +extern void GUI_ShowMainMenu(); + +// display progress / description in loading screen +extern void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task); + + + +extern void Render(); + +extern void Shutdown(); + +extern void Init(int argc, char* argv[], bool setup_gfx = true); diff --git a/source/ps/Hotkey.cpp b/source/ps/Hotkey.cpp index 7d02417aca..ec39c3f250 100755 --- a/source/ps/Hotkey.cpp +++ b/source/ps/Hotkey.cpp @@ -9,7 +9,7 @@ extern CConsole* g_Console; extern bool keys[SDLK_LAST]; -extern bool mouseButtons[5]; +extern bool mouse_buttons[5]; bool unified[5]; /* SDL-type */ @@ -424,7 +424,7 @@ int hotkeyInputHandler( const SDL_Event* ev ) } else if( *itKey < UNIFIED_SHIFT ) { - if( mouseButtons[keyCode-SDLK_LAST] != rqdState ) accept = false; + if( mouse_buttons[keyCode-SDLK_LAST] != rqdState ) accept = false; } else if( unified[keyCode-UNIFIED_SHIFT] != rqdState ) accept = false; @@ -484,7 +484,7 @@ int hotkeyInputHandler( const SDL_Event* ev ) } else if( *itKey < UNIFIED_SHIFT ) { - if( mouseButtons[keyCode-SDLK_LAST] != rqdState ) accept = false; + if( mouse_buttons[keyCode-SDLK_LAST] != rqdState ) accept = false; } else if( unified[keyCode-UNIFIED_SHIFT] != rqdState ) accept = false; @@ -548,7 +548,7 @@ int hotkeyInputHandler( const SDL_Event* ev ) } else if( *itKey < UNIFIED_SHIFT ) { - if( !mouseButtons[(*itKey)-SDLK_LAST] ) accept = false; + if( !mouse_buttons[(*itKey)-SDLK_LAST] ) accept = false; } else if( !unified[(*itKey)-UNIFIED_SHIFT] ) accept = false; diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 865cde8707..89ea88247d 100755 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -15,9 +15,12 @@ #include "timer.h" #include "Loader.h" #include "LoaderThunks.h" +#include "graphics/MapWriter.h" #define LOG_CATEGORY "world" +// global light settings. this is not a member of CWorld because it is +// passed to the renderer before CWorld exists. CLightEnv g_LightEnv; void CWorld::Initialize(CGameAttributes *pAttribs) @@ -63,3 +66,9 @@ CWorld::~CWorld() delete &m_EntityManager; delete &m_ProjectileManager; } + + +void CWorld::RewriteMap() +{ + CMapWriter::RewriteAllMaps(&m_Terrain, &m_UnitManager, &g_LightEnv); +} \ No newline at end of file diff --git a/source/ps/World.h b/source/ps/World.h index df7aa3f66f..ef7aff030b 100755 --- a/source/ps/World.h +++ b/source/ps/World.h @@ -38,6 +38,8 @@ public: */ void Initialize(CGameAttributes *pGameAttributes); + // provided for JS _rewritemaps function + void RewriteMap(); inline CTerrain *GetTerrain() { return &m_Terrain; } @@ -56,4 +58,8 @@ private: ERROR_SUBGROUP(Game, World); ERROR_TYPE(Game_World, MapLoadFailed); +// rationale: see definition. +class CLightEnv; +extern CLightEnv g_LightEnv; + #endif diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index e25400e582..f9390191e2 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -641,7 +641,7 @@ JSBool _rewriteMaps( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* UN { REQUIRE_NO_PARAMS(_rewriteMaps); - CMapWriter::RewriteAllMaps(g_Game->GetWorld()->GetTerrain(), g_Game->GetWorld()->GetUnitManager(), &g_LightEnv); + g_Game->GetWorld()->RewriteMap(); return JS_TRUE; } diff --git a/source/scripting/ScriptGlue.h b/source/scripting/ScriptGlue.h index 1a66218ed6..6a7585afe0 100755 --- a/source/scripting/ScriptGlue.h +++ b/source/scripting/ScriptGlue.h @@ -4,8 +4,6 @@ #include "ScriptingHost.h" -#include "LightEnv.h" // required by g_LightEnv declaration below. - // referenced by ScriptingHost.cpp extern JSFunctionSpec ScriptFunctionTable[]; extern JSPropertySpec ScriptGlobalTable[]; @@ -18,7 +16,6 @@ extern CStr g_CursorName; extern void StartGame(); extern void EndGame(); // .. other -extern CLightEnv g_LightEnv; #if OS_WIN extern int GetVRAMInfo(int&, int&); #endif diff --git a/source/simulation/Scheduler.h b/source/simulation/Scheduler.h index be558991f1..9de930c0c0 100755 --- a/source/simulation/Scheduler.h +++ b/source/simulation/Scheduler.h @@ -85,6 +85,10 @@ public: static void ScriptingInit(); }; +// made visible to main.cpp's Frame() so that it can abort after 100 frames +// if g_FixedFrameTiming == true (allows measuring performance). +extern size_t frameCount; + extern const int ORDER_DELAY; #endif