changeset 23:47478557428d

Implemented drawing a very basic gl box, and only drawing when necessary. Improvements to window resizing, and gl draws a box as a test. Scheduler has "on request" support to redraws only when requested by an event. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 27 Mar 2008 10:58:57 +0000
parents 249eb6620685
children 32eff0e01c05
files codeDoc/jobs.txt codeDoc/options.txt data/conf/options.mtt mde/SDL.d mde/events.d mde/gl.d mde/options.d mde/scheduler/runTime.d
diffstat 8 files changed, 157 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Tue Mar 25 12:24:04 2008 +0000
+++ b/codeDoc/jobs.txt	Thu Mar 27 10:58:57 2008 +0000
@@ -6,6 +6,8 @@
 
 
 To do:
+*   Generalise Options subclass handling. Add local versions (store options from user path plus changed options). Add changing functions to change both sets and track whether or not to save at exit. Save from local versions. Update doc file.
+
 Also see todo.txt.
 *   Windows building/compatibility (currently partial)
 *   gdc building/compatibility (wait for tango 0.99.5 release?)
@@ -40,6 +42,7 @@
 
 
 Done (for git log message):
-Window sizes for fullscreen and windowed modes are now independant.
-Window resizes by the WM are now persistant.
-Options class contents are now generated by templates.
+Implemented drawing a very basic gl box, and only drawing when necessary.
+
+Improvements to window resizing, and gl draws a box as a test.
+Scheduler has "on request" support to redraws only when requested by an event.
--- a/codeDoc/options.txt	Tue Mar 25 12:24:04 2008 +0000
+++ b/codeDoc/options.txt	Thu Mar 27 10:58:57 2008 +0000
@@ -13,6 +13,12 @@
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
 
 
+Possibilities (first is current functionality):
+* Store current options, write at exit
+* Store current options and options changed during run, if any changed: merge with local options and write at exit
+* Store current options and local options, changes affect local options, write at exit if changed
+
+
 Ideas for extending options to track user-changed options separately from system options so as not to override unchanged system options.
 
 I was inteding on implementing this, until I realised the extra complexity necessary. Also the gains in functionality seem tiny and not always desireable.
@@ -39,7 +45,7 @@
     
     bool*[char[]] optsBool;
     bool[char[]] cgdOptsBool;
-    bool[char[]] sysOptsBool;
+    //bool[char[]] sysOptsBool;
     bool changed; sysLoaded;
     
     this () {
--- a/data/conf/options.mtt	Tue Mar 25 12:24:04 2008 +0000
+++ b/data/conf/options.mtt	Thu Mar 27 10:58:57 2008 +0000
@@ -1,14 +1,16 @@
 {MT01}
 {misc}
+<bool|useThreads=false>
 <char[]|L10n="en-GB">
-<bool|useThreads=true>
 <int|logLevel=1>
 
 {video}
 <bool|noFrame=false>
-<bool|resizable=false>
+<bool|resizable=true>
 <bool|hardware=true>
-<bool|fullscreen=true>
-<int|height=1024>
-<int|width=1280>
+<bool|fullscreen=false>
+<int|screenW=1280>
+<int|windowW=1272>
+<int|screenH=1024>
+<int|windowH=993>
 
--- a/mde/SDL.d	Tue Mar 25 12:24:04 2008 +0000
+++ b/mde/SDL.d	Thu Mar 27 10:58:57 2008 +0000
@@ -20,6 +20,8 @@
 import mde.scheduler.InitStage;
 import mde.input.joystick;
 import mde.options;
+import mde.gl;
+import global = mde.global;
 
 import tango.util.log.Log : Log, Logger;
 import tango.stdc.stringz;
@@ -74,38 +76,41 @@
     logger.trace ("init2: initSdlAndGl() finished");
 }
 
+version = MDE_OPENGL;
+
 void setupWindow() {    // init4 func
     logger.trace ("init4: setupWindow() started");
     
-    // Window creation flags
+    // 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;
-    if (Options.video.fullscreen) flags |= SDL_FULLSCREEN;
+    if (Options.video.hardware) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
+    else flags |= SDL_SWSURFACE;
+    int w, h;
+    if (Options.video.fullscreen) {
+        flags |= SDL_FULLSCREEN;
+        w = Options.video.screenW;
+        h = Options.video.screenH;
+    }
     else {
         if (Options.video.resizable) flags |= SDL_RESIZABLE;
         if (Options.video.noFrame) flags |= SDL_NOFRAME;
+        w = Options.video.windowW;
+        h = Options.video.windowH;
     }
-    if (Options.video.hardware) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
-    else flags |= SDL_SWSURFACE;
     
     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,  16);
