Changeset 86:79d816b3e2d2
- Timestamp:
- 09/12/08 12:36:14
(4 months ago)
- Author:
- Diggory Hardy <diggory.hardy@gmail.com>
- branch:
- default
- Message:
New InitStage? system, Screen & Screen.Drawable, separate testing and guiDemo binaries.
This (and the previous) commit are the result of several quite significant changes to mde. All the unittests run, but it hasn't had a huge amount of testing so don't be surprised if bugs show up.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r85 |
r86 |
|
| 4 | 4 | |
|---|
| 5 | 5 | In progress: |
|---|
| 6 | | why is nothing drawn until a resize? seems to be working now (??) |
|---|
| 7 | | why isn't font texture drawn in mde? |
|---|
| 8 | | why does mde&guiDemo hang on exit, only if no resize occurred? |
|---|
| 9 | | wierd things with options.mtt (font section getting output twice) |
|---|
| | 6 | Sometimes nothing is drawn until a resize, and fonts are blocks? External bug? |
|---|
| 10 | 7 | CircularIterator |
|---|
| 11 | 8 | unittest again! |
|---|
| r82 |
r86 |
|
| 526 | 526 | } catch (Exception e) { |
|---|
| 527 | 527 | r = true; |
|---|
| 528 | | logger.trace ("Exception caught: "~e.msg); |
|---|
| 529 | 528 | } |
|---|
| 530 | 529 | return r; |
|---|
| r85 |
r86 |
|
| 163 | 163 | _path = path; |
|---|
| 164 | 164 | _dataset = ds; |
|---|
| 165 | | foreach (i,s; _dataset.sec) |
|---|
| 166 | | debug logger.trace ("sec ID length: {}", i.length); |
|---|
| 167 | 165 | } |
|---|
| 168 | 166 | //END CTOR / DTOR |
|---|
| … | … | |
| 181 | 179 | |
|---|
| 182 | 180 | try { |
|---|
| 183 | | debug logger.trace ("W.w: 1"); |
|---|
| 184 | 181 | FileConduit conduit; // actual conduit; don't use directly when there's content in the buffer |
|---|
| 185 | 182 | IBuffer buffer; // write strings directly to this (use opCall(void[]) ) |
|---|
| 186 | 183 | |
|---|
| 187 | | debug logger.trace ("W.w: 2"); |
|---|
| 188 | 184 | // Open a conduit on the file: |
|---|
| 189 | 185 | conduit = new FileConduit (_path, FileConduit.WriteCreate); |
|---|
| 190 | 186 | scope(exit) conduit.close(); |
|---|
| 191 | 187 | |
|---|
| 192 | | debug logger.trace ("W.w: 3"); |
|---|
| 193 | 188 | buffer = new Buffer(conduit); // And a buffer |
|---|
| 194 | 189 | scope(exit) buffer.flush(); |
|---|
| 195 | 190 | |
|---|
| 196 | | debug logger.trace ("W.w: 4"); |
|---|
| 197 | 191 | // Write the header: |
|---|
| 198 | 192 | buffer ("{MT" ~ MTFormatVersion.CurrentString ~ "}" ~ Eol); |
|---|
| 199 | | debug logger.trace ("W.w: 5"); |
|---|
| 200 | 193 | if (_dataset.header !is null) writeSection (buffer, _dataset.header); |
|---|
| 201 | 194 | |
|---|
| 202 | | debug logger.trace ("W.w: 6"); |
|---|
| 203 | 195 | // Write the rest: |
|---|
| 204 | 196 | foreach (ID id, IDataSection sec; _dataset.sec) { |
|---|
| 205 | | debug logger.trace ("W.w: 71"); |
|---|
| 206 | 197 | writeSectionIdentifier (buffer, id); |
|---|
| 207 | | debug logger.trace ("W.w: 72"); |
|---|
| 208 | 198 | writeSection (buffer, sec); |
|---|
| 209 | 199 | } |
|---|
| 210 | 200 | |
|---|
| 211 | | debug logger.trace ("W.w: 8"); |
|---|
| 212 | 201 | buffer.flush(); |
|---|
| 213 | 202 | |
|---|
| 214 | | debug logger.trace ("W.w: 9"); |
|---|
| 215 | 203 | } |
|---|
| 216 | 204 | catch (IOException e) { |
|---|
| … | … | |
| 223 | 211 | |
|---|
| 224 | 212 | private void writeSectionIdentifier (IBuffer buffer, ID id) { |
|---|
| 225 | | debug logger.trace ("W.wSI: 0"); |
|---|
| 226 | | debug logger.trace ("W.wSI: id ({})",id.length); |
|---|
| 227 | | debug logger.trace ("W.wSI: Eol ({})",Eol.length); |
|---|
| 228 | 213 | char[] tp = "{" ~ cast(char[])id ~ "}" ~ Eol; |
|---|
| 229 | | debug logger.trace ("W.wSI: 0.1"); |
|---|
| 230 | | debug logger.trace ("W.wSI: string ({}): {}",tp.length, tp); |
|---|
| 231 | 214 | buffer (tp); |
|---|
| 232 | | debug logger.trace ("W.wSI: 1"); |
|---|
| 233 | 215 | } |
|---|
| 234 | 216 | |
|---|
| r82 |
r86 |
|
| 312 | 312 | } catch (Exception e) { |
|---|
| 313 | 313 | r = true; |
|---|
| 314 | | logger.trace ("Exception caught: "~e.msg); |
|---|
| 315 | 314 | } |
|---|
| 316 | 315 | return r; |
|---|
| r85 |
r86 |
|
| 330 | 330 | float[4] Cc = [ 1.0f, 1f, 1f, 1f ]; |
|---|
| 331 | 331 | glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Cc.ptr); |
|---|
| 332 | | glColor3f (1f, 0f, 0f); |
|---|
| 333 | 332 | |
|---|
| 334 | 333 | glBegin (GL_QUADS); |
|---|
| r85 |
r86 |
|
| 131 | 131 | /** Cleanup: delete all fonts. */ |
|---|
| 132 | 132 | StageState cleanup () { |
|---|
| 133 | | // Clear loaded fonts: |
|---|
| | 133 | // Clear loaded fonts (each has an FT_Face object needing to be freed): |
|---|
| 134 | 134 | foreach (fs; fonts) |
|---|
| 135 | 135 | delete fs; |
|---|
| 136 | | fonts = null; |
|---|
| 137 | | delete fallback; |
|---|
| 138 | | |
|---|
| 139 | | delete fontTex; // clear texture |
|---|
| | 136 | |
|---|
| 140 | 137 | FT_Done_FreeType (library); // free the library |
|---|
| 141 | 138 | |
|---|
| … | … | |
| 227 | 224 | * This function will only actually update the cache if it is invalid, caused either by the |
|---|
| 228 | 225 | * font being changed or if cache.cacheVer < 0. */ |
|---|
| 229 | | void updateBlock (char[] str, ref TextBlock cache) { |
|---|
| | 226 | void updateBlock (char[] str, ref TextBlock cache) |
|---|
| | 227 | in { |
|---|
| | 228 | debug assert (face, "FontStyle: face is null"); |
|---|
| | 229 | } body { |
|---|
| 230 | 230 | try { |
|---|
| 231 | 231 | fontTex.updateCache (face, str, cache); |
|---|
| … | … | |
| 260 | 260 | * of a text block is to use a TextBlock cache and update it, either with this function or with |
|---|
| 261 | 261 | * the updateBlock function. */ |
|---|
| 262 | | void textBlock (int x, int y, char[] str, ref TextBlock cache, Colour col) { |
|---|
| | 262 | void textBlock (int x, int y, char[] str, ref TextBlock cache, Colour col) |
|---|
| | 263 | in { |
|---|
| | 264 | debug assert (face, "FontStyle: face is null"); |
|---|
| | 265 | } body { |
|---|
| 263 | 266 | try { |
|---|
| 264 | 267 | fontTex.drawCache (face, str, cache, x, y, col); |
|---|
| … | … | |
| 268 | 271 | } |
|---|
| 269 | 272 | /** ditto */ |
|---|
| 270 | | void textBlock (int x, int y, char[] str, Colour col) { |
|---|
| | 273 | void textBlock (int x, int y, char[] str, Colour col) |
|---|
| | 274 | in { |
|---|
| | 275 | debug assert (face, "FontStyle: face is null"); |
|---|
| | 276 | } body { |
|---|
| 271 | 277 | try { |
|---|
| 272 | 278 | // Using the cache method for one-time use is slightly less than optimal, but doing so |
|---|
| … | … | |
| 284 | 290 | * Set the alpha by calling glColor*() first. See FontTexture.drawCacheA()'s documentation for |
|---|
| 285 | 291 | * details. */ |
|---|
| 286 | | void textBlockA (int x, int y, char[] str, ref TextBlock cache, Colour col) { |
|---|
| | 292 | void textBlockA (int x, int y, char[] str, ref TextBlock cache, Colour col) |
|---|
| | 293 | in { |
|---|
| | 294 | debug assert (face, "FontStyle: face is null"); |
|---|
| | 295 | } body { |
|---|
| 287 | 296 | try { |
|---|
| 288 | 297 | fontTex.drawCacheA (face, str, cache, x, y, col); |
|---|
| … | … | |
| 298 | 307 | |
|---|
| 299 | 308 | ~this () { |
|---|
| 300 | | debug logger.trace ("{}.~this: start", this); |
|---|
| 301 | 309 | FT_Done_Face (face); |
|---|
| 302 | | debug logger.trace ("{}.~this: done", this); |
|---|
| 303 | 310 | } |
|---|
| 304 | 311 | |
|---|
| r85 |
r86 |
|
| 51 | 51 | * Aside from the IWidgetManager methods, this class should be thread-safe. |
|---|
| 52 | 52 | *************************************************************************************************/ |
|---|
| 53 | | class WidgetManager : WidgetLoader, Screen.Drawable { |
|---|
| | 53 | class WidgetManager : WidgetLoader, Screen.IDrawable { |
|---|
| 54 | 54 | /** Construct a new widget manager. |
|---|
| 55 | 55 | * |
|---|
| … | … | |
| 75 | 75 | /** Draw the gui. */ |
|---|
| 76 | 76 | void draw() { |
|---|
| 77 | | debug logger.trace ("drawing; w,h = {},{}",w,h); |
|---|
| 78 | 77 | synchronized(mutex) |
|---|
| 79 | 78 | if (child) |
|---|
| … | … | |
| 118 | 117 | |
|---|
| 119 | 118 | |
|---|
| 120 | | void sizeEvent (int nw, int nh) { // Drawable function |
|---|
| | 119 | void sizeEvent (int nw, int nh) { // IDrawable function |
|---|
| 121 | 120 | mutex.lock; |
|---|
| 122 | 121 | scope(exit) mutex.unlock; |
|---|
| r85 |
r86 |
|
| 162 | 162 | else debug logger.error ("Ended up with DataSection of wrong type; this should never happen."); |
|---|
| 163 | 163 | } |
|---|
| 164 | | |
|---|
| 165 | | debug (MDE_CONFIG_DUMP) { |
|---|
| 166 | | logger.trace ("Loaded {} config sections.", configs.length); |
|---|
| 167 | | foreach (id, cfg; configs) { |
|---|
| 168 | | logger.trace ("Section " ~ id ~ |
|---|
| 169 | | ":\n\tbutton:\t\t" ~ parseFrom!(uint[][][uint])(cfg.button) ~ |
|---|
| 170 | | "\n\taxis:\t\t" ~ parseFrom!(uint[][][uint])(cfg.axis) ~ |
|---|
| 171 | | "\n\trelMotion:\t" ~ parseFrom!(uint[][][uint])(cfg.relMotion) ); |
|---|
| 172 | | } |
|---|
| 173 | | } |
|---|
| 174 | 164 | } |
|---|
| 175 | 165 | |
|---|
| r85 |
r86 |
|
| 55 | 55 | foreach (js; joysticks) { |
|---|
| 56 | 56 | // FIXME: This sometimes causes a SIGSEGV (Address boundary error) when init fails. |
|---|
| 57 | | debug logger.trace ("Closing joysticks (this sometimes fails when mde exits prematurely)"); |
|---|
| 58 | 57 | if(js !is null) SDL_JoystickClose(js); // only close if successfully opened |
|---|
| 59 | | debug logger.trace ("Done closing joysticks"); |
|---|
| 60 | 58 | } |
|---|
| 61 | 59 | return StageState.INACTIVE; |
|---|
| r85 |
r86 |
|
| 137 | 137 | assert (((cast(ID) i) in subClasses) is null); // Don't allow a silent replacement |
|---|
| 138 | 138 | } body { |
|---|
| 139 | | debug logger.trace ("Adding Options subClass: "~i); |
|---|
| 140 | 139 | subClasses[cast(ID) i] = c; |
|---|
| 141 | 140 | } |
|---|
| … | … | |
| 170 | 169 | void save () { |
|---|
| 171 | 170 | if (!changed) return; // no changes to save |
|---|
| 172 | | // Types: |
|---|
| 173 | | // interface IDataSection {...} |
|---|
| 174 | | // class Options {...} |
|---|
| 175 | | // alias char[] ID; |
|---|
| 176 | | // IDataSection[ID] ds.sec; |
|---|
| 177 | | // Options[ID] subClasses; |
|---|
| | 171 | debug logger.trace ("Saving options..."); |
|---|
| | 172 | |
|---|
| 178 | 173 | DataSet ds = new DataSet(); |
|---|
| 179 | | foreach (id, subOpts; subClasses) { |
|---|
| | 174 | foreach (id, subOpts; subClasses) |
|---|
| 180 | 175 | ds.sec[id] = subOpts.optionChanges; |
|---|
| 181 | | debug logger.trace ("Saving options section: "~id); |
|---|
| 182 | | } |
|---|
| 183 | | foreach (i,s; ds.sec) |
|---|
| 184 | | debug logger.trace ("sec ID length: {}", i.length); |
|---|
| 185 | | debug logger.trace ("0"); |
|---|
| 186 | 176 | |
|---|
| 187 | 177 | // Read locally-stored options |
|---|
| … | … | |
| 190 | 180 | reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_ONLY, ds); |
|---|
| 191 | 181 | reader.dataSecCreator = delegate IDataSection(ID id) { |
|---|
| 192 | | debug logger.trace ("New section to save ignored: "~id); |
|---|
| | 182 | debug logger.warn ("New section appearing in options.mtt during save (ignored & overwritten): "~id); |
|---|
| 193 | 183 | return null; // All recognised sections are already in the dataset. |
|---|
| 194 | 184 | }; |
|---|
| … | … | |
| 202 | 192 | |
|---|
| 203 | 193 | try { |
|---|
| 204 | | debug logger.trace ("1"); |
|---|
| 205 | 194 | IWriter writer; |
|---|
| 206 | | foreach (i,s; ds.sec) |
|---|
| 207 | | debug logger.trace ("sec ID length: {}", i.length); |
|---|
| 208 | | debug logger.trace ("2"); |
|---|
| 209 | | writer = confDir.makeMTWriter (fileName, ds); // FIXME - sometimes SIGSEGV |
|---|
| 210 | | debug logger.trace ("3"); |
|---|
| 211 | | writer.write(); // FIXME - this is causing hang at exit! |
|---|
| 212 | | debug logger.trace ("4"); |
|---|
| | 195 | writer = confDir.makeMTWriter (fileName, ds); |
|---|
| | 196 | writer.write(); |
|---|
| 213 | 197 | } catch (Exception e) { |
|---|
| 214 | 198 | logger.error ("Saving options aborted: "~e.msg); |
|---|
| r85 |
r86 |
|
| 31 | 31 | import tango.time.Clock; // Clock.now() |
|---|
| 32 | 32 | import tango.util.log.Log : Log, Logger; |
|---|
| 33 | | debug (mdeUnitTest) { |
|---|
| | 33 | debug (mdeUnitTest) { // These modules contain unittests which wouldn't be run otherwise. |
|---|
| 34 | 34 | import mde.file.ssi; |
|---|
| 35 | 35 | import mde.file.mergetag.mdeUT; |
|---|
| 36 | 36 | } |
|---|
| 37 | 37 | |
|---|
| | 38 | //BEGIN A simple drawable to print a message in the window. |
|---|
| | 39 | import mde.font.font; |
|---|
| | 40 | class SimpleDrawable : Screen.IDrawable { |
|---|
| | 41 | this () { |
|---|
| | 42 | msg = "Welcome to mde.\nThis executable is only for testing, and\nas such doesn't do anything interesting."; |
|---|
| | 43 | debug msg ~= "\nRunning in debug mode."; |
|---|
| | 44 | font = FontStyle.get("default");// get the default or fallback font |
|---|
| | 45 | } |
|---|
| | 46 | void sizeEvent (int,int) {}; // Don't care what the size is |
|---|
| | 47 | void draw () { |
|---|
| | 48 | font.textBlock (16,32, msg, textCache, Colour.WHITE); |
|---|
| | 49 | } |
|---|
| | 50 | char[] msg; |
|---|
| | 51 | FontStyle font; |
|---|
| | 52 | TextBlock textCache; |
|---|
| | 53 | } |
|---|
| | 54 | //END A simple drawable to print a message in the window. |
|---|
| | 55 | |
|---|
| | 56 | |
|---|
| 38 | 57 | int main(char[][] args) |
|---|
| 39 | 58 | { |
|---|
| | 59 | Logger logger = Log.getLogger ("mde.mde"); |
|---|
| | 60 | |
|---|
| 40 | 61 | // If compiled with unittests, notify that they completed and exit: |
|---|
| 41 | 62 | debug (mdeUnitTest) { |
|---|
| 42 | | Logger logger = Log.getLogger ("mde.mde"); |
|---|
| 43 | 63 | logger.info ("Compiled unittests have completed; terminating."); |
|---|
| 44 | 64 | return 0; |
|---|
| … | … | |
| 46 | 66 | |
|---|
| 47 | 67 | scope Init init = new Init(args); // initialize mde |
|---|
| | 68 | |
|---|
| | 69 | // Note: must create the drawable after init, since it uses font (initialized in init). |
|---|
| | 70 | Screen.addDrawable (new SimpleDrawable); // a drawable to print a message. |
|---|
| 48 | 71 | |
|---|
| 49 | 72 | // Make sure pollInterval has a sane value. FIXME: get Options class to enforce range |
|---|
| r85 |
r86 |
|
| 258 | 258 | } |
|---|
| 259 | 259 | } |
|---|
| 260 | | debug logger.trace ("Added {} init/cleanup stages", toRun.size); |
|---|
| 261 | 260 | int numWorking = miscOpts.numThreads; |
|---|
| 262 | 261 | bool abortInit = false; |
|---|
| … | … | |
| 276 | 275 | * When notified, threads start at 1. */ |
|---|
| 277 | 276 | void initThreadFct () { |
|---|
| 278 | | debug logger.trace ("initThreadFct: starting"); |
|---|
| 279 | 277 | try { // created as a thread - must not throw exceptions |
|---|
| 280 | 278 | InitStage* stage; |
|---|
| … | … | |
| 347 | 345 | } |
|---|
| 348 | 346 | toRunC.notifyAll(); // Most likely if we're exiting, we should make sure others aren't waiting. |
|---|
| 349 | | debug logger.trace ("initThreadFct: returning"); |
|---|
| 350 | 347 | return; |
|---|
| 351 | 348 | } |
|---|
| … | … | |
| 397 | 394 | |
|---|
| 398 | 395 | debug (mdeUnitTest) unittest { |
|---|
| 399 | | logger.trace ("Starting unittest"); |
|---|
| 400 | | |
|---|
| 401 | 396 | auto realInit = stages; // backup the real init stages |
|---|
| 402 | 397 | stages = new typeof(stages); // an empty test-bed |
|---|
| r85 |
r86 |
|
| 36 | 36 | // TYPES (these mustn't be static): |
|---|
| 37 | 37 | /** Interface for anything hooking into the screen for drawing, etc. */ |
|---|
| 38 | | interface Drawable { |
|---|
| | 38 | interface IDrawable { |
|---|
| 39 | 39 | /** Called on window creation and whenever the window manager resizes the window, before |
|---|
| 40 | 40 | * the new size is set. The new size is passed. |
|---|
| … | … | |
| 64 | 64 | throw new InitException ("SDL Initialization failed"); |
|---|
| 65 | 65 | } |
|---|
| 66 | | debug logger.trace ("SDL initialised"); |
|---|
| 67 | 66 | return StageState.ACTIVE; |
|---|
| 68 | 67 | } |
|---|
| … | … | |
| 100 | 99 | |
|---|
| 101 | 100 | // Open a window |
|---|
| 102 | | debug logger.trace ("Opening a window (this can crash if the libraries are messed up)"); |
|---|
| 103 | 101 | if (setWindow (w, h)) { |
|---|
| 104 | 102 | throw new InitException ("Failed to open a window"); |
|---|
| … | … | |
| 170 | 168 | } |
|---|
| 171 | 169 | |
|---|
| 172 | | /** Add a drawable element to the screen (see Drawable interface). |
|---|
| | 170 | /** Add a drawable element to the screen (see IDrawable interface). |
|---|
| 173 | 171 | * |
|---|
| 174 | | * Should be called before Init to get initial size. Currently no means to remove drawables, |
|---|
| 175 | | * and not really designed for more than one. */ |
|---|
| 176 | | void addDrawable (Drawable d) { |
|---|
| | 172 | * Should be called before Init to get the initial size (sizeEvent is only called when the size |
|---|
| | 173 | * is set). Currently no means to remove drawables, and not really designed for more than one. |
|---|
| | 174 | */ |
|---|
| | 175 | void addDrawable (IDrawable d) { |
|---|
| 177 | 176 | drawables ~= d; |
|---|
| 178 | 177 | } |
|---|
| … | … | |
| 182 | 181 | glClear(GL_COLOR_BUFFER_BIT); |
|---|
| 183 | 182 | |
|---|
| 184 | | foreach (Drawable d; drawables) |
|---|
| | 183 | foreach (IDrawable d; drawables) |
|---|
| 185 | 184 | d.draw; |
|---|
| 186 | 185 | |
|---|
| 187 | | debug (drawGlyphCache) { |
|---|
| 188 | | logger.trace ("Drawing font texture"); |
|---|
| 189 | | FontStyle.drawTexture; |
|---|
| 190 | | } |
|---|
| | 186 | debug (drawGlyphCache) FontStyle.drawTexture; |
|---|
| 191 | 187 | |
|---|
| 192 | 188 | // Error check: |
|---|
| … | … | |
| 207 | 203 | d.sizeEvent (w,h); |
|---|
| 208 | 204 | |
|---|
| 209 | | debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags); |
|---|
| | 205 | //debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags); |
|---|
| 210 | 206 | if (SDL_SetVideoMode (w, h, 32, flags) is null) { |
|---|
| 211 | 207 | logger.fatal ("Unable to set video mode:"); |
|---|
| … | … | |
| 264 | 260 | private: |
|---|
| 265 | 261 | uint flags = 0; |
|---|
| 266 | | Drawable[] drawables; |
|---|
| | 262 | IDrawable[] drawables; |
|---|
| 267 | 263 | Logger logger; |
|---|
| 268 | 264 | OptionsVideo vidOpts; |
|---|