changeset 25:2c28ee04a4ed

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 <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 03 Apr 2008 17:26:52 +0100
parents 32eff0e01c05
children 611f7b9063c6
files mde/SDL.d mde/events.d mde/exception.d mde/gl.d mde/input/exception.d mde/mde.d mde/mergetag/exception.d mde/options.d mde/scheduler/Init.d mde/scheduler/InitFunctions.d mde/scheduler/InitStage.d mde/scheduler/exception.d
diffstat 12 files changed, 137 insertions(+), 228 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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) {
--- 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) {
--- 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 () {
--- 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) {
--- 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) {
--- 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) {
--- 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 () {
--- 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. */
--- /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;
+    }
+}
--- 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;
--- 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) {