Mercurial > projects > mde
view mde/setup/Screen.d @ 98:49e7cfed4b34
All types of Option have been converted to use ValueContent classes, and their values can be displayed.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 12 Nov 2008 13:18:51 +0000 |
parents | 30470bc19ca4 |
children | ee209602770d |
line wrap: on
line source
/* 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 as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. 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, see <http://www.gnu.org/licenses/>. */ /** Screen: SDL & OpenGL setup/cleanup, drawing. * * Has an interface by which other code can hook in for drawing and resize notifications. */ module mde.setup.Screen; import mde.setup.exception; import mde.lookup.Options; import imde = mde.imde; debug (drawGlyphCache) import mde.font.font; import tango.util.log.Log : Log, Logger; import tango.stdc.stringz; import tango.time.Time; // TimeSpan (type only; unused) import derelict.sdl.sdl; import derelict.opengl.gl; import derelict.util.exception; /** Currently just used as a namespace. Potential for multiple screen support later? */ struct Screen { // TYPES (these mustn't be static): /** Interface for anything hooking into the screen for drawing, etc. */ interface IDrawable { /** Called on window creation and whenever the window manager resizes the window, before * the new size is set. The new size is passed. * * The parameters were passed as ref to allow the called function to change them, but SDL * didn't appear able to resize the window (on X11), so this was dropped. */ void sizeEvent (int w, int h); /** Called you guess when :-) */ void draw (); } /** All video options. */ class VideoOptions : Options { mixin (impl!("bool fullscreen,hardware,resizable,noFrame; int screenW,screenH,windowW,windowH;")); } static: /** Init function to initialize SDL. */ StageState init () { // init func // Initialise SDL debug logger.trace ("Calling SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)"); if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK /+| SDL_INIT_EVENTTHREAD+/)) { logger.fatal ("SDL initialisation failed:"); char* msg = SDL_GetError (); logger.fatal (msg ? fromStringz(msg) : "no reason available"); throw new InitException ("SDL Initialization failed"); } return StageState.ACTIVE; } /** SDL shutdown */ StageState cleanup () { debug logger.trace ("Calling SDL_Quit ()"); SDL_Quit(); return StageState.INACTIVE; } /** Init function to set up a window with OpenGL support. */ StageState initWindow () { //BEGIN Create window and initialize OpenGL // Window creation flags and size flags = SDL_OPENGL; if (videoOpts.hardware()) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF; else flags |= SDL_SWSURFACE; int w, h; if (videoOpts.fullscreen()) { flags |= SDL_FULLSCREEN; w = videoOpts.screenW(); h = videoOpts.screenH(); } else { if (videoOpts.resizable()) flags |= SDL_RESIZABLE; if (videoOpts.noFrame()) flags |= SDL_NOFRAME; w = videoOpts.windowW(); h = videoOpts.windowH(); } // OpenGL attributes SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); // Open a window if (setWindow (w, h)) { throw new InitException ("Failed to open a window"); } /* Now (must be done after GL context is created) we can try to load later version. * The initial loading provides opengl 1.1 features. * * 1.4 is now used for glBlendColor (coloured text). * * Currently the latest version used is 1.3; adjust this as necessary. However, before using * features from any OpenGL version > 1.1 a check must be made on what was loaded by calling * DerelictGL.availableVersion(). Note that availableVersion() could be used instead to load * the highest supported version but this way we know what we're getting. */ if (DerelictGL.availableVersion < GLVersion.Version13) { throw new InitException ("Required at least OpenGL 1.3; didn't get this."); } /+try { DerelictGL.loadVersions(GLVersion.Version14); } catch (SharedLibProcLoadException e) { logger.warn ("Loading OpenGL version 1.4 failed:"); logger.warn (e.msg); setInitFailure (); return; }+/ // OpenGL stuff: glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glShadeModel(GL_SMOOTH); glClearColor (0.0f, 0.0f, 0.0f, 0.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Used for font rendering: glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //NOTE: wrap mode may have an effect, but shouldn't be noticed... // Window-manager settings SDL_WM_SetCaption (toStringz ("mde"), null); // SDL_WM_GrabInput (use later) //END Create window and initialize OpenGL return StageState.ACTIVE; } /** Called when a resize event occurs (when the window manager resizes the window). */ void resizeEvent (int w, int h) { // Save new size to config if (videoOpts.fullscreen()) { // probably resizeEvent only called when not fullscreen videoOpts.screenW = w; videoOpts.screenH = h; } else { videoOpts.windowW = w; videoOpts.windowH = h; } if (setWindow (w,h)) imde.run = false; } /** Add a drawable element to the screen (see IDrawable interface). * * Should be called before Init to get the initial size (sizeEvent is only called when the size * is set). Currently no means to remove drawables, and not really designed for more than one. */ void addDrawable (IDrawable d) { drawables ~= d; } /** Drawing function */ void draw (TimeSpan) { glClear(GL_COLOR_BUFFER_BIT); foreach (d; drawables) { try { d.draw; } catch (Exception e) { logger.error ("Drawable failed to draw: "~e.msg); } } debug (drawGlyphCache) FontStyle.drawTexture; // Error check: GLenum err = glGetError(); while (err != GL_NO_ERROR) { logger.error ("GL error: {}", err); err = glGetError(); } glFinish(); // Use Finish rather than Flush to make sure gl is ready to swap buffers SDL_GL_SwapBuffers(); } /** Set a new window size. Returns true on failure due to the different ways this must be * handled. */ private bool setWindow (int w, int h) { foreach (d; drawables) { // Tell all drawables the new window size. try { d.sizeEvent (w,h); } catch (Exception e) { logger.error ("Drawable failed while setting size: "~e.msg); } } //debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags); debug logger.trace ("Calling SDL_SetVideoMode ({}, {}, 32, 0x{:x})", w,h, flags); 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"); // Print a load of info: logger.info ("Available video modes:"); SDL_Rect** modes = SDL_ListModes (null, SDL_FULLSCREEN); if (modes is null) logger.info ("None!"); else if (modes is cast(SDL_Rect**) -1) logger.info ("All modes are available"); else { for (uint i = 0; modes[i] !is null; ++i) { logger.info ("\t{}x{}", modes[i].w, modes[i].h); } } SDL_VideoInfo* vi = SDL_GetVideoInfo (); if (vi !is null) { logger.info ("Video info:"); logger.info ("Hardware surface support: "~ (vi.flags & SDL_HWSURFACE ? "yes" : "no")); logger.info ("Video memory: {}", vi.video_mem); if (vi.vfmt !is null) { logger.info ("Best video mode:"); logger.info ("Bits per pixel: {}", vi.vfmt.BitsPerPixel); } } return true; } // Reset the projection and viewport glMatrixMode (GL_PROJECTION); glLoadIdentity (); glViewport (0,0,w,h); // Make the top-left the origin (see gui/GUI notes.txt): // Note that this only affects vertex operations − direct rasterisation operations are // unaffected! glOrtho (0.0,w, h,0.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); return false; } static this() { logger = Log.getLogger ("mde.setup.Screen"); videoOpts = new VideoOptions; Options.addOptionsClass (videoOpts, "VideoOptions"); } // DATA: private: uint flags = 0; IDrawable[] drawables; Logger logger; VideoOptions videoOpts; }