/*
 * $Id$
 *
 * $Date$
 * $Revision$
 *
 * (C) 1999 by Hyperion
 * All rights reserved
 *
 * This file is part of the MiniGL library project
 * See the file Licence.txt for more details
 *
 */
#define __USE_INLINE__
#include "mgl/gl.h"
#include <math.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <libraries/lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos/dos.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/lowlevel.h>
#include <proto/dos.h>
#include <proto/graphics.h>

#define inline __inline
#define M_PI 3.1415927
int kprintf(char *format, ...)
{
    return 0;
}

struct Library *LowLevelBase;
struct LowLevelIFace *ILowLevel;

#ifndef __PPC__
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Library *UtilityBase;
extern struct DosLibrary *DOSBase;
extern struct ExecBase *SysBase;
#endif

extern int kprintf(char *format, ...);
#define DEBUG(x) kprintf x

extern void GLPrintMatrix(int);

static struct EClockVal eval;
static float fps;
static GLfloat fog_start, fog_end;
static GLboolean fogon = GL_FALSE;
static GLboolean sync = GL_TRUE;

typedef struct
{
    GLfloat x,y,z,u,v;
} MyVertex;

static MyVertex vertices1 [] =
{
    {-1, -1, -1, 0.5, 0.5}, // 0
    {-1, -1,  1, 0.5, 0.0}, // 1
    {-1,  1,  1, 0.0, 0.0}, // 2
    {-1,  1, -1, 0.0, 0.5}, // 3
    { 1,  1, -1, 0.0, 1.0}, // 4
    { 1, -1, -1, 0.5, 1.0}, // 5
    { 1, -1,  1, 1.0, 1.0}, // 6
    {-1, -1,  1, 1.0, 0.5}  // 7
};

static MyVertex vertices2 [] =
{
    { 1,  1,  1, 0.5, 0.5}, // 0
    { 1, -1,  1, 0.5, 0.0}, // 1
    { 1, -1, -1, 0.0, 0.0}, // 2
    { 1,  1, -1, 0.0, 0.5}, // 3
    {-1,  1, -1, 0.0, 1.0}, // 4
    {-1,  1,  1, 0.5, 1.0}, // 5
    {-1, -1,  1, 1.0, 1.0}, // 6
    { 1, -1,  1, 1.0, 0.5}  // 7
};

struct ResInfo
{
    int width, height;
    char *name;
};

struct ResInfo Resolutions [] =
{
    {320, 240, "320 x 240"},
    {400, 300, "400 x 300"},
    {640, 480, "640 x 480"},
    {800, 600, "800 x 600"}, // Out of memory...
    {1024, 768, "1024 x 768"},
    {-1, -1, NULL}
};

GLint ResPtr;
char *CurrentRes;
GLboolean ShowRes = GL_TRUE;
GLboolean zbuffer = GL_TRUE;

GLfloat mouse_x = 0.0, mouse_y = 0.0, mouse_z = 0.0;
GLint offset = 0;
GLfloat fov = 70.0;
GLfloat inf_w = 0.1;
GLfloat zback = 1000.0;
GLfloat alpha = 1.0;

GLubyte index_texture[] =
{
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,
    1,0,1,2,2,2,2,2,2,2,2,2,2,1,0,1,
    1,0,1,2,1,1,1,1,1,1,1,1,2,1,0,1,
    1,0,1,2,1,3,3,3,3,3,3,1,2,1,0,1,
    1,0,1,2,1,3,1,1,1,1,3,1,2,1,0,1,
    1,0,1,2,1,3,1,4,4,1,3,1,2,1,0,1,
    1,0,1,2,1,3,1,4,4,1,3,1,2,1,0,1,
    1,0,1,2,1,3,1,1,1,1,3,1,2,1,0,1,
    1,0,1,2,1,3,3,3,3,3,3,1,2,1,0,1,
    1,0,1,2,1,1,1,1,1,1,1,1,2,1,0,1,
    1,0,1,2,2,2,2,2,2,2,2,2,2,1,0,1,
    1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,
    1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};

