view mde/setup/sdl.d @ 63:66d555da083e

Moved many modules/packages to better reflect usage.
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 27 Jun 2008 18:35:33 +0100
parents mde/sdl.d@f3d8c0441408
children cc3763817b8a
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/>. */

/** Just a temporary place to put SDL Init and Video stuff.
*/
module mde.setup.sdl;

import mde.setup.initFunctions;
import mde.input.joystick;
import mde.lookup.Options;
import mde.gl.basic;
import imde = mde.imde;

import tango.util.log.Log : Log, Logger;
import tango.stdc.stringz;

import derelict.sdl.sdl;
import derelict.opengl.gl;	// for loading a later gl version
import derelict.util.exception;

private Logger logger;
static this() {
    logger = Log.getLogger ("mde.setup.sdl");
    
    init.addFunc (&initSdlAndGl, "initSdlAndGl");
}

private uint flags = 0;

void initSdlAndGl() {   // init func
    // Initialise SDL
    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");
        
        setInitFailure ();
        return;
    }
    
    debug logger.trace ("SDL initialised");
    
    // Must be called after SDL has been initialised, so cannot be a separate Init function.
    openJoysticks ();                   // after SDL init
    cleanup.addFunc (&cleanupSDL, "cleanupSDL");
    
    setupWindow();
}

void setupWindow() {    // indirect init func (depends on initSdlAndGl)
    // Window creation flags and size
    flags = SDL_OPENGL;
    if (vidOpts.hardware) flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
    else flags |= SDL_SWSURFACE;
    int w, h;
    if (vidOpts.fullscreen) {
        flags |= SDL_FULLSCREEN;
        w = vidOpts.screenW;
        h = vidOpts.screenH;
    }
    else {
        if (vidOpts.resizable) flags |= SDL_RESIZABLE;
        if (vidOpts.noFrame) flags |= SDL_NOFRAME;
        w = vidOpts.windowW;
        h = vidOpts.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
    debug logger.trace ("Opening a window (this can crash if the libraries are messed up)");
    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:");
        char[128] tmp;
        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 (logger.format (tmp, "\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 (logger.format (tmp, "Video memory: {}", vi.video_mem));
    
            if (vi.vfmt !is null) {
                logger.info ("Best video mode:");
                logger.info (logger.format (tmp, "Bits per pixel: {}", vi.vfmt.BitsPerPixel));
            }
        }
        
        setInitFailure ();
        return;
    }
    
    /* 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) {
        logger.fatal ("Required at least OpenGL 1.3");
        setInitFailure;
        return;
    }
    /+try {
        DerelictGL.loadVersions(GLVersion.Version14);
    } catch (SharedLibProcLoadException e) {
        logger.warn ("Loading OpenGL version 1.4 failed:");
        logger.warn (e.msg);
        
        //NOTE: might be worth guaranteeing a minimal version to save later checks?
        /+ Do this if you want the program to abort:
        setInitFailure ();
        return;
        +/
    }+/
    
    // OpenGL stuff:
    glSetup();
    setProjection (w, h);
    
    // Window-manager settings
    SDL_WM_SetCaption (toStringz ("mde"), null);
    // SDL_WM_GrabInput (use later)
}

void resizeWindow (int w, int h) {
    if (vidOpts.fullscreen) {
        Options.setInt ("video", "screenW", w);
        Options.setInt ("video", "screenH", h);
    } else {
        Options.setInt ("video", "windowW", w);
        Options.setInt ("video", "windowH", h);
    }
    
    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");
        
        imde.run = false;
    }
    
    // Reset the projection and viewport
    setProjection (w, h);
}

void cleanupSDL () {    // cleanup func
    closeJoysticks();
    SDL_Quit();
}


/** All video options. */
OptionsVideo vidOpts;
class OptionsVideo : Options {
    mixin (impl!("bool fullscreen,hardware,resizable,noFrame; int screenW,screenH,windowW,windowH;"));
    
    static this() {
        vidOpts = new OptionsVideo;
        Options.addOptionsClass (vidOpts, "video");
    }
}