/*
 * $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
 *
 */

#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 <dos/dos.h>
#ifdef __GNUC__
#ifdef __PPC__
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/lowlevel.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#else
#include <inline/exec.h>
#include <inline/intuition.h>
#include <inline/lowlevel.h>
#include <inline/dos.h>
#include <inline/graphics.h>
#endif
#endif

#ifdef __STORMC__
#include <string.h>
#include <clib/powerpc_protos.h>
#ifndef __PPC__
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/lowlevel.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#else
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/lowlevel_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#endif
#define inline __inline
#define M_PI 3.1415927
int kprintf(char *format, ...)
{
	return 0;
}
#endif

#ifdef __VBCC__
#include <proto/exec.h>
include <proto/intuition.h>
#include <proto/lowlevel.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#define inline
#define   M_PI 3.14159265358979323846
#endif

static char rcsid[] = "$Id$";
struct Library *LowLevelBase;

#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);
}

static void UpRes(void)
{
	ResPtr++; if (Resolutions[ResPtr].width == -1) ResPtr = 0;
	mglResizeContext(Resolutions[ResPtr].width, Resolutions[ResPtr].height);
	CurrentRes = Resolutions[ResPtr].name;
	ShowRes = GL_TRUE;
}

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();
}

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

#ifndef __STORM__
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();

	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 == stricmp(argv[i], "manual"))
			{
				LockMode = MGL_LOCK_MANUAL;
			}
			else if (0 == stricmp(argv[i], "auto"))
			{
				LockMode = MGL_LOCK_AUTOMATIC;
			}
			else if (0 == stricmp(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");
	}

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