GLubyte palette[] =
{
    0x00, 0x00, 0x00,
    0xFF, 0x00, 0x00,
    0x00, 0xFF, 0x00,
    0x00, 0x00, 0xff,
    0xFF, 0xFF, 0xFF,
};

static void ReplaceTexture(void)
{
    GLenum error;
    int i=1;

    glDeleteTextures(1, (const unsigned int *)&i);
    glBindTexture(GL_TEXTURE_2D, 1);
    glColorTable(GL_COLOR_TABLE, GL_RGB, 5, GL_RGB, GL_UNSIGNED_BYTE, palette);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, index_texture);
    error = glGetError();
    kprintf("Error = %d\n", error);
}

static void MakeRot(GLfloat angle1, GLfloat angle2)
{
    GLfloat sinel = (GLfloat)sin((double)angle1/180*M_PI);
    GLfloat cosel = (GLfloat)cos((double)angle1/180*M_PI);
    GLfloat sinaz = (GLfloat)sin((double)angle2/180*M_PI);
    GLfloat cosaz = (GLfloat)cos((double)angle2/180*M_PI);
    GLfloat mat[16];

    mat[0] = cosaz;        mat[4] = 0.0;    mat[8] = -sinaz;       mat[12] = 0;
    mat[1] = -sinel*sinaz; mat[5] = cosel;  mat[9] = -sinel*cosaz; mat[13] = 0.0;
    mat[2] = cosel*sinaz;  mat[6] = sinel;  mat[10] = cosel*cosaz; mat[14] = 0.0;
    mat[3] =               mat[7] =         mat[11] = 0.0;         mat[15] = 1.0;
    glMultMatrixf(mat);
}


void PrExit(void)
{
    if (LowLevelBase)   CloseLibrary(LowLevelBase);
    exit(0L);
}

void PrInit(void)
{
    LowLevelBase  = OpenLibrary("lowlevel.library", 40L);
    if (!LowLevelBase) PrExit();
}

GLdouble angle = 0.0;
GLfloat mouse_angle_x = 0.0;
GLfloat mouse_angle_y = 0.0;
GLfloat tlow = 0.0;
GLfloat offx = 0.f, offy = 0.f;
GLdouble zclear = 1.0;
GLenum primitive = GL_POLYGON;

/*
** Load a PPM file into memory.
** The resulting pointer can be free()'d
*/
GLubyte *LoadPPM(char *name, GLint *w, GLint *h)
{
    int i;
    unsigned long x,y;
    FILE *f;
    GLubyte *where;

    f = fopen(name, "r");

    if (!f)
    {
	*w = 0; *h=0;
	return NULL;
    }
    #ifndef __STORM__
    i = fscanf(f, "P6\n%ld %ld\n255\n",&x, &y);
    #else
    i = fscanf(f, "P6\n%ld\n%ld\n255\n", &x, &y);
    #endif

    if (i!= 2)
    {
	printf("Error scanning PPM header\n");
	fclose(f);
	*w = 0; *h = 0;
	return NULL;
    }

    *w = x;
    *h = y;

    where = malloc(x*y*3);
    if (!where)
    {
	printf("Error out of Memory\n");
	fclose(f);
	*w = 0; *h = 0;
	return NULL;
    }

    i = fread(where, 1, x*y*3, f);
    fclose(f);

    if (i != x*y*3)
    {
	printf("Error while reading file\n");
	free(where);
	*w = 0; *h = 0;
	return NULL;
    }

    return where;
}

void TexInit(void)
{
    GLubyte *tmap;
    GLint x,y;

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);

    tmap = LoadPPM("data/t1.ppm",&x, &y);
    glBindTexture(GL_TEXTURE_2D, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, 3,
	x,y, 0, GL_RGB, GL_UNSIGNED_BYTE, tmap);
    free(tmap);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    tmap = LoadPPM("data/t2.ppm",&x, &y);
    glBindTexture(GL_TEXTURE_2D, 2);
    glTexImage2D(GL_TEXTURE_2D, 0, 3,
	x,y, 0, GL_RGB, GL_UNSIGNED_BYTE, tmap);
    free(tmap);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    tmap = LoadPPM("data/stars.ppm",&x, &y);
    glBindTexture(GL_TEXTURE_2D, 3);
    glTexImage2D(GL_TEXTURE_2D, 0, 3,
	x,y, 0, GL_RGB, GL_UNSIGNED_BYTE, tmap);
    free(tmap);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

}

static void drawCubeFan(GLint tex1, GLint tex2)
{
    GLfloat w = 1.0;

    if (tex1 == tex2) w = inf_w;

    glBindTexture(GL_TEXTURE_2D, tex1);
    glBegin(GL_TRIANGLE_FAN);
	//glColor3f(1.0, 0.0, 0.0);
	glTexCoord2f(vertices1[0].u, vertices1[0].v);
	glVertex4f(vertices1[0].x, vertices1[0].y, vertices1[0].z,w);
	if (tex1 != tex2) glColor4f(0.7, 0.7, 0.7, alpha);
	glTexCoord2f(vertices1[1].u, vertices1[1].v);
	glVertex4f(vertices1[1].x, vertices1[1].y, vertices1[1].z,w);
	glTexCoord2f(vertices1[2].u, vertices1[2].v);
	glVertex4f(vertices1[2].x, vertices1[2].y, vertices1[2].z,w);
	glTexCoord2f(vertices1[3].u, vertices1[3].v);
	glVertex4f(vertices1[3].x, vertices1[3].y, vertices1[3].z,w);
	glTexCoord2f(vertices1[4].u, vertices1[4].v);
	glVertex4f(vertices1[4].x, vertices1[4].y, vertices1[4].z,w);
	glTexCoord2f(vertices1[5].u, vertices1[5].v);
	glVertex4f(vertices1[5].x, vertices1[5].y, vertices1[5].z,w);
	glTexCoord2f(vertices1[6].u, vertices1[6].v);
	glVertex4f(vertices1[6].x, vertices1[6].y, vertices1[6].z,w);
	glTexCoord2f(vertices1[7].u, vertices1[7].v);
	glVertex4f(vertices1[7].x, vertices1[7].y, vertices1[7].z,w);
    glEnd();

    glBindTexture(GL_TEXTURE_2D, tex2);
    glBegin(GL_TRIANGLE_FAN);
	if (tex1 != tex2) glColor4f(0.0, 1.0, 0.0, alpha);
	glTexCoord2f(vertices2[0].u, vertices2[0].v);
	glVertex4f(vertices2[0].x, vertices2[0].y, vertices2[0].z,w);
	if (tex1 != tex2) glColor4f(0.7, 0.7, 0.7, alpha);
	glTexCoord2f(vertices2[1].u, vertices2[1].v);
	glVertex4f(vertices2[1].x, vertices2[1].y, vertices2[1].z,w);
	glTexCoord2f(vertices2[2].u, vertices2[2].v);
	glVertex4f(vertices2[2].x, vertices2[2].y, vertices2[2].z,w);
	glTexCoord2f(vertices2[3].u, vertices2[3].v);
	glVertex4f(vertices2[3].x, vertices2[3].y, vertices2[3].z,w);
	glTexCoord2f(vertices2[4].u, vertices2[4].v);
	glVertex4f(vertices2[4].x, vertices2[4].y, vertices2[4].z,w);
	glTexCoord2f(vertices2[5].u, vertices2[5].v);
	glVertex4f(vertices2[5].x, vertices2[5].y, vertices2[5].z,w);
	glTexCoord2f(vertices2[6].u, vertices2[6].v);
	glVertex4f(vertices2[6].x, vertices2[6].y, vertices2[6].z,w);
	glTexCoord2f(vertices2[7].u, vertices2[7].v);
	glVertex4f(vertices2[7].x, vertices2[7].y, vertices2[7].z,w);
    glEnd();
}

#if !defined(__STORM__) && !defined(__VBCC__)
static
#endif
inline void myVertex(int i)
{
    glTexCoord2f(vertices1[i].u, vertices1[i].v);
    glVertex3f(vertices1[i].x, vertices1[i].y, vertices1[i].z);
}

#if !defined(__STORM__) && !defined(__VBCC__)
static
#endif
inline void myVertex2(int i)
{
    glTexCoord2f(vertices2[i].u, vertices2[i].v);
    glVertex3f(vertices2[i].x, vertices1[i].y, vertices2[i].z);
}

static void drawCubeQuad(GLint tex1, GLint tex2)
{
    glDisable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
	glColor3f(1.0, 0.0, 0.0);
	glVertex3f(-1,-1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,-1); glVertex3f(1,1,-1); glVertex3f(1,-1,-1);

	glColor3f(1.0, 0.5, 0.0);
	glVertex3f(-1,1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,1); glVertex3f(1,1,1); glVertex3f(1,1,-1);

	glColor3f(0.0, 1.0, 0.0);
	glVertex3f(1,1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(1,1,1); glVertex3f(1,-1,1); glVertex3f(1,-1,-1);

	glColor3f(0.0, 0.0, 1.0);
	glVertex3f(1,1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,1); glVertex3f(-1,-1,1); glVertex3f(1,-1,1);

	glColor3f(0.0, 0.0, 0.0);
	glVertex3f(-1,1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,-1); glVertex3f(-1,-1,-1); glVertex3f(-1,-1,1);

	glColor3f(1.0, 1.0, 1.0);
	glVertex3f(-1,-1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,-1,-1);
	glVertex3f(1,-1,-1);
	glVertex3f(1,-1,1);

    glEnd();
    glEnable(GL_TEXTURE_2D);
}

static void drawCubePoly(GLint tex1, GLint tex2)
{
    glDisable(GL_TEXTURE_2D);
    glBegin(GL_POLYGON);
	glColor3f(1.0, 0.0, 0.0);
	glVertex3f(-1,-1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,-1); glVertex3f(1,1,-1); glVertex3f(1,-1,-1);
    glEnd();
    glBegin(GL_POLYGON);
	glColor3f(1.0, 0.5, 0.0);
	glVertex3f(-1,1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,1); glVertex3f(1,1,1); glVertex3f(1,1,-1);
    glEnd();
    glBegin(GL_POLYGON);
	glColor3f(0.0, 1.0, 0.0);
	glVertex3f(1,1,-1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(1,1,1); glVertex3f(1,-1,1); glVertex3f(1,-1,-1);
    glEnd();
    glBegin(GL_POLYGON);
	glColor3f(0.0, 0.0, 1.0);
	glVertex3f(1,1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,1); glVertex3f(-1,-1,1); glVertex3f(1,-1,1);
    glEnd();
    glBegin(GL_POLYGON);
	glColor3f(0.0, 0.0, 0.0);
	glVertex3f(-1,1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,1,-1); glVertex3f(-1,-1,-1); glVertex3f(-1,-1,1);
    glEnd();
    glBegin(GL_POLYGON);
	glColor3f(1.0, 1.0, 1.0);
	glVertex3f(-1,-1,1); glColor3f(0.5, 0.5, 0.5);
	glVertex3f(-1,-1,-1);
	glVertex3f(1,-1,-1);
	glVertex3f(1,-1,1);
    glEnd();
    glEnable(GL_TEXTURE_2D);
}


typedef void (*drawFunc)(GLint, GLint);

drawFunc funcs[] =
{
    drawCubeFan,
    drawCubeQuad,
    drawCubePoly,
    NULL,
};

static void (*drawCube)(GLint, GLint) = drawCubeFan;

void Rot1(void)
{
    glLoadIdentity();
    glTranslatef(0.f, 0.f, -8.f);
    glRotatef(angle, 0.f, 1.f, 1.f);
}

void Rot2(void)
{
    glLoadIdentity();
    glTranslatef(1.0, 3.0, -8.f);
    glRotatef(-angle, 0.f, 1.f, 1.f);
    glScalef(0.8, 2.0, 1.2);
}

void Rot3(void)
{
    glLoadIdentity();
    glTranslatef(-3.0, 2.0, -7.0);
    glRotatef(-90, 1,0,0);
    glRotatef(90, 0,0,1);
    glRotatef(angle, 1.0, 0.0, 0.0);
    glRotatef(-angle, 0.0, 1.0, 0.0);
    glRotatef(angle/2.0, 0.0, 0.0, 1.0);
    glRotatef(-angle, 1.0, 1.0, 1.0);
}

void Rot4(void)
{
    glLoadIdentity();
    glTranslatef(3.0, 3.0, -10.0);
    glRotatef(2.0*angle, 0.0, 0.0, 1.0);
}

void Rot5(void)
{
    glScalef(20.0, 20.0, 20.0);
}


static
GLboolean draw(void)
{
    static int framecount = 0;
    ULONG fracsecs;
    static  char buffer[256];
    struct Window *win = mglGetWindowHandle();


    #ifndef NODRAW
    if (GL_FALSE == mglLockDisplay())
    {
	printf("Unable to lock drawing area\n");
	return GL_FALSE;
    }

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    #endif


    if (alpha != 1.0)
    {
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    glEnable(GL_TEXTURE_2D);

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glLoadIdentity();
    //MakeRot(mouse_angle_x, mouse_angle_y);
    MakeRot(angle, angle);
    Rot5();
    glFrontFace(GL_CW);
    glColor4f(1.f, 1.f, 1.f, 1.f);
    drawCube(3,3);
    glFrontFace(GL_CCW);

    if (alpha != 1.0) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    Rot1();
    glColor4f(1.0, 1.0, 0.0, alpha);
    drawCube(1,2);

    Rot2();
    glColor4f(1.0, 0.0, 0.0, alpha);
    drawCube(1,2);

    Rot3();
    glColor4f(0.0, 0.0, 1.0, alpha);
    drawCube(1,2);

    Rot4();
    glColor4f(0.0, 1.0, 1.0, alpha);
    drawCube(1,2);

    #ifndef NODRAW
    mglUnlockDisplay();
    #endif

    mglSwitchDisplay();
    framecount++;

    if (fogon == GL_TRUE)
    {
	Move(win->RPort, 10, win->Height-5);
	sprintf(buffer, "S: %6.3f E: %6.3f", fog_start, fog_end);
	Text(win->RPort, buffer, strlen(buffer));
    }

    fracsecs  = ElapsedTime(&eval);
    fracsecs &= 0xFFFF;

    fps = 65536.0/(float)(fracsecs+1);
    
    Move(win->RPort, win->Width - 50, 14);
    sprintf(buffer, "%4.2f", fps);
    Text(win->RPort, buffer, strlen(buffer));
    
    return GL_TRUE;
//    return GL_FALSE;
}

static GLboolean idle (void)
{
  return draw ();
}

static void reshape(int width, int height, int offset, float fov)
{
    GLfloat fog_color[4] = {0.6, 0.3, 0.1, 1.0};
    glFogfv(GL_FOG_COLOR, fog_color);
    glFogf(GL_FOG_MODE, GL_LINEAR);
    glFogf(GL_FOG_START, 1.5);
    glFogf(GL_FOG_END,   fog_end);


    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(fov, 1.3333333, 1.0, (GLdouble)zback);

    glMatrixMode(GL_MODELVIEW);
    glViewport(offset,offset, (GLint)width-2*offset, (GLint)height-2*offset);
    glClearColor(0.0f, 0.f, 0.f, 1.f);
    glClearDepth(zclear);
    glEnable(GL_TEXTURE_2D);
    if (alpha == 1.0) glEnable(GL_CULL_FACE);
    else              glDisable(GL_CULL_FACE);

}

void ClampMouse(struct Window *window, int x, int y, GLboolean left, GLboolean right)
{
    if (left == GL_FALSE && right == GL_FALSE)
    {
	mouse_x = (GLfloat)x/(GLfloat)(window->Width)*8.0;
	mouse_y = (GLfloat)(window->Height - y)/(GLfloat)(window->Height)*8.0;
	if (mouse_x > 8.0) mouse_x = 8.0;
	if (mouse_y > 8.0) mouse_y = 8.0;
	if (mouse_x < 0.0) mouse_x = 0.0;
	if (mouse_y < 0.0) mouse_y = 0.0;
	mouse_x -= 4.0;
	mouse_y -= 4.0;
	mouse_x *= 2.0;
	mouse_y *= 2.0;
    }
    else
    if (left == GL_TRUE && right == GL_FALSE)
    {
	mouse_z = (GLfloat)y/(GLfloat)(window->Height)*15.0;
	if (mouse_z > 15.0) mouse_z = 15.0;
	if (mouse_z < 0.0) mouse_z = 0.0;
	mouse_z -= 5.0;
    }
    else
    if (left == GL_FALSE && right == GL_TRUE)
    {
	mouse_angle_x = (GLfloat)x/(GLfloat)(window->Width)*360.0;
	mouse_angle_y = (GLfloat)y/(GLfloat)(window->Height)*360.0;
    }
}


GLenum LockMode = MGL_LOCK_SMART;

void IdleHandler(void)
{
    angle+=1.0;
    idle();
}

void KeyHandler(char key)
{
    struct Window *window;
    static int drawfn = 0;
    static GLenum WHint = GL_DONT_CARE;

    window = (struct Window *)mglGetWindowHandle();

    switch(key)
    {
	case '1':
	    if (WHint == GL_DONT_CARE) WHint = GL_FASTEST;
	    else                       WHint = GL_DONT_CARE;
	    glHint(MGL_W_ONE_HINT, WHint);
	    break;
	case 's':
	    if (sync == GL_FALSE)   sync = GL_TRUE;
	    else                sync = GL_FALSE;
	    mglEnableSync(sync);
	    break;
	case '8':
	    fog_end++; if (fog_end > zback) fog_end = zback;
	    glFogf(GL_FOG_END, fog_end);
	    break;
	case '5':
	    fog_end--; if (fog_end < fog_start) fog_end = fog_start;
	    glFogf(GL_FOG_END, fog_end);
	    break;
	case '7':
	    fog_start++; if (fog_start > fog_end) fog_start = fog_end;
	    glFogf(GL_FOG_START, fog_start);
	    break;
	case '4':
	    fog_start--; if (fog_start < 1.5) fog_start = 1.5;
	    glFogf(GL_FOG_START, fog_start);
	    break;
	case 'f':
	    if (fogon == GL_FALSE)
	    {
		glEnable(GL_FOG);
		fogon = GL_TRUE;
	    }
	    else
	    {
		glDisable(GL_FOG);
		fogon = GL_FALSE;
	    }
	    break;
	case 'd':
	    drawfn++; if (funcs[drawfn] == NULL) drawfn = 0;
	    drawCube = funcs[drawfn];
	    break;
	case 'Q':
	case 27:
	    mglExit();
	    break;
	case '+':
	    if (zclear < 1.0) zclear += 0.01;
	    if (zclear > 1.0) zclear = 1.0;
	    glClearDepth(zclear);
	    break;
	case '-':
	    if (zclear > 0.0) zclear -= 0.01;
	    if (zclear < 0.0) zclear = 0.0;
	    glClearDepth(zclear);
	    break;
	case 'e':
	    mouse_z = 10.0;
	    break;
	case 'w':
	    offset += 10;
	    if (offset >=100) offset = 100;
	    reshape((int)window->Width,(int)window->Height, offset, fov);
	    break;
	case 'q':
	    offset -= 10;
	    if (offset <=0) offset = 0;
	    reshape((int)window->Width,(int)window->Height, offset, fov);
	    break;
	case 'y':
	    fov += 2.0;
	    if (fov>180.0) fov = 180.0;
	    reshape((int)window->Width,(int)window->Height, offset, fov);
	    break;
	case 'x':
	    fov -= 2.0;
	    if (fov<40.0) fov = 40.0;
	    reshape((int)window->Width,(int)window->Height, offset, fov);
	    break;
	case 'z':
	    if (zbuffer == GL_TRUE)
	    {
		zbuffer = GL_FALSE;
		glDisable(GL_DEPTH_TEST);
	    }
	    else
	    {
		zbuffer = GL_TRUE;
		glEnable(GL_DEPTH_TEST);
	    }
	    break;
	case 'r':
	    ReplaceTexture();
	    break;
    }
}

void MouseHandler(GLint MouseX, GLint MouseY, GLbitfield buttons)
{
}

void MainLoop(void)
{
    struct Window *window;


    window = (struct Window *)mglGetWindowHandle();

    TexInit();

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);

    reshape((int)window->Width,(int)window->Height, offset, fov);
    ElapsedTime(&eval);
    SetAPen(window->RPort, 2);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);

    mglLockMode(LockMode);
    mglKeyFunc(KeyHandler);
    mglMouseFunc(MouseHandler);
    mglIdleFunc(IdleHandler);
    mglMainLoop();
}

int main(int argc, char **argv)
{
    int i;
    int numb=3, resnr=0;

    printf("Calling MGLInit...\n");
    PrInit();
    MGLInit();

	LowLevelBase = OpenLibrary("lowlevel.library", 0);
	ILowLevel = (struct LowLevelIFace *)GetInterface(LowLevelBase, "main", 1, 0);
	
    for (i=1; i<argc; i++)
    {
	if (0 == strcmp(argv[i], "-window"))
	{
	    mglChooseWindowMode(GL_TRUE);
	}
	else if (0 == strcmp(argv[i], "-zback"))
	{
	    i++;
	    zback = (GLfloat)atof(argv[i]);
	}
	else if (0 == strcmp(argv[i], "-w"))
	{
	    i++;
	    inf_w = (GLfloat)atof(argv[i]);
	}
	else if (0 == strcmp(argv[i], "-buffers"))
	{
	    i++;
	    numb = atoi(argv[i]);
	}
	else if (0 == strcmp(argv[i], "-res"))
	{
	    i++;
	    resnr = atoi(argv[i]);
	}
	else if (0 == strcmp(argv[i], "-alpha"))
	{
	    i++;
	    alpha = atof(argv[i]);
	}
	else if (0 == strcmp(argv[i], "-lock"))
	{
	    i++;
	    if (0 == strcasecmp(argv[i], "manual"))
	    {
		LockMode = MGL_LOCK_MANUAL;
	    }
	    else if (0 == strcasecmp(argv[i], "auto"))
	    {
		LockMode = MGL_LOCK_AUTOMATIC;
	    }
	    else if (0 == strcasecmp(argv[i], "smart"))
	    {
		LockMode = MGL_LOCK_SMART;
	    }
	    else printf("Unknown lockmode. Using default\n");
	}
	else
	{
	    printf("Unknown option %s\n", argv[i]);
	    printf("Usage: %s -zback <float> -w <float> -res <int> -lock (manual|auto|smart) -buffers <int>\n", argv[0]);
	    exit(0);
	}
    }

    ResPtr = resnr;
    CurrentRes = Resolutions[ResPtr].name;

    fog_start = 1.5;
    fog_end = 100.0;

    //mglSetDebugLevel(10);
    printf("Setting number of buffers to %d...\n", numb);
    mglChooseNumberOfBuffers(numb);
    printf("Setting pixel depth to 15...\n");
    mglChoosePixelDepth(15);
    printf("Creating context...\n");
    if (mglCreateContext(0,0, Resolutions[ResPtr].width, Resolutions[ResPtr].height))
    {
	if (alpha != 1.0) glShadeModel(GL_FLAT);
	printf("Switching sync...\n");
	mglEnableSync(GL_TRUE);
	printf("Going into main loop...\n");
	MainLoop();
	printf("Done\n");
	mglDeleteContext();
    }
    else
    {
	printf("Error: Can't mglCreateContext()\n");
    }

	DropInterface((struct Interface *)ILowLevel);
	CloseLibrary(LowLevelBase);

    MGLTerm();
    PrExit();
    return 0;
}