+    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  24);
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
     }
     
     // Open a window
-    SDL_Surface* surface;
-    if (Options.video.fullscreen) {
-        surface = SDL_SetVideoMode (Options.video.screenW, Options.video.screenH, 32, flags);
-    } else {
-        surface = SDL_SetVideoMode (Options.video.windowW, Options.video.windowH, 32, flags);
-    }
-    if (surface is null) {
+    if (SDL_SetVideoMode (w, h, 32, flags) is null) {
         logger.fatal ("Unable to set video mode:");
         char* msg = SDL_GetError ();
         logger.fatal (msg ? fromStringz(msg) : "no reason available");
@@ -114,6 +119,12 @@
         return;
     }
     
+    // OpenGL stuff:
+    glSetup();
+    
+    // Projection (mde.gl)
+    setProjection (w, h);
+    
     // Window-manager settings
     SDL_WM_SetCaption (toStringz ("mde"), null);
     // SDL_WM_GrabInput (use later)
@@ -130,9 +141,16 @@
         Options.video.windowH = h;
     }
     
-    /+ Does SDL_SetVideoMode need to be called?
-    setupWindow ();
-    +/
+    if (SDL_SetVideoMode (w, h, 32, flags) is null) {
+        logger.fatal ("Unable to reset video mode:");
+        char* msg = SDL_GetError ();
+        logger.fatal (msg ? fromStringz(msg) : "no reason available");
+        
+        global.run = false;
+    }
+    
+    // Reset the projection and viewport
+    setProjection (w, h);
 }
 
 void cleanupSDL () {    // cleanup2 func
--- a/mde/events.d	Tue Mar 25 12:24:04 2008 +0000
+++ b/mde/events.d	Thu Mar 27 10:58:57 2008 +0000
@@ -34,6 +34,8 @@
     logger = Log.getLogger ("mde.events");
 
     init2.addFunc (&initInput);
+    
+    Scheduler.perFrame (&pollEvents);
 }
 
 void initInput () { // init2 func
@@ -42,8 +44,6 @@
     try {
         global.input = new Input();
         global.input.loadConfig ();         // (may also create instance)
-                
-        Scheduler.perFrame (&pollEvents);
     } catch (Exception e) {
         setInitFailure ();                // must clean up properly
     }
@@ -61,6 +61,11 @@
                 break;
             case SDL_VIDEORESIZE:
                 mde.SDL.resizeWindow (event.resize.w, event.resize.h);
+                Scheduler.requestUpdate(RF_KEYS.DRAW);
+                break;
+            case SDL_ACTIVEEVENT:
+            case SDL_VIDEOEXPOSE:
+                Scheduler.requestUpdate(RF_KEYS.DRAW);
                 break;
             default:
                 try {
--- a/mde/gl.d	Tue Mar 25 12:24:04 2008 +0000
+++ b/mde/gl.d	Thu Mar 27 10:58:57 2008 +0000
@@ -16,7 +16,49 @@
 /** Simple OpenGL functions. */
 module mde.gl;
 
+import mde.scheduler.runTime;
+
+import derelict.sdl.sdl;
 import derelict.opengl.gl;
 
 static this() {
+    Scheduler.perRequest (RF_KEYS.DRAW, &draw);
 }
+
+void glSetup () {
+    glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void setProjection (int w, int h) {
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity ();
+    
+    glViewport (0,0,w,h);
+    //glOrtho (0.0,w, 0.0,h, -1.0, 1.0);
+    glOrtho (0.0,1.0,0.0,1.0,-1.0,1.0);
+    
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+}
+
+// Temporary draw function
+void draw () {
+    glClear(GL_COLOR_BUFFER_BIT);
+    
+    glBegin (GL_QUADS);
+    {
+        glColor3f (0.2f, 0.6f, 0.8f);
+        /+glVertex2i (40, 40);
+        glVertex2i (200, 40);
+        glVertex2i (200, 200);
+        glVertex2i (40, 200);+/
+        glVertex2f (0.1f, 0.1f);
+        glVertex2f (0.9f, 0.1f);
+        glVertex2f (0.9f, 0.9f);
+        glVertex2f (0.1f, 0.9f);
+    }
+    glEnd();
+    
+    glFlush();
+    SDL_GL_SwapBuffers();
+}
--- a/mde/options.d	Tue Mar 25 12:24:04 2008 +0000
+++ b/mde/options.d	Thu Mar 27 10:58:57 2008 +0000
@@ -56,7 +56,7 @@
     protected char[]*[ID]   optsCharA;
     protected int*   [ID]   optsInt;
     
-    //BEGIN Mergtag loading/saving code
+    //BEGIN Mergetag loading/saving code
     void addTag (char[] tp, ID id, char[] dt) {
         if (tp == "bool") {
             bool** p = id in optsBool;
@@ -74,7 +74,7 @@
         foreach (ID id, char[]* val; optsCharA) dlg ("char[]", id, parseFrom!(char[]) (*val));
         foreach (ID id, int*    val; optsInt)   dlg ("int"   , id, parseFrom!(int   ) (*val));
     }
-    //END Mergtag loading/saving code
+    //END Mergetag loading/saving code
         
     //BEGIN Static
     // Each individual section
--- a/mde/scheduler/runTime.d	Tue Mar 25 12:24:04 2008 +0000
+++ b/mde/scheduler/runTime.d	Thu Mar 27 10:58:57 2008 +0000
@@ -19,9 +19,20 @@
 
 import tango.time.Time;
 
+debug {
+    import tango.util.log.Log : Log, Logger;
+    private Logger logger;
+}
+static this() {
+    debug logger = Log.getLogger ("mde.scheduler.runTime");
+}
+
+/** Some enums used by per request functions. */
+enum RF_KEYS : uint { DRAW };
+
 // NOTE: Currently has no support for removing functions. To fix, assign ID and store fct pointers
 // in an associative array, returning the ID [on adding fct pointer].
-// FIXME: support delegates or not?
+// NOTE: support delegates or not?
 /// This class can run scheduled functions per frame or every t seconds (sim-time).
 abstract class Scheduler
 {
@@ -49,7 +60,31 @@
     static void perTime (TimeSpan n, scheduleFct fct)
     in { assert (n > TimeSpan (0L)); }
     body {
-        timeFcts ~= TimeFct (fct, n);
+        timeFcts ~= new TimeFct (fct, n);
+    }
+    
+    /** Add a function to be called per requested update.
+    *
+    * A bool parameter is stored locally describing whether or not the function needs recalling,
+    * and is set true upon creation and when requestUpdate is called with the same key. The
+    * function is then called by scheduler's run() whenever this bool variable is true.
+    */
+    static void perRequest (uint key, void function() fct)
+    in {
+        debug if ((key in requestFcts) is null)
+            logger.warn ("perRequest: replacing existing function with same key!");
+    }
+    body {
+        requestFcts[key] = fct;
+        requestFctsUpdate[key] = true;
+    }
+    
+    /** Request an update to request function key. */
+    static void requestUpdate (uint key) {
+        // Note: check the value for this key actually exists
+        bool* p = key in requestFctsUpdate;
+        if (p) *p = true;
+        else debug logger.warn ("requestUpdate called with invalid key");
     }
     
     /** This function should get called by the main loop, once per frame.
@@ -74,10 +109,19 @@
             
             fct.fct (interval);				// call
         }
+        
+        // Call all per-request functions:
+        foreach (key, fct; requestFcts) {
+            if (requestFctsUpdate[key]) {
+                fct();
+                requestFctsUpdate[key] = false;
+            }
+        }
     }
     
-    /* Holds details for functions called per time interval. */
-    private struct TimeFct {
+    /* Holds details for functions called per time interval.
+    * Needs to be a reference type, and using a class is easiest for this. */
+    private static class TimeFct {
         scheduleFct fct;			// function to call
         
         TimeSpan interval;			// interval to call at
@@ -85,15 +129,15 @@
         // be compared to time every frame where fct is not called:
         Time nextCall = Time (0L);
         
-        static TimeFct opCall (scheduleFct f, TimeSpan t) {	// static CTOR
-            TimeFct ret;
-            ret.fct = f;
-            ret.interval = t;
-            return ret;
+        this (scheduleFct f, TimeSpan t) {
+            fct = f;
+            interval = t;
         }
     }
     
     private static Time lastTime = Time (0L);
     private static scheduleFct[] frameFcts;
     private static TimeFct[] timeFcts;
+    private static void function()[uint] requestFcts;
+    private static bool[uint] requestFctsUpdate;    // associated with requestFcts
 }