/*
 * glut_gamemode.c
 *
 * Adapted from the FreeGLUT library by Hans de Ruiter.
 * The FreeGLUT license holds for this file.
 *
 * The game mode handling code.
 *
 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
 * Creation date: Thu Dec 16 1999
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "mgl/gl.h"
#include <GL/glut.h>
#include <MGL/minigl.h>
#include <interfaces/minigl.h>
#include "glut_internal.h"

extern struct MiniGLIFace *IMiniGL;

/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */

/**
 * Returns true if the game mode specified in the last game mode string is valid
 */
static GLboolean isModeValid(GLsizei width, GLsizei height, GLint depth)
{
	return IMiniGL->ScreenModeIsSupported(width, height, depth);
}

/* -- INTERFACE FUNCTIONS -------------------------------------------------- */

/*
 * Sets the game mode display string
 */
void glut_GLUTGameModeString(struct GlutIFace *Self,  const char* string )
{
    GLUTcontext ctx = (GLUTcontext)GET_INSTANCE(Self);
    int width = 640, height = 480, depth = 16, refresh = 72;

    /*
     * This one seems a bit easier than glutInitDisplayString. The bad thing
     * about it that I was unable to find the game mode string definition, so
     * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
     * appears in all GLUT game mode programs I have seen to date.
     */
    if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) !=
        4 )
        if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
            if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
                if( sscanf( string, "%ix%i", &width, &height ) != 2 )
                    if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
                        if( sscanf( string, ":%i", &depth ) != 1 )
                            if( sscanf( string, "@%i", &refresh ) != 1 )
								dprintf(
                                    "unable to parse game mode string `%s'",
                                    string
                                );

    /* Hopefully it worked, and if not, we still have the default values */
	ctx->gameModeSize.X  = width;
	ctx->gameModeSize.Y  = height;
	ctx->gameModeDepth   = depth;
	ctx->gameModeRefresh = refresh;

	if(depth == 32)
	{
		// A workaround for Warp3D not knowing what a 32-bit screenmode is
		ctx->gameModeDepth   = 24;
	}
}

/*
 * Enters the game mode
 */
int glut_GLUTEnterGameMode(struct GlutIFace *Self)
{
    GLUTcontext ctx = (GLUTcontext)GET_INSTANCE(Self);

	if(ctx->gameModeData.gameModeActive)
	{
		return ctx->gameModeData.windowID;
	}

	if(ctx->__glutContext)
	{
        ctx->__glutContext->DeleteContext();
		ctx->__glutContext = 0;
	}

	ctx->gameModeData.windowID = Self->GLUTCreateWindow("");

	dprintf("windowID %d\n", ctx->gameModeData.windowID);

	if(ctx->gameModeData.windowID == -1)
	{
		return -1;
	}

	if(ctx->__glutContext->SetDisplayMode(GL_FALSE, ctx->gameModeSize.X,
				 ctx->gameModeSize.Y, ctx->gameModeDepth) == GL_FALSE)
	{
        Self->GLUTDestroyWindow(ctx->gameModeData.windowID);
		ctx->gameModeData.windowID = -1;
		ctx->gameModeData.gameModeActive = GL_FALSE;
		return -1;
	}
	ctx->gameModeData.gameModeActive = GL_TRUE;

    ctx->GlutW = ctx->gameModeSize.X;
	ctx->GlutH = ctx->gameModeSize.Y;

    return ctx->gameModeData.windowID;
}

/*
 * Leaves the game mode
 */
void glut_GLUTLeaveGameMode(struct GlutIFace *Self)
{
    GLUTcontext ctx = (GLUTcontext)GET_INSTANCE(Self);
	
	if(ctx->gameModeData.gameModeActive)
	{
		Self->GLUTDestroyWindow(ctx->gameModeData.windowID);
		ctx->gameModeData.gameModeActive = GL_FALSE;
	}
}

/*
 * Returns information concerning the freeglut game mode
 */
int glut_GLUTGameModeGet(struct GlutIFace *Self,  GLenum eWhat )
{
    GLUTcontext ctx = (GLUTcontext)GET_INSTANCE(Self);
    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" );

    switch( eWhat )
    {
    case GLUT_GAME_MODE_ACTIVE:
		return ctx->gameModeData.gameModeActive;

    case GLUT_GAME_MODE_POSSIBLE:
		return isModeValid(ctx->gameModeSize.X, ctx->gameModeSize.Y, ctx->gameModeDepth);

    case GLUT_GAME_MODE_WIDTH:
		return ctx->gameModeSize.X;

    case GLUT_GAME_MODE_HEIGHT:
		return ctx->gameModeSize.Y;

    case GLUT_GAME_MODE_PIXEL_DEPTH:
		return ctx->gameModeDepth;

    case GLUT_GAME_MODE_REFRESH_RATE:
		return ctx->gameModeRefresh;

    case GLUT_GAME_MODE_DISPLAY_CHANGED:
        /*
         * This is true if the game mode has been activated successfully..
         */
		return ctx->gameModeData.gameModeActive;
    }

	dprintf( "Unknown gamemode get: %d", eWhat );
    return -1;
}

/*** END OF FILE ***/
