# HG changeset patch # User Diggory Hardy # Date 1207240012 -3600 # Node ID 2c28ee04a4ed4d921c21056e2319f9db4a417a50 # Parent 32eff0e01c05e9f4bd18c5bb8e153a292403db9b Some minor and some futile efforts. Played around with init functions, had problems, gave up and put them back. Removed idea for multiple init stages; it's not good for performance or simplicity. Adjusted exception messages. committer: Diggory Hardy diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/SDL.d --- a/mde/SDL.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/SDL.d Thu Apr 03 17:26:52 2008 +0100 @@ -17,7 +17,7 @@ */ module mde.SDL; -import mde.scheduler.InitStage; +import mde.scheduler.InitFunctions; import mde.input.joystick; import mde.options; import mde.gl; @@ -34,15 +34,12 @@ static this() { logger = Log.getLogger ("mde.SDL"); - init2.addFunc (&initSdlAndGl); - init4.addFunc (&setupWindow); + init.addFunc (&initSdlAndGl); } private uint flags = 0; -void initSdlAndGl() { // init2 func - debug logger.trace ("init2: initSdlAndGl() started"); - +void initSdlAndGl() { // init func // Load SDL and GL dynamic libs try { DerelictSDL.load(); @@ -66,25 +63,18 @@ return; } - cleanup2.addFunc (&cleanupSDL); debug logger.trace ("SDL initialised"); // Must be called after SDL has been initialised, so cannot be a separate Init function. openJoysticks (); // after SDL init - cleanup2.addFunc (&closeJoysticks); + cleanup.addFunc (&cleanupSDL); - debug logger.trace ("init2: initSdlAndGl() finished"); + setupWindow(); } -version = MDE_OPENGL; - -void setupWindow() { // init4 func - debug logger.trace ("init4: setupWindow() started"); - +void setupWindow() { // indirect init func (depends on initSdlAndGl) // Window creation flags and size - /* NOTE: I'm getting an API mismatch error from the nvidia driver when using OpenGL, - * thus I've temporarily disabled it. */ - version (MDE_OPENGL) flags = SDL_OPENGL; + flags = SDL_OPENGL; if (vidOpts.hardware) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF; else flags |= SDL_SWSURFACE; int w, h; @@ -100,14 +90,12 @@ h = vidOpts.windowH; } - version (MDE_OPENGL) { // OpenGL attributes SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); - } // Open a window if (SDL_SetVideoMode (w, h, 32, flags) is null) { @@ -119,6 +107,19 @@ return; } + // Now (must be done after GL context is created) try to load later version: + /+ No later GL features are currently used. + try { + DerelictGL.loadVersions(GLVersion.Version21); + } catch (DerelictException de) { + logger.fatal ("Loading OpenGL version > 1.1 failed:"); + logger.fatal (de.msg); + + setInitFailure (); + return; + } + +/ + // OpenGL stuff: glSetup(); @@ -128,8 +129,6 @@ // Window-manager settings SDL_WM_SetCaption (toStringz ("mde"), null); // SDL_WM_GrabInput (use later) - - debug logger.trace ("init4: setupWindow() finished"); } void resizeWindow (int w, int h) { @@ -153,10 +152,9 @@ setProjection (w, h); } -void cleanupSDL () { // cleanup2 func - debug logger.trace ("cleanup2: cleanupSDL() started"); +void cleanupSDL () { // cleanup func + closeJoysticks(); SDL_Quit(); - debug logger.trace ("cleanup2: cleanupSDL() finished"); } /+ Load of info-printing stuff (currently doesn't have a use) diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/events.d --- a/mde/events.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/events.d Thu Apr 03 17:26:52 2008 +0100 @@ -16,15 +16,15 @@ /// Handles all events from SDL_PollEvent. module mde.events; -import mde.scheduler.InitStage; -import mde.scheduler.runTime; - import global = mde.global; static import mde.SDL; import mde.input.input; import mde.input.exception; +import mde.scheduler.InitFunctions; +import mde.scheduler.runTime; + import derelict.sdl.events; import tango.util.log.Log : Log, Logger; @@ -32,23 +32,26 @@ private Logger logger; static this() { logger = Log.getLogger ("mde.events"); + + init.addFunc (&initInput); - init2.addFunc (&initInput); - - Scheduler.perFrame (&pollEvents); + Scheduler.perFrame (&mde.events.pollEvents); } -void initInput () { // init2 func - debug logger.trace ("init2: initInput() started"); - +void initInput () { // init func try { global.input = new Input(); global.input.loadConfig (); // (may also create instance) - } catch (Exception e) { - setInitFailure (); // must clean up properly + + global.input.addButtonCallback (cast(Input.inputID) 0x0u, delegate void(Input.inputID i, bool b) { + if (b) { + logger.info ("Quiting..."); + global.run = false; + } + } ); + } catch (Exception) { + setInitFailure; } - - debug logger.trace ("init2: initInput() finished"); } void pollEvents (double) { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/exception.d --- a/mde/exception.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/exception.d Thu Apr 03 17:26:52 2008 +0100 @@ -27,26 +27,27 @@ * "mde.pkg.file.Class" describing where the exception was thrown. (Since only methods overload * correctly, symbol is made static and an overloadable method is used to access the correct symbol.) */ -class mdeException : Exception { - static const symbol = "mde"; /// Override in derived classes to name the module where the error occured. + class mdeException : Exception { + /// Override in derived classes to name the module where the error occured. char[] getSymbol () { - return symbol; + return "mde"; + } + /// Prefix msg, e.g.: "mde.foo: message" + char[] prefixedMsg () { + return getSymbol() ~ ": " ~ msg; } this (char[] msg) { - super(getSymbol() ~ ": " ~ msg); + super(msg); } this () { // No supplied error message. - super(symbol); + super(""); } } /// Thrown when loading options fails. class optionsLoadException : mdeException { - // NOTE: if symbol is final, it can't be modified in the static this(), but as const it can - static const char[] symbol; - static this () { symbol = super.symbol ~ ".options"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".options"; } this (char[] msg) { @@ -56,11 +57,8 @@ /// Thrown when loading strings for the requested name and current locale fails. class L10nLoadException : mdeException { - // NOTE: if symbol is final, it can't be modified in the static this(), but as const it can - static const char[] symbol; - static this () { symbol = super.symbol ~ ".i18n.I18nTranslation"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".i18n.I18nTranslation"; } this (char[] msg) { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/gl.d --- a/mde/gl.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/gl.d Thu Apr 03 17:26:52 2008 +0100 @@ -21,8 +21,8 @@ import derelict.sdl.sdl; import derelict.opengl.gl; -static this() { - Scheduler.perRequest (RF_KEYS.DRAW, &draw); +static this () { + Scheduler.perRequest (RF_KEYS.DRAW, &mde.gl.draw); } void glSetup () { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/input/exception.d --- a/mde/input/exception.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/input/exception.d Thu Apr 03 17:26:52 2008 +0100 @@ -19,10 +19,8 @@ /// Base Input exception class. class inputException : mdeException { - static const char[] symbol; - static this () { symbol = super.symbol ~ ".input"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".input"; } this (char[] msg) { @@ -32,10 +30,8 @@ } class InputClassException : inputException { - static const char[] symbol; - static this () { symbol = super.symbol ~ ".input.Input"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".input.Input"; } this (char[] msg) { @@ -45,10 +41,8 @@ } class ConfigLoadException : inputException { - static const char[] symbol; - static this () { symbol = super.symbol ~ ".config.Config"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".config.Config"; } this (char[] msg) { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/mde.d --- a/mde/mde.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/mde.d Thu Apr 03 17:26:52 2008 +0100 @@ -15,29 +15,24 @@ /** Modular D Engine * - * This module contains main(). + * This module contains main(), which calls Init and runs the main loop. */ module mde.mde; -// Package imports -import global = mde.global; -import mde.events; -import mde.exception; +// Comment to show use, where only used minimally: -import mde.SDL; // This module is ONLY imported because otherwise it wouldn't be compiled in +import global = mde.global; // global.run +import mde.SDL; // unused (but must be linked in) +import mde.events; // unused (but must be linked in) import mde.scheduler.Init; -import mde.scheduler.runTime; -import mde.scheduler.exception; - -import mde.input.input; +import mde.scheduler.runTime; // Scheduler.run() +import mde.scheduler.exception; // InitException -import tango.core.Thread : Thread; // for sleep -import tango.time.Clock; +import tango.core.Thread : Thread; // Thread.sleep() +import tango.time.Clock; // Clock.now() import tango.util.log.Log : Log, Logger; -import derelict.sdl.sdl; - int main() { //BEGIN Initialisation @@ -48,17 +43,9 @@ try { init = new Init(); // initialisation } catch (InitException e) { - logger.fatal ("Initialisation failed; error was:"); - logger.fatal (e.msg); + logger.fatal ("Initialisation failed: " ~ e.msg); return 1; } - - global.input.addButtonCallback (cast(Input.inputID) 0x0u, delegate void(Input.inputID i, bool b) { - if (b) { - logger.info ("Quiting..."); - global.run = false; - } - } ); //END Initialisation while (global.run) { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/mergetag/exception.d --- a/mde/mergetag/exception.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/mergetag/exception.d Thu Apr 03 17:26:52 2008 +0100 @@ -24,10 +24,8 @@ /// Base MergeTag exception class. class MTException : mdeException { - static const char[] symbol; - static this() { symbol = super.symbol ~ ".mergetag"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".mergetag"; } this (char[] msg) { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/options.d --- a/mde/options.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/options.d Thu Apr 03 17:26:52 2008 +0100 @@ -164,7 +164,7 @@ } catch (MTException e) { logger.fatal (MT_LOAD_EXC); logger.fatal (e.msg); - throw new optionsLoadException ("Loading aborted: mergetag exception"); + throw new optionsLoadException ("Mergetag exception (see above message)"); } } static void save () { diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/scheduler/Init.d --- a/mde/scheduler/Init.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/scheduler/Init.d Thu Apr 03 17:26:52 2008 +0100 @@ -22,7 +22,7 @@ *************************************************************************************************/ module mde.scheduler.Init; -import mde.scheduler.InitStage; +import mde.scheduler.InitFunctions; import mde.scheduler.exception; import mde.options; @@ -36,7 +36,7 @@ import tango.util.log.Log : Log, Logger; import tango.util.log.ConsoleAppender : ConsoleAppender; -version = SwitchAppender; +//version = SwitchAppender; version (SwitchAppender) { // My own variation, currently just a test import tango.util.log.SwitchingFileAppender : SwitchingFileAppender; } else { @@ -92,6 +92,7 @@ */ scope class Init { + //private bool failure = false; // set true on failure during init, so that clean private static Logger logger; static this() { logger = Log.getLogger ("mde.scheduler.Init.Init"); @@ -121,7 +122,7 @@ try { Options.load(); } catch (optionsLoadException e) { - throw new InitException ("Loading options failed; message: " ~ e.msg); + throw new InitException ("Loading options failed: " ~ e.msg); } // Now re-set the logging level: @@ -135,28 +136,12 @@ * Current method is to try using threads, and on failure assume no threads were actually * created and run functions in a non-threaded manner. */ - // init2 - cleanupStages ~= &cleanup2; // add appropriate cleanup stage try { - debug logger.trace ("Init: init2"); - if (runStageThreaded (init2)) runStageForward (init2); + if (runStageThreaded (init)) runStageForward (init); } catch (InitStageException) { // This init stage failed. - debug logger.trace ("Init: init2 failed"); - runCleanupStages(); - throw new InitException ("Initialisation failed during stage init2"); - } - - // init4 - cleanupStages ~= &cleanup4; // add appropriate cleanup stage - try { - debug logger.trace ("Init: init4"); - if (runStageThreaded (init4)) runStageForward (init4); - } - catch (InitStageException) { // This init stage failed. - debug logger.trace ("Init: init4 failed"); - runCleanupStages(); - throw new InitException ("Initialisation failed during stage init4"); + // FIXME: check DTOR still runs + throw new InitException ("An init function failed (see above message(s))"); } //END Init @@ -168,11 +153,16 @@ { debug logger.trace ("Cleanup: starting"); - // cleanup1: Options.save(); // save options... do so here for now - // cleanup2, 4: - runCleanupStages(); + // General cleanup: + try { + if (runStageThreaded (cleanup)) runStageReverse (cleanup); + } + catch (InitStageException) { + // Nothing else to do but report: + logger.error ("One or more cleanup functions failed!"); + } debug logger.trace ("Cleanup: done"); } @@ -259,22 +249,6 @@ } //END runStage... - private { - InitStage*[] cleanupStages; // All cleanup stages needing to be run later. - void runCleanupStages () { - foreach_reverse (s; cleanupStages) { - try { - runStageReverse (*s); - } - catch (InitStageException) { - // We're cleaning up anyway, just report and continue - logger.error ("Cleanup function failed! Continuing..."); - } - } - cleanupStages = []; // All have been run, don't want them getting run again - } - } - debug (mdeUnitTest) unittest { /* Fake init and cleanup. Use unittest-specific init and cleanup InitStages to avoid * messing other init/cleanup up. */ diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/scheduler/InitFunctions.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mde/scheduler/InitFunctions.d Thu Apr 03 17:26:52 2008 +0100 @@ -0,0 +1,55 @@ +/** This module is responsible for calling all init functions. +* +* It is also responsible for setting up all scheduled functions for now. */ +module mde.scheduler.InitFunctions; + +static import mde.gl; + +import tango.util.log.Log : Log, Logger; +static this() { + logger = Log.getLogger ("mde.scheduler.InitFunctions"); +} + +/** Should be called by an init function when a failure occurs. */ +void setInitFailure () { + initFailure = true; +} + +package: + +/** Represents all functions to be called for a particular init stage. */ +struct InitStage +{ + alias void function() InitFunction; /// Alias + + /** Add a function to be called during this init stage. + * + * Called in order added when not threaded (reverse order for cleanup). + * + * Exceptions should never be thrown, since each function may run as a thread, and catching + * thread exceptions is not guaranteed to work. Log a message, call setFailure() and return + * instead. */ + void addFunc (InitFunction f) { + funcs ~= f; + } + + InitFunction[] funcs = []; +} + +InitStage init; // all functions called during init (all should be thread-safe) +InitStage cleanup; // all functions called during cleanup (all should be thread-safe) + +bool initFailure = false; // set on failure (throwing through threads isn't a good idea) + +private: +Logger logger; +const FAIL_MSG = "Init function failed: "; +// Template to call function, catching exceptions: +void initInput(alias Func) () { + try { + Func(); + } catch (Exception e) { + logger.fatal (FAIL_MSG ~ e.msg); + initFailure = true; + } +} diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/scheduler/InitStage.d --- a/mde/scheduler/InitStage.d Thu Mar 27 16:15:21 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* LICENSE BLOCK -Part of mde: a Modular D game-oriented Engine -Copyright © 2007-2008 Diggory Hardy - -This program is free software; you can redistribute it and/or modify it under the terms of -the GNU General Public License, version 2, as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -/** This module is used to create a list of all functions required to run for initialisation and -* cleanup. -* -* It has been separated out of Init.d to massively reduce dependancies of modules adding init -* functions. -*/ -module mde.scheduler.InitStage; - -import tango.util.log.Log : Log, Logger; -private Logger logger; -static this() { - logger = Log.getLogger ("mde.scheduler.InitStage"); -} - -/** Represents all functions to be called for a particular init stage. -* -* No code is included here to run the functions intentionally, to keep dependancies minimal. -*/ -struct InitStage -{ - alias void function() InitFunction; /// Alias - - /** Add a function to be called during this init stage. - * - * Called in order added when not threaded (reverse order for cleanup). - * - * Exceptions should never be thrown, since each function may run as a thread, and catching - * thread exceptions is not guaranteed to work. Log a message, call setFailure() and return - * instead. */ - void addFunc (InitFunction f) { - funcs ~= f; - } - - package InitFunction[] funcs = []; -} - -/** Init can be divided up into these stages, each run in order: -* -* init0: -* static this() (not represented here) -* -* init1: -* Also known as pre-init; is where options get loaded by Init (not represented here). -* -* init2: -* Main symbol and config loading and general low-level stage. This stage is threaded, so all -* called functions need to be thread-safe. -* -* init3: -* Reserved as an unthreaded stage. -* -* init4: -* Main loading stage for data files and setup for higher-level elements, e.g. windows and input -* devices. This stage is threaded, so all called functions need to be thread-safe. -* -* cleanupX: -* Corresponding cleanup stage to initX. Called in reverse order (e.g. cleanup2 called before -* cleanup1). Cleanup is never threaded. -* -* The following functions get called (update list as appropriate): -* -* init2: -* mde.SDL.initSdlAndGl, mde.events.initInput -* -* init4: -* mde.SDL.setupWindow -* -* cleanup2: -* (Potentially): mde.SDL.cleanupSDL, mde.init.joystick.closeJoysticks -*/ -InitStage init2; -InitStage init4; /// ditto -InitStage cleanup2; /// ditto -InitStage cleanup4; /// ditto - -/** Should be called by an init function when a failure occurs. */ -void setInitFailure () { - initFailure = true; -} -package bool initFailure = false; diff -r 32eff0e01c05 -r 2c28ee04a4ed mde/scheduler/exception.d --- a/mde/scheduler/exception.d Thu Mar 27 16:15:21 2008 +0000 +++ b/mde/scheduler/exception.d Thu Apr 03 17:26:52 2008 +0100 @@ -20,11 +20,8 @@ /// Thrown when Init fails. class InitException : mdeException { - // NOTE: if symbol is final, it can't be modified in the static this(), but as const it can - static const char[] symbol; - static this () { symbol = super.symbol ~ ".Init"; } char[] getSymbol () { - return symbol; + return super.getSymbol ~ ".Init"; } this (char[] msg) {