/* editor.c */

#include "gameinc.h"

/* Array of editor modes */
char *editor_editmodes[]={	"None",
							"Lights",
							"Location",
							"Animation",
							"Objects"
							"Entities"
						};

/* Editor mode flag, initialised by Editor_SetupEditorEnvironment(void) */
int editor_editmode;

/*******************************************************************************/
/*******************************************************************************/
/* Now the code area */
/*******************************************************************************/
/*******************************************************************************/

/* Inits the editor states and work areas */
int Editor_SetupEditorEnvironment(void)
{
	editor_editmode=EDITMODE_GAME; /* Tell the engine we are starting up as a game */
	/* Init all menu stuff */
	Editor_SetupMenuEnvironment();
	Editor_SetupAnimEnvironment();

	return BRE_OK;
}


/*******************************************************************************/
/*******************************************************************************/
/* Misc operations usefull for the editor */
/*******************************************************************************/
/*******************************************************************************/

/* Plots some debug text to the 3DFX screen */
static void Editor_PlotDebug(char *text)
{
	static int ypos=-220;
	static int first=0;
	static br_pixelmap *debugscr;

	if (first==0)
	{
		first=1;
		debugscr=BrPixelmapAllocate(back_screen->type,back_screen->width,back_screen->height,NULL,BR_PMAF_NORMAL);
		debugscr->origin_x=back_screen->origin_x;
		debugscr->origin_y=back_screen->origin_y;
	}
	

	BrPixelmapTextF(debugscr,-300,ypos,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
					text);
	BrPixelmapCopy(back_screen,debugscr);
	BrPixelmapDoubleBuffer(screen, back_screen);
	BrPixelmapCopy(back_screen,debugscr);
	BrPixelmapDoubleBuffer(screen, back_screen);

	ypos+=10;
}


/* Get a 4byte integer value from a piece of memory */
int E_GetInt4(br_uint_8 *buff)
{

	return buff[0]|(buff[1]<<8)|(buff[2]<<16)|(buff[3]<<24);
}


/* Static support routine for the material bilinear set */
static br_uint_32 BR_CALLBACK E_ToggleMaterialSwitch( br_material *pMat, void *arg )
{
	br_uint_32 Flag = (br_uint_32) arg ;

	pMat->flags |= Flag ;        
	BrMaterialUpdate( pMat, BR_MATU_ALL );

	return 0 ;
}


/* Static support routine for the material bilinear set */
static br_uint_32 BR_CALLBACK E_ToggleMaterialSwitchNot( br_material *pMat, void *arg )
{
	br_uint_32 Flag = (br_uint_32) arg ;

	pMat->flags &= ~Flag ;
	BrMaterialUpdate( pMat, BR_MATU_ALL );

	return 0 ;
}

/* When called sets all materials loaded to be binlinear filtered */
void Editor_SetAllBilinear(void)
{
	BrMaterialEnum( NULL, E_ToggleMaterialSwitch, (void*) BR_MATF_MAP_INTERPOLATION );
}


/* When called sets all materials loaded to be non-binlinear filtered */
void Editor_SetAllBilinearNot(void)
{
	BrMaterialEnum( NULL, E_ToggleMaterialSwitchNot, (void*) BR_MATF_MAP_INTERPOLATION );
}


/* Console thingys */
int e_console_ypos=480;
int e_console_flags=2;
extern br_pixelmap *con_overlay;
static char e_console_text_buffer[40][256];
static char e_console_input[256];

/* Inserts text into the console buffer for debug plotting */
void Editor_OverlayDebug(char *text)
{
	int i;

	for (i=0;i<39;i++)
	{
		strcpy(e_console_text_buffer[i],e_console_text_buffer[i+1]);
	}

	strcpy(e_console_text_buffer[39],text);

	/* If new text added and the debug screen is the only thing on screen then display it */
	/* right away. */
	if (e_console_flags==2 && back_screen!=NULL)
	{
		Editor_HandleConsole();
		BrPixelmapDoubleBuffer(screen, back_screen);
	}
}


/* Displays a nice overlayed screen on a given pixelmap screen with a given number of scanlines to plot */
/* WARNING:	This destroys what ever is in the Z buffer until the BR_MATF_FORCE_FRONT */
/*				bug is fixed!!!! */
/* TODO: Test with the BR_FIXED build of the renderers just to make sure the black poly */
/* still displays behind the texture map poly! Loss of accuracy in the BR_FIXED type may */
/* need the black poly to be moved furthur back behind the texture map poly. */
void Editor_DisplayOverlay(br_pixelmap *screen,br_pixelmap *depth,int ypos,br_pixelmap *overlay)
{
	static int firsttime = BR_TRUE;
	static br_actor *world, *camera, *copy;
	static br_material *material, *material2;
	static br_model *thismodel;
	int i,j;
	static int flashon=1;
	static int flashcount=0;

	/* First time around do this... */
	/* Setup the mini-BRender world with materials, models and cameras. */
	if (firsttime )
	{
		firsttime = BR_FALSE;

		/* Allocate material with texture information */
		material = BrMaterialAllocate("overlaymat");
		material->flags = BR_MATF_PRELIT | BR_MATF_MAP_INTERPOLATION | BR_MATF_PERSPECTIVE
					| BR_MATF_ALWAYS_VISIBLE | BR_MATF_FORCE_FRONT | BR_MATF_SMOOTH;
		material->colour_map = overlay;
		material->colour = BR_COLOUR_RGB(255,255,255);
		BrMaterialAdd(material);

		/* Allocate material with black poly information */
		material2 = BrMaterialAllocate("overlaymat2");
		material2->flags = BR_MATF_PRELIT | BR_MATF_ALWAYS_VISIBLE
								| BR_MATF_SMOOTH;
		material2->colour = BR_COLOUR_RGB(0,0,0);
		BrMaterialAdd(material2);

		/* Create a model with two faces, one the texture map and the other with a black */
		/* poly just behind it */
		thismodel = BrModelAllocate("overlaymod",8,4);
		thismodel->vertices[0].p.v[0]=BR_SCALAR(-100.0);
		thismodel->vertices[0].p.v[1]=BR_SCALAR(100.0);
		thismodel->vertices[0].p.v[2]=BR_SCALAR(0.0);
		thismodel->vertices[0].red = 255;
		thismodel->vertices[0].grn = 255;
		thismodel->vertices[0].blu = 255;
		thismodel->vertices[0].map.v[0]=BR_SCALAR(0.0);
		thismodel->vertices[0].map.v[1]=BR_SCALAR(0.0);

		
		thismodel->vertices[1].p.v[0]=BR_SCALAR(100.0);
		thismodel->vertices[1].p.v[1]=BR_SCALAR(100.0);
		thismodel->vertices[1].p.v[2]=BR_SCALAR(0.0);
		thismodel->vertices[1].red = 255;
		thismodel->vertices[1].grn = 255;
		thismodel->vertices[1].blu = 255;
		thismodel->vertices[1].map.v[0]=BR_SCALAR(1.0);
		thismodel->vertices[1].map.v[1]=BR_SCALAR(0.0);

		thismodel->vertices[2].p.v[0]=BR_SCALAR(100.0);
		thismodel->vertices[2].p.v[1]=BR_SCALAR(-100.0);
		thismodel->vertices[2].p.v[2]=BR_SCALAR(0.0);
		thismodel->vertices[2].red = 255;
		thismodel->vertices[2].grn = 255;
		thismodel->vertices[2].blu = 255;
		thismodel->vertices[2].map.v[0]=BR_SCALAR(1.0);
		thismodel->vertices[2].map.v[1]=BR_SCALAR(1.0);

		thismodel->vertices[3].p.v[0]=BR_SCALAR(-100.0);
		thismodel->vertices[3].p.v[1]=BR_SCALAR(-100.0);
		thismodel->vertices[3].p.v[2]=BR_SCALAR(0.0);
		thismodel->vertices[3].red = 255;
		thismodel->vertices[3].grn = 255;
		thismodel->vertices[3].blu = 255;
		thismodel->vertices[3].map.v[0]=BR_SCALAR(0.0);
		thismodel->vertices[3].map.v[1]=BR_SCALAR(1.0);

		thismodel->vertices[4].p.v[0]=BR_SCALAR(-160.0);
		thismodel->vertices[4].p.v[1]=BR_SCALAR(100.0);
		thismodel->vertices[4].p.v[2]=BR_SCALAR(-0.01);
		thismodel->vertices[4].red = 0;
		thismodel->vertices[4].grn = 0;
		thismodel->vertices[4].blu = 0;
		thismodel->vertices[4].map.v[0]=BR_SCALAR(0.0);
		thismodel->vertices[4].map.v[1]=BR_SCALAR(0.0);

		
		thismodel->vertices[5].p.v[0]=BR_SCALAR(160.0);
		thismodel->vertices[5].p.v[1]=BR_SCALAR(100.0);
		thismodel->vertices[5].p.v[2]=BR_SCALAR(-0.01);
		thismodel->vertices[5].red = 0;
		thismodel->vertices[5].grn = 0;
		thismodel->vertices[5].blu = 0;
		thismodel->vertices[5].map.v[0]=BR_SCALAR(1.0);
		thismodel->vertices[5].map.v[1]=BR_SCALAR(0.0);

		thismodel->vertices[6].p.v[0]=BR_SCALAR(160.0);
		thismodel->vertices[6].p.v[1]=BR_SCALAR(-100.0);
		thismodel->vertices[6].p.v[2]=BR_SCALAR(-0.01);
		thismodel->vertices[6].red = 0;
		thismodel->vertices[6].grn = 0;
		thismodel->vertices[6].blu = 0;
		thismodel->vertices[6].map.v[0]=BR_SCALAR(1.0);
		thismodel->vertices[6].map.v[1]=BR_SCALAR(1.0);

		thismodel->vertices[7].p.v[0]=BR_SCALAR(-160.0);
		thismodel->vertices[7].p.v[1]=BR_SCALAR(-100.0);
		thismodel->vertices[7].p.v[2]=BR_SCALAR(-0.01);
		thismodel->vertices[7].red = 0;
		thismodel->vertices[7].grn = 0;
		thismodel->vertices[7].blu = 0;
		thismodel->vertices[7].map.v[0]=BR_SCALAR(0.0);
		thismodel->vertices[7].map.v[1]=BR_SCALAR(1.0);

		thismodel->faces[0].vertices[0]=0;
		thismodel->faces[0].vertices[1]=1;
		thismodel->faces[0].vertices[2]=2;
		thismodel->faces[0].material=material;

		thismodel->faces[1].vertices[0]=0;
		thismodel->faces[1].vertices[1]=2;
		thismodel->faces[1].vertices[2]=3;
		thismodel->faces[1].material=material;

		thismodel->faces[2].vertices[0]=4;
		thismodel->faces[2].vertices[1]=5;
		thismodel->faces[2].vertices[2]=6;
		thismodel->faces[2].material=material2;

		thismodel->faces[3].vertices[0]=4;
		thismodel->faces[3].vertices[1]=6;
		thismodel->faces[3].vertices[2]=7;
		thismodel->faces[3].material=material2;

		thismodel->flags=BR_MODF_KEEP_ORIGINAL;

		/* Add model to registry */
		BrModelAdd(thismodel);
		BrModelUpdate(thismodel,BR_MODU_ALL);

		/* Allocate a mini hierarchy of actors and their models */
		world = BrActorAllocate(BR_ACTOR_NONE,NULL);

		copy = BrActorAdd(world,BrActorAllocate(BR_ACTOR_MODEL,NULL));

		copy->model = thismodel;

		/* Allocate a camera that looks at the mini model */
		camera = BrActorAllocate(BR_ACTOR_CAMERA, NULL);
		camera->identifier = "cameraoverlay";
		((br_camera *) camera->type_data)->type = BR_CAMERA_PERSPECTIVE;
		((br_camera *) camera->type_data)->field_of_view = BR_ANGLE_DEG(55.0);
		((br_camera *) camera->type_data)->hither_z = BR_SCALAR(2.0);
		((br_camera *) camera->type_data)->yon_z = BR_SCALAR(20000.0);
		((br_camera *) camera->type_data)->aspect = BR_SCALAR(1.6);
		camera->t.type = BR_TRANSFORM_MATRIX34;
		BrActorAdd(world, camera);

	}

	if (ypos > 0)
	{
		/* Move camera depending on how many pixels of the screen should be displayed */
		BrMatrix34Translate(&camera->t.t.mat, BR_SCALAR(0.0), BR_SCALAR(-200.0*(((float)(480-ypos))/480.0)), BR_SCALAR(190.0));

		/* Fill depth buffer and render */
		BrPixelmapFill(depth, 0xffffffff);
		BrZbSceneRender(world, camera, screen, depth);

		/* Over plot some debugging text */
		j=-480+ypos-(12*2);
		for (i=0;i<40;i++)
		{
			BrPixelmapTextF(screen,-300,j-240,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
				e_console_text_buffer[i]);
			j+=12;
		}

		i=BrPixelmapTextWidth(screen,BrFontProp7x9,e_console_input);
		BrPixelmapTextF(screen,-300,j-240,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
			e_console_input);

		if (flashon)
		{
			BrPixelmapRectangleFill(screen,-300+i,j-240,8,9,8+8*32+8*32*32);
		}

		flashcount++;
		if (flashcount>=4)
		{
			flashcount=0;
			flashon = !flashon;
		}
	}
}


void Editor_HandleConsole(void)
{
	if (DOSKeyTest(SC_PG_DOWN, 0, REPT_FIRST_DOWN) && e_console_flags != 2)
	{
		if (e_console_flags == 0)
		{
			e_console_flags=1;
		}
		else
		{
			e_console_flags=0;
		}
	}

	if (e_console_flags == 2)
	{
		e_console_ypos=480;
	}

	if (e_console_flags == 1)
	{
		if (e_console_ypos > 240)
			e_console_ypos-=20;

		if (e_console_ypos < 240)
			e_console_ypos+=20;
	}

	if (e_console_flags == 0)
	{
		if (e_console_ypos > 0)
			e_console_ypos-=20;
	}

	Editor_DisplayOverlay(back_screen,depth_buffer,e_console_ypos,con_overlay);
}


/*******************************************************************************/
/*******************************************************************************/
/* CFM model file loading routines */
/*******************************************************************************/
/*******************************************************************************/

/* Extract verticies from a .CFM file */
/* at this point the br_model is allocated, the file pointer is passed and the offsets and size
passed from Editor_ImportCFM() */
void E_ExtractVerticies(br_model *thismodel,FILE *fp,int offset,int size)
{
	br_uint_8 buff[12];		/* A work buffer */
	int i;					/* A counter variable */
	int x,y;				/* Some ordinates */

	fseek(fp,offset,SEEK_SET);	/* Seek to the relevent file position for the vertex data */
	for (i=0;i<size;i++)		/* Count through the number of verticies */
	{
		fread(buff,1,12,fp);	/* Read in three lots of 4byte int values */
		/* Each ordinate is a 4byte integer in X,Z,Y order. These are scaled down by 65536 to fit the
			BRender model space */
		thismodel->vertices[i].p.v[0]=BR_SCALAR(((float)E_GetInt4(buff))/8.0);
		thismodel->vertices[i].p.v[1]=BR_SCALAR(((float)E_GetInt4(buff+4))/8.0);
		thismodel->vertices[i].p.v[2]=BR_SCALAR(((float)E_GetInt4(buff+8))/8.0);

		/* Plot the models 2D points to the screen to see it being loaded */
		x=E_GetInt4(buff)/4;
		y=E_GetInt4(buff+8)/4;
		BrPixelmapPixelSet(back_screen, x, y, 0xffffff);
		
	}

	BrPixelmapDoubleBuffer(screen, back_screen);
}


/* Extract a single triangle from offsets supplied by E_ExtractFaces() */
/* maxv is the total number of verticies that are available for this model */
void E_Maketriangle(int offset,br_face *thisbrface,int fileoffset,FILE *fp,int maxv)
{
	br_uint_8 buff[256];	/* Some workspace */
	int v1,v2,v3;

	fseek(fp,fileoffset+(offset*4),SEEK_SET);	/* Seek to relevent file position */
	fread(buff,1,256,fp);						/* Read in a chunk of data */

	v1=E_GetInt4(buff);	/* Get vertex index */
	v2=E_GetInt4(buff+4);
	v3=E_GetInt4(buff+8);
	thisbrface->vertices[0]=v1;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v2;
	thisbrface->vertices[2]=v3;
	thisbrface->smoothing=1;

	thisbrface++;
	thisbrface->vertices[0]=v3;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v2;
	thisbrface->vertices[2]=v1;
	thisbrface->smoothing=1;

	/* Check for errors incase of incorrect file parsing etc */
	/* Checks for vertex index number going negative or greater or equal to the total number or verticies */
	if (thisbrface->vertices[0]>=maxv || thisbrface->vertices[1]>=maxv || thisbrface->vertices[2]>=maxv
		|| thisbrface->vertices[0]<0 || thisbrface->vertices[1]<0 || thisbrface->vertices[2]<0)
	{
		printf("Nasty horrible error!\n");
		return;
	}
}

void E_Makequad(int offset,br_face *thisbrface,int fileoffset,FILE *fp,int maxv)
{
	br_uint_8 buff[256];	/* Some workspace */
	int v1,v2,v3,v4;

	fseek(fp,fileoffset+(offset*4),SEEK_SET);	/* Seek to relevent file position */
	fread(buff,1,256,fp);						/* Read in a chunk of data */

	v1=E_GetInt4(buff);	/* Get vertex index */
	v2=E_GetInt4(buff+4);
	v3=E_GetInt4(buff+8);
	v4=E_GetInt4(buff+12);
	thisbrface->vertices[0]=v1;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v2;
	thisbrface->vertices[2]=v3;
	thisbrface->smoothing=1;

	thisbrface++;
	thisbrface->vertices[0]=v1;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v3;
	thisbrface->vertices[2]=v4;
	thisbrface->smoothing=1;

	thisbrface++;
	thisbrface->vertices[0]=v3;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v2;
	thisbrface->vertices[2]=v1;
	thisbrface->smoothing=1;

	thisbrface++;
	thisbrface->vertices[0]=v4;	/* Get vertex index and put them into the face structure */
	thisbrface->vertices[1]=v3;
	thisbrface->vertices[2]=v1;
	thisbrface->smoothing=1;

	/* Check for errors incase of incorrect file parsing etc */
	/* Checks for vertex index number going negative or greater or equal to the total number or verticies */
	if (thisbrface->vertices[0]>=maxv || thisbrface->vertices[1]>=maxv || thisbrface->vertices[2]>=maxv
		|| thisbrface->vertices[0]<0 || thisbrface->vertices[1]<0 || thisbrface->vertices[2]<0)
	{
		printf("Nasty horrible error!\n");
		return;
	}
}


/* Extract a group of faces from a given .CFM file into a br_model */
void E_ExtractFaces(br_model *thismodel,FILE *fp,int *blockoffset,int headerpos,int *blocksize)
{
	int i,numbrfaces=0;		/* counter variable, total number of faces parsed=0 */
	br_uint_8 *buff,*thisface;	/* workspace pointer, current CFM face group pointer */
	br_face *thisbrface;		/* current br_face pointer */
	int mod_tris=0,mod_quads=0;
	char textbuff[256];
	
	thisface=NULL;				/* Stops compiler complaining */
	thisbrface=thismodel->faces; /* Initialise br_face pointer */
	buff=malloc(blocksize[1]*12);	/* allocate some space, no error checking */
	fseek(fp,blockoffset[1]+headerpos,SEEK_SET);	/* Seeh the .CFM face group file position */
	fread(buff,1,blocksize[1]*12,fp);	/* read in all .CFM face group data */

	for (i=0;i<blocksize[1];i++)		/* parse all .CFM face group structures */
	{
		thisface=buff+i*12;				/* initialise pointer to .CFM face structure */
		switch(thisface[0])				/* Parse different .CFM face groups */
		{
			case 0x83 :					/* Type 0x83 is a triangle */
				/* Extract triangle */
				E_Maketriangle(E_GetInt4(thisface+4),thisbrface,blockoffset[9]+headerpos,fp,blocksize[8]);
				/* increment pointers and value */
				thisbrface+=2;
				numbrfaces+=2;
				mod_tris++;
				break;
			case 0x84 :					/* Type 0x84 is a quad */
				/* Extract triangle */
				E_Makequad(E_GetInt4(thisface+4),thisbrface,blockoffset[9]+headerpos,fp,blocksize[8]);
				/* increment pointers and value */
				thisbrface+=4;
				numbrfaces+=4;
				mod_quads++;
				break;
			case 0x8c :					/* Type 0x8c is a quad */
				/* Extract triangle */
				E_Makequad(E_GetInt4(thisface+4),thisbrface,blockoffset[9]+headerpos,fp,blocksize[8]);
				/* increment pointers and value */
				thisbrface+=4;
				numbrfaces+=4;
				mod_quads++;
				break;
			default :					/* Unrecognised byte code */
				break;
		}
	}

	sprintf(textbuff,"Tris = %d   Quads = %d\n",mod_tris,mod_quads);
	Editor_PlotDebug(textbuff);

	/* save out the total number of  br_faces created */
	thismodel->nfaces=numbrfaces;
	/* free workspace, no error checking */
	free(buff);
}


/* Imports a .CFM model given a filename and returns a br_model or NULL if an error occures */
br_model *Editor_ImportCFM(char *filename )
{
	br_uint_8 buffer[256],text[256];	/* Workspaces */
	FILE *fp;							/* File pointer */
	int i,currpos=-1,headerpos;			/* Counters and headerpos for the current .CFM model */
	int blockoffset[12],blocksize[12];	/* Table of calculated offsets for the current .CFM model */
	br_model *thismodel;				/* Pointer to br_model */

	/* Plot some debug messages */
	Editor_PlotDebug("Loading model...");
	Editor_PlotDebug(filename);

	/* Open the file */
	fp=fopen(filename,"rb");
	/* Check for errors */
	if (fp==NULL)
	{
		Editor_PlotDebug("Model load failed!");
		return NULL;	/* Return NULL for an error */
	}

	/* More debug printing */
	Editor_PlotDebug("Searching for 'ORIP' header");

	/* Read in a chunk of data for the header find test */
	fread(buffer,1,256,fp);
	/* Search through the start of the file untill a header is found */
	for (i=0;i<249;i++)
	{
		/* "ORIP" is the model header */
		if (strncmp(buffer+i,"ORIP",4)==0)
		{
			/* Print debug message */	
			sprintf(text,"Found header at $%x",i);
			Editor_PlotDebug(text);
			/* Set current position of this .CFM model header */
			currpos=i;
		}
	}

	/* Was a header found?... */
	if (currpos==-1)
	{
		/* Plot debug */
		Editor_PlotDebug("Didn't find the model header, giving up.");
		/* Return NULL when no model is found in the flle */
		return NULL;
	}

	/* now set the real header position */
	headerpos=currpos;
	/* Seek to the header */
	fseek(fp,headerpos,SEEK_SET);
	/* Read in header */
	fread(buffer,1,256,fp);

	/* Calculate the block offsets for this model inside the .CFM file */
	blockoffset[1]=	E_GetInt4(buffer+0x28);
	blocksize[1]=	E_GetInt4(buffer+0x24);
	blockoffset[2]=	E_GetInt4(buffer+0x20);
	blocksize[2]=	E_GetInt4(buffer+0x1c);
	blockoffset[3]=	E_GetInt4(buffer+0x3c);
	blocksize[3]=	E_GetInt4(buffer+0x38);
	blockoffset[4]=	E_GetInt4(buffer+0x44);
	blocksize[4]=	E_GetInt4(buffer+0x40);
	blockoffset[5]=	E_GetInt4(buffer+0x4c);
	blocksize[5]=	E_GetInt4(buffer+0x48);
	blockoffset[6]=	E_GetInt4(buffer+0x58);
	blocksize[6]=	E_GetInt4(buffer+0x54);
	blockoffset[7]=	E_GetInt4(buffer+0x60);
	blocksize[7]=	E_GetInt4(buffer+0x5c);
	blockoffset[8]=	E_GetInt4(buffer+0x18);
	blocksize[8]=	E_GetInt4(buffer+0x10);
	blockoffset[9]=	E_GetInt4(buffer+0x50);
	blocksize[9]=	0;

	/* Print up the header values for debug purposes */
	for (i=1;i<=9;i++)
	{
		sprintf(text,"header[%d] at $%x  (size $%x)",i,blockoffset[i],blocksize[i]);
		Editor_PlotDebug(text);
	}

	/* Allocate a br_model with enough verticies and faces */
	thismodel=BrModelAllocate("testmodel",blocksize[8],blocksize[1]*8);

	/* Extract verticies */
	E_ExtractVerticies(thismodel,fp,blockoffset[8]+headerpos,blocksize[8]);
	/* Extract faces */
	E_ExtractFaces(thismodel,fp,blockoffset,headerpos,blocksize);

	/* Apply a mapping system to the br_model ( NONE for now ) */
	BrModelApplyMap(thismodel,BR_APPLYMAP_NONE,NULL);
	/* Add the model to the registry */
	thismodel->nvertices=blocksize[8];
	thismodel->flags=BR_MODF_KEEP_ORIGINAL;
	BrModelAdd(thismodel);
	BrModelUpdate(thismodel,BR_MODU_ALL);

	/* Return the model pointer and exit */
	return thismodel;
}


/*******************************************************************************/
/*******************************************************************************/
/* Editor routines for handling the mouse pointer */
/*******************************************************************************/
/*******************************************************************************/

/* Draws a coloured mouse at the pixelmap x and y position */
void Editor_DrawMouse(br_pixelmap *Screen,int color,int x,int y)
{

	BrPixelmapPixelSet(Screen, x+0, y+0, 0);
	BrPixelmapPixelSet(Screen, x+1, y+0, 0);

	BrPixelmapPixelSet(Screen, x+0, y+1, 0);
	BrPixelmapPixelSet(Screen, x+1, y+1, color);
	BrPixelmapPixelSet(Screen, x+2, y+1, 0);

	BrPixelmapPixelSet(Screen, x+0, y+2, 0);
	BrPixelmapPixelSet(Screen, x+1, y+2, color);
	BrPixelmapPixelSet(Screen, x+2, y+2, color);
	BrPixelmapPixelSet(Screen, x+3, y+2, 0);

	BrPixelmapPixelSet(Screen, x+0, y+3, 0);
	BrPixelmapPixelSet(Screen, x+1, y+3, color);
	BrPixelmapPixelSet(Screen, x+2, y+3, color);
	BrPixelmapPixelSet(Screen, x+3, y+3, color);
	BrPixelmapPixelSet(Screen, x+4, y+3, 0);

	BrPixelmapPixelSet(Screen, x+0, y+4, 0);
	BrPixelmapPixelSet(Screen, x+1, y+4, color);
	BrPixelmapPixelSet(Screen, x+2, y+4, color);
	BrPixelmapPixelSet(Screen, x+3, y+4, color);
	BrPixelmapPixelSet(Screen, x+4, y+4, color);
	BrPixelmapPixelSet(Screen, x+5, y+4, 0);

	BrPixelmapPixelSet(Screen, x+0, y+5, 0);
	BrPixelmapPixelSet(Screen, x+1, y+5, color);
	BrPixelmapPixelSet(Screen, x+2, y+5, color);
	BrPixelmapPixelSet(Screen, x+3, y+5, color);
	BrPixelmapPixelSet(Screen, x+4, y+5, color);
	BrPixelmapPixelSet(Screen, x+5, y+5, color);
	BrPixelmapPixelSet(Screen, x+6, y+5, 0);

	BrPixelmapPixelSet(Screen, x+0, y+6, 0);
	BrPixelmapPixelSet(Screen, x+1, y+6, color);
	BrPixelmapPixelSet(Screen, x+2, y+6, color);
	BrPixelmapPixelSet(Screen, x+3, y+6, color);
	BrPixelmapPixelSet(Screen, x+4, y+6, color);
	BrPixelmapPixelSet(Screen, x+5, y+6, color);
	BrPixelmapPixelSet(Screen, x+6, y+6, color);
	BrPixelmapPixelSet(Screen, x+7, y+6, 0);

	BrPixelmapPixelSet(Screen, x+0, y+7, 0);
	BrPixelmapPixelSet(Screen, x+1, y+7, color);
	BrPixelmapPixelSet(Screen, x+2, y+7, color);
	BrPixelmapPixelSet(Screen, x+3, y+7, 0);
	BrPixelmapPixelSet(Screen, x+4, y+7, color);
	BrPixelmapPixelSet(Screen, x+5, y+7, color);
	BrPixelmapPixelSet(Screen, x+6, y+7, 0);
	BrPixelmapPixelSet(Screen, x+7, y+7, 0);
	BrPixelmapPixelSet(Screen, x+8, y+7, 0);

	BrPixelmapPixelSet(Screen, x+0, y+8, 0);
	BrPixelmapPixelSet(Screen, x+1, y+8, 0);
	BrPixelmapPixelSet(Screen, x+2, y+8, 0);
	BrPixelmapPixelSet(Screen, x+3, y+8, 0);
	BrPixelmapPixelSet(Screen, x+4, y+8, 0);
	BrPixelmapPixelSet(Screen, x+5, y+8, color);
	BrPixelmapPixelSet(Screen, x+6, y+8, color);
	BrPixelmapPixelSet(Screen, x+7, y+8, 0);

	BrPixelmapPixelSet(Screen, x+5, y+9, 0);
	BrPixelmapPixelSet(Screen, x+6, y+9, 0);
	BrPixelmapPixelSet(Screen, x+7, y+9, 0);
}


/*******************************************************************************/
/*******************************************************************************/
/* Editor routines for displaying menus and acting upon menu selcetions etc */
/*******************************************************************************/
/*******************************************************************************/

/* Some variables for the menu mouse handling routines. Statically defined. */
static int e_menu_firstdownl,e_menu_downl,e_menu_firstdownr,e_menu_downr;
static int e_menu_identifier_selected=E_MENU_ERROR;
static int e_menu_identifier_highlighted=E_MENU_ERROR;
static int e_menu_item_selected;
static int e_menu_item_highlighted;
static int e_menu_over_menu;
static int e_menu_clicked_x,e_menu_clicked_y,e_menu_clickdrag=E_MENU_ERROR;

/* Some global vars for the menu stuff */
p_E_Menu			e_menu_allocated_list[E_MENU_MAX_MENUS]; /* Pointers to allocated menus */
struct s_E_Menu_pos	e_menu_open_list[E_MENU_MAX_OPEN_MENUS]; /* list of open menus */

static int basemenuid;

/* This inits the menu stuff, called from int Editor_SetupEditorEnvironment usually*/
void Editor_SetupMenuEnvironment(void)
{
	int i;

	/* Clear all allocated menu pointers */
	for (i=0;i<E_MENU_MAX_MENUS;i++)
	{
		e_menu_allocated_list[i]=NULL;
	}

	/* Clear all menu positions to E_MENU_ERROR meaning no menus are plotted */
	for (i=0;i<E_MENU_MAX_OPEN_MENUS;i++)
	{
		e_menu_open_list[i].identifier=E_MENU_ERROR;
	}

}


/* Sets the base menu id for a right click */
void Editor_SetMenuBaseId(int menuid)
{
	basemenuid=menuid;
}


/* Creates a menu structure and passes back a menu number or E_MENU_ERROR */
/* if not successfull */
int Editor_CreateMenu(void)
{
	p_E_Menu	thismenu;
	int i,identifier=E_MENU_ERROR;

	/* Find a free position in the allocated list */
	for (i=0;i<E_MENU_MAX_MENUS;i++)
	{
		if (e_menu_allocated_list[i]==NULL)
		{
			identifier=i;
			break;	/* Step out of loop! */
		}
	}

	/* Simple error trap */
	if (identifier==E_MENU_ERROR)
	{
		return E_MENU_ERROR;
	}

	/* Allocate some space for the menu */
	if ( (thismenu=calloc(1,sizeof(struct s_E_Menu)))==NULL)
	{
		return E_MENU_ERROR; /* Error trap */
	}

	/* Set some default values for the menu structure */	
	thismenu->submenu_opened_identifier=E_MENU_ERROR;
	for (i=0;i<E_MENU_MAX_ENTRIES;i++)
	{
		thismenu->submenu_identifier[i]=E_MENU_ERROR;
	}

	e_menu_allocated_list[identifier]=thismenu;

	return identifier;
}


/* Close a menu given an open menu identifier */
void Editor_CloseMenu(int menuid)
{
	if (menuid>= 0 && menuid<E_MENU_MAX_OPEN_MENUS)
	{
		e_menu_open_list[menuid].identifier=E_MENU_ERROR;
	}
}


/* Close all menus that are open */
void Editor_CloseAllMenus(void)
{
	int i;

	e_menu_identifier_selected=E_MENU_ERROR;
	e_menu_identifier_highlighted=E_MENU_ERROR;
	e_menu_over_menu=E_MENU_ERROR;
	e_menu_item_selected=0;
	e_menu_item_highlighted=0;

	for (i=0;i<E_MENU_MAX_OPEN_MENUS;i++)
	{
		if ( e_menu_open_list[i].identifier != E_MENU_ERROR )
		{
			Editor_CloseMenu(i);
		}
	}
}


/* Opens a menu on screen given a menuid, xpos and ypos and kills all previous menu flags etc */
int Editor_OpenMenu(int menuid,int xpos,int ypos)
{
	p_E_Menu thismenu;
	int i,identifier=E_MENU_ERROR;

	/* Simple error trap */	
	if (menuid==E_MENU_ERROR)
	{
		return E_MENU_ERROR;
	}

	/* Find a free position in the open menu list */
	for (i=0;i<E_MENU_MAX_OPEN_MENUS;i++)
	{
		if (e_menu_open_list[i].identifier==E_MENU_ERROR)
		{
			identifier=i;
			break;	/* Step out of loop! */
		}
	}

	/* Simple error trap */	
	if (identifier==E_MENU_ERROR)
	{
		return E_MENU_ERROR;
	}

	/* Get pointer and flag all submenus as closed and remove highlights */
	thismenu=e_menu_allocated_list[menuid];
	for (i=0;i<E_MENU_MAX_ENTRIES;i++)
	{
		thismenu->entries_flags[i] = thismenu->entries_flags[i] & (~(E_MENU_I_SUBMENU_OPEN | E_MENU_I_HIGHLIGHTED));
	}
	thismenu->submenu_opened_identifier=E_MENU_ERROR;

	e_menu_open_list[identifier].identifier=menuid;
	e_menu_open_list[identifier].x=xpos;
	e_menu_open_list[identifier].y=ypos;

	return identifier;
}


/* TODO: Add full error checking of menuids and allocated NULL checks to this and the */
/* functions below */
/* Attaches a callback function to a given menu */
void Editor_MenuAttachCallBack(int menuid,menu_CALLBACKFN *menu_callback)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	thismenu->menu_callback = menu_callback;
}


/* Attaches a title to an allocated menu */
void Editor_MenuSetTitle(int menuid,char *text)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	/* Attach title */
	thismenu->title=text;
}


/* Attaches entries to an allocated menu */
void Editor_MenuAttachEntry(int menuid,int entryid,char *text, int flags)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	/* Attach entry */
	thismenu->entries_textarea[entryid]=text;
	thismenu->entries_flags[entryid]=flags;
}


/* Attaches many entries to an allocated menu */
void Editor_MenuAttachEntryMany(int menuid,int entryid,int num,char **text, int *flags)
{
	p_E_Menu thismenu;
	int i;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	/* Attach entries */
	for (i=0;i<num;i++)
	{
		thismenu->entries_textarea[entryid+i]=text[i];
		thismenu->entries_flags[entryid+i]=flags[i];
	}
}


/* Attaches a submenu to a given menuid and entryid, will not set submenu flags in the */
/* parent menu */
void Editor_MenuAttachSubMenu(int menuid,int entryid,int submenuid)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	/* Attach submenu */
	thismenu->submenu_identifier[entryid]=submenuid;
}


/* Send a message to either the supplied ALLOCATED menuid */
void Editor_SendMenuMessage(int menuid,int entryid,int message)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	/* Update the ticked bit if needed */
	if (thismenu->entries_flags[entryid] & E_MENU_I_TICKABLE && message == E_MENU_M_SELECTED )
	{
		if (thismenu->entries_flags[entryid] & E_MENU_I_TICKED)
		{
			thismenu->entries_flags[entryid] &= ~(E_MENU_I_TICKED);
		}
		else
		{
			thismenu->entries_flags[entryid] |= E_MENU_I_TICKED;
		}
	}

	if (thismenu->menu_callback != NULL)
	{
		(*thismenu->menu_callback)(menuid,entryid,message);
	}
}


/* Sets the flags state from the supplied ALLOCATED menuid */
void Editor_MenuSetFlags(int menuid,int entryid,int flags)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	thismenu->entries_flags[entryid] = flags;
}


/* Gets the flags state from the supplied ALLOCATED menuid */
int Editor_MenuGetFlags(int menuid,int entryid)
{
	p_E_Menu thismenu;

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	return thismenu->entries_flags[entryid];
}


/* Draw a random algorithmic colour to a boxed area */
/* Mostly used by E_DrawSingleMenu() */
/* colour1 is the base colour, colour2 is the grain of the texture */
void E_DrawRandomColourBox(br_pixelmap *screen,int x,int y, int w,int h,int colour1,int colour2)
{
	int i,j;

	/* Use a seeded random number generator for the algorithm */
	srand(12345);
	for (i=0;i<w;i++)
	{
		for (j=0;j<h;j++)
		{
			/* Plot this pixel if true */
			if ((rand() & 7) == 7)
			{
				BrPixelmapPixelSet(screen,x+i,y+j,colour2);
			}
			else
			{
				BrPixelmapPixelSet(screen,x+i,y+j,colour1);
			}
		}
	}
}


/* Draw one menu from its identifier and an x and y pos */
/* Mostly used by Editor_DrawMenus to draw its menus */
void E_DrawSingleMenu(br_pixelmap *screen,int menuid,int x,int y)
{
	int menu_max_text_width=32,i,temp,menu_width,menu_height;
	int text_ypos,textxoft,submenu=0,tickable=0;
	p_E_Menu thismenu;
	int item_colour;

	/* Small check */
	if (menuid==E_MENU_ERROR)
	{
		return;
	}

	/* Get pointer */
	thismenu=e_menu_allocated_list[menuid];

	menu_height=16;

	/* find maximum text width for the menu */
	if (thismenu->title != NULL)
	{
		temp=BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->title);
		if (menu_max_text_width<temp)
		{
			menu_max_text_width=temp;
		}
	}

	for (i=0;i<E_MENU_MAX_ENTRIES;i++)
	{
		if (thismenu->entries_textarea[i] != NULL)
		{
			menu_height+=11;
			temp=0;
			if (thismenu->entries_textarea[i] != NULL)
			{
				temp=BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->entries_textarea[i]);
			}
			if (thismenu->entries_flags[i] & E_MENU_I_SUBMENU )
			{
//				temp+=12;
				submenu=12;
			}

			if (thismenu->entries_flags[i] & E_MENU_I_TICKABLE )
			{
//				temp+=12;
				tickable=12;
			}

			if (menu_max_text_width<temp)
			{
				menu_max_text_width=temp;
			}
		}
	}

	menu_max_text_width+=submenu+tickable;

	/* Draw the menu background */
	menu_width=menu_max_text_width+8;

	E_DrawRandomColourBox(screen,x,y,menu_width,13,20+(20<<5)+(20<<10),23+(23<<5)+(23<<10));
	BrPixelmapLine(screen,x,y+13,x+menu_width,y+13,0);
	E_DrawRandomColourBox(screen,x,y+14,menu_width,menu_height-14,65535,27+(27<<5)+(27<<10));
	BrPixelmapRectangle(screen,x-1,y-1,menu_width+2,menu_height+2,5+(5<<5)+(5<<10));
	BrPixelmapRectangle(screen,x-2,y-2,menu_width+4,menu_height+4,5+(5<<5)+(5<<10));


	/* Plot all the text areas */
	text_ypos=y+2;
	if (thismenu->title != NULL)
	{
		BrPixelmapTextF(screen,x+4,text_ypos,BR_COLOUR_RGB(0,0,0),BrFontProp7x9,
				thismenu->title);
	}
	text_ypos=y+14;
	for (i=0;i<E_MENU_MAX_ENTRIES;i++)
	{
		if (thismenu->entries_textarea[i] != NULL)
		{
			textxoft=0;
			item_colour=0;
			/* Handle various menu item style by adjusting colour and text offset within the menu */
			/* Handle GHOSTED style */
			if (thismenu->entries_flags[i] & E_MENU_I_GHOSTED)
			{
				item_colour=9+(9<<5)+(9<<10);
				E_DrawRandomColourBox(screen,x,text_ypos,menu_width,11,14+(14<<5)+(14<<10),17+(17<<5)+(17<<10));
			}
			/* Handle highlighted menu items */
			if (thismenu->entries_flags[i] & (E_MENU_I_HIGHLIGHTED | E_MENU_I_SUBMENU_OPEN ))
			{
				item_colour=31+(31<<5)+(31<<10);
				BrPixelmapRectangleFill(screen,x,text_ypos,menu_width,11,0);
			}
			/* Do a check for a non-NULL text pointer */
			if (thismenu->entries_textarea[i] != NULL)
			{
				textxoft=x+4;
				if (thismenu->entries_flags[i] & E_MENU_I_ALIGN_RIGHT)
				{
					textxoft=x+4+menu_max_text_width-submenu-BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->entries_textarea[i]);
				}
				if (thismenu->entries_flags[i] & E_MENU_I_ALIGN_CENTER)
				{
					textxoft=x+4+((menu_max_text_width-submenu)/2)-(BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->entries_textarea[i])/2);
				}
				BrPixelmapTextF(screen,textxoft,text_ypos+1,item_colour,BrFontProp7x9,
						thismenu->entries_textarea[i]);
			}

			/* Sub menu arrow */
			if (thismenu->entries_flags[i] & E_MENU_I_SUBMENU )
			{
				textxoft=x+4+menu_max_text_width-8;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+2,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+3,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+7,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+8,item_colour);
				textxoft++;

				BrPixelmapPixelSet(screen,textxoft,text_ypos+3,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+7,item_colour);
				textxoft++;

				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);

				textxoft++;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
			}
			/* Sub menu arrow */
			if (thismenu->entries_flags[i] & E_MENU_I_TICKED )
			{
				textxoft=x+4+menu_max_text_width-8-submenu;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				textxoft++;

				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);
				textxoft++;

				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+7,item_colour);

				textxoft++;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+6,item_colour);

				textxoft++;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+5,item_colour);

				textxoft++;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+3,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+4,item_colour);

				textxoft++;
				BrPixelmapPixelSet(screen,textxoft,text_ypos+2,item_colour);
				BrPixelmapPixelSet(screen,textxoft,text_ypos+3,item_colour);
			}
			text_ypos+=11;
		}
	}

}


/* Plot all active menus */
void Editor_DrawMenus(br_pixelmap *screen)
{
	int i,menuid;

	for (i=0;i<E_MENU_MAX_OPEN_MENUS;i++)
	{
		menuid=e_menu_open_list[i].identifier;
		if (menuid!=E_MENU_ERROR)
		{
			E_DrawSingleMenu(screen,menuid,e_menu_open_list[i].x,e_menu_open_list[i].y);
		}
	}
}


/* Calculates if a menu has any highlights items */
void E_CalculateMouseMenuHighlight(int menuid,int mouse_x,int mouse_y)
{
	int menu_max_text_width=32,i,temp,menu_height;
	int submenu=0,tickable=0;
	p_E_Menu thismenu;
	int x,y,addon,addon2;

	/* Small check */
	if (menuid==E_MENU_ERROR)
	{
		return;
	}

	x=e_menu_open_list[menuid].x;
	y=e_menu_open_list[menuid].y;

	/* Get pointer */
	thismenu=e_menu_allocated_list[e_menu_open_list[menuid].identifier];

	menu_height=16;

	/* find maximum text width for the menu */
	/* FIXME: Cache this in the open menu bit. */
	if (thismenu->title != NULL)
	{
		temp=BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->title);
		if (menu_max_text_width<temp)
		{
			menu_max_text_width=temp;
		}
	}

	/* Calculate menus width and height */
	/* FIXME: Cache this in the open menu bit. */
	for (i=0;i<E_MENU_MAX_ENTRIES;i++)
	{
		if (thismenu->entries_textarea[i] != NULL)
		{
			menu_height+=11;
			temp=0;
			if (thismenu->entries_textarea[i] != NULL)
			{
				temp=BrPixelmapTextWidth(screen,BrFontProp7x9,thismenu->entries_textarea[i]);
			}
			if (thismenu->entries_flags[i] & E_MENU_I_SUBMENU )
			{
				submenu=12;
			}

			if (thismenu->entries_flags[i] & E_MENU_I_TICKABLE )
			{
				tickable=12;
			}

			/* Clear all highlighted flags */
			thismenu->entries_flags[i] = thismenu->entries_flags[i] & (~E_MENU_I_HIGHLIGHTED);
			if (menu_max_text_width<temp)
			{
				menu_max_text_width=temp;
			}
		}
	}

	menu_max_text_width+=8+submenu+tickable;

	/* FIXME: When opening more than one level of submenus things might go wrong with menus being */
	/* left open. To fix this menus need to know a little more information about the menu->submenu */
	/* lists. */

	/* Check to see if we are over the menu title bar */
	if (mouse_x>=x && mouse_x<(x+menu_max_text_width) && mouse_y>=y && mouse_y<(y+14))
	{
		/* Hey we have started a click with select! */
		if (e_menu_firstdownl==1)
		{
			e_menu_clicked_x=e_menu_open_list[menuid].x-mouse_x;
			e_menu_clicked_y=e_menu_open_list[menuid].y-mouse_y;
			e_menu_clickdrag=menuid;
			/* Close all sub menus from this menu because select was used */
			if (thismenu->submenu_opened_identifier != E_MENU_ERROR)
			{
				for (i=0;i<E_MENU_MAX_ENTRIES;i++)
				{
					if (thismenu->entries_textarea[i] != NULL)
					{
						thismenu->entries_flags[i] = thismenu->entries_flags[i] & (~E_MENU_I_SUBMENU_OPEN);
					}
				}

				Editor_CloseMenu(thismenu->submenu_opened_identifier);
				thismenu->submenu_opened_identifier=E_MENU_ERROR;
			}
		}

		/* Hey we have started a click with adjust! */
		if (e_menu_firstdownr==1)
		{
			e_menu_clicked_x=e_menu_open_list[menuid].x-mouse_x;
			e_menu_clicked_y=e_menu_open_list[menuid].y-mouse_y;
			e_menu_clickdrag=menuid;
		}
	}

	/* Now update the menus x,y coords to match any movement at all */
	x=e_menu_open_list[menuid].x;
	y=e_menu_open_list[menuid].y;

	/* Anywhere on the menu? */
	if (mouse_x>=x-2 && mouse_x<(x+menu_max_text_width+2) && mouse_y>=y-2 && mouse_y<(y+menu_height+2) )
	{
		e_menu_over_menu=menuid;
	}

	/* Check to see if we are in the menu box and we are not doing a click drag operation */
	if (mouse_x>=x && mouse_x<(x+menu_max_text_width) && mouse_y>=y+14 && mouse_y<(y+menu_height) && e_menu_clickdrag == E_MENU_ERROR )
	{
		/* Yes we are inside the menu and no clickdrags are going on */
		mouse_y=(mouse_y-y-14)/11;
		addon=0;
		addon2=mouse_y;
		for (i=0;i<E_MENU_MAX_ENTRIES;i++)
		{
			if (thismenu->entries_textarea[i] != NULL)
			{
				addon2--;
			}

			if (addon2==-1)
			{
				mouse_y=i;
				break;
			}
		}

		if ( thismenu->entries_textarea[mouse_y] != NULL)
		{
			if ( !(thismenu->entries_flags[mouse_y] & (E_MENU_I_GHOSTED | E_MENU_I_NO_SELECT)))
			{
				thismenu->entries_flags[mouse_y] |= E_MENU_I_HIGHLIGHTED;
				e_menu_identifier_highlighted = e_menu_open_list[menuid].identifier;
				e_menu_item_highlighted = mouse_y;
			}
			/* If a submenu isn't open according to the flags... */
			if ( !(thismenu->entries_flags[mouse_y] & E_MENU_I_SUBMENU_OPEN))
			{
				/* Close all sub menus from this menu */
				if (thismenu->submenu_opened_identifier != E_MENU_ERROR )
				{
					for (i=0;i<E_MENU_MAX_ENTRIES;i++)
					{
						if (thismenu->entries_textarea[i] != NULL)
						{
							thismenu->entries_flags[i] = thismenu->entries_flags[i] & (~E_MENU_I_SUBMENU_OPEN);
						}
					}
	
					Editor_CloseMenu(thismenu->submenu_opened_identifier);
					thismenu->submenu_opened_identifier=E_MENU_ERROR;
				}

				/* If I'm on a submenu box and the submenu field is switched on then... */
				if (mouse_x>=(x+menu_max_text_width-12) && mouse_x<(x+menu_max_text_width) && (thismenu->entries_flags[mouse_y] & E_MENU_I_SUBMENU ) && !(thismenu->entries_flags[mouse_y] & E_MENU_I_GHOSTED))
				{
					/* Open the sub menu and flag the menu as being opened */
					if (thismenu->submenu_identifier[mouse_y] != E_MENU_ERROR )
					{
						Editor_SendMenuMessage(e_menu_open_list[menuid].identifier,mouse_y,E_MENU_M_OPENSUBMENU);
						thismenu->entries_flags[mouse_y] |= E_MENU_I_SUBMENU_OPEN;
						thismenu->submenu_opened_identifier=Editor_OpenMenu(thismenu->submenu_identifier[mouse_y],x+menu_max_text_width+4,(mouse_y*11)+y);
					}
				}
			}
		}
	}
}


/* Handles all mouse stuff to do with menus */
/* Accepts mouse x,y and buttons, returns -1 if pointer not over a menu otherwise returns */
/* the displayed menu identifier that the pointer is over. */
/* MUST be called before Editr_DrawMenus() */
int Editor_HandleMouse(int mouse_x,int mouse_y,int buttons )
{
	int i,menuid;

	e_menu_downl=0;
	e_menu_downr=0;

	if ( buttons & 1 )
	{
		e_menu_downl=1;
		e_menu_firstdownl++;
	}
	else
	{
		if (e_menu_clickdrag != E_MENU_ERROR && e_menu_firstdownl>0)
		{
			e_menu_clickdrag=E_MENU_ERROR;
		}
		e_menu_downl=0;
		e_menu_firstdownl=0;
	}

	if ( buttons & 2 )
	{
		e_menu_downr=1;
		e_menu_firstdownr++;
	}
	else
	{
		if (e_menu_clickdrag != E_MENU_ERROR && e_menu_firstdownr>0)
		{
			e_menu_clickdrag=E_MENU_ERROR;
		}
		e_menu_downr=0;
		e_menu_firstdownr=0;
	}

	e_menu_identifier_selected=E_MENU_ERROR;
	e_menu_identifier_highlighted=E_MENU_ERROR;
	e_menu_over_menu=E_MENU_ERROR;
	e_menu_item_selected=0;
	e_menu_item_highlighted=0;
	if ((e_menu_firstdownl>1 || e_menu_firstdownr>1 ) && e_menu_clickdrag != E_MENU_ERROR )
	{
		e_menu_open_list[e_menu_clickdrag].x=mouse_x+e_menu_clicked_x;
		e_menu_open_list[e_menu_clickdrag].y=mouse_y+e_menu_clicked_y;
		e_menu_over_menu=e_menu_clickdrag;
	}

	for (i=E_MENU_MAX_OPEN_MENUS-1;i>=0;i--)
	{
		menuid=e_menu_open_list[i].identifier;
		if (menuid!=E_MENU_ERROR && e_menu_over_menu == E_MENU_ERROR)
		{
			E_CalculateMouseMenuHighlight(i,mouse_x,mouse_y);
		}
	}

	if (e_menu_clickdrag != E_MENU_ERROR )
	{
		e_menu_over_menu=e_menu_clickdrag;
	}

	/* If a mouse click happens anywhere inside of any menu on an item then close all the menus */
	/* on screen. */
	if (e_menu_firstdownl==1 && e_menu_identifier_highlighted != E_MENU_ERROR)
	{
		e_menu_identifier_selected=e_menu_identifier_highlighted;
		e_menu_item_selected=e_menu_item_highlighted;
		Editor_SendMenuMessage(e_menu_identifier_selected,e_menu_item_selected,E_MENU_M_SELECTED);
		Editor_CloseAllMenus();
	}

	if (e_menu_firstdownr==1 && e_menu_identifier_highlighted != E_MENU_ERROR)
	{
		e_menu_identifier_selected=e_menu_identifier_highlighted;
		e_menu_item_selected=e_menu_item_highlighted;
		Editor_SendMenuMessage(e_menu_identifier_selected,e_menu_item_selected,E_MENU_M_SELECTED);
	}

	/* If a mouse click happens anywhere outside of any menu then close all the menus on screen */
	if ((e_menu_downl==1 || e_menu_downr==1) && e_menu_over_menu==E_MENU_ERROR )
	{
		Editor_CloseAllMenus();
	}

	if (e_menu_firstdownr==1 && e_menu_over_menu==E_MENU_ERROR )
	{
		e_menu_over_menu=Editor_OpenMenu(basemenuid,mouse_x-8,mouse_y-15);
		e_menu_firstdownl=0;
	}

	return e_menu_over_menu;
}


/* Game editing state */
void E_EditGame(mouse_x,mouse_y,buttons)
{

	if (game_map_loaded == 0)
	{
		BrPixelmapRectangleFill(back_screen,-320,-240,160,64,8+8*32+8*32*32);
		BrPixelmapTextF(back_screen,-320+16,-240+16,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
						"No game files loaded!!!!");
	}
}


/* Generic editing state */
void E_EditGeneric(mouse_x,mouse_y,buttons)
{

	BrPixelmapRectangleFill(back_screen,-320,-240,160,64,8+8*32+8*32*32);
	BrPixelmapTextF(back_screen,-320+16,-240+16,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
					"Generic edit state");
}


/* Lights editing state */
void E_EditLights(mouse_x,mouse_y,buttons)
{

	BrPixelmapRectangleFill(back_screen,-320,-240,160,64,8+8*32+8*32*32);
	BrPixelmapTextF(back_screen,-320+16,-240+16,BR_COLOUR_RGB(255,255,255),BrFontProp7x9,
					"Edit Lights state");

}


/* This is called to do all the editor specific fundtions for each edit mode */
void Editor_HandleEditorStates(int mouse_x,int mouse_y,int buttons)
{

	switch (editor_editmode)
	{
		case EDITMODE_GAME:
			E_EditGame(mouse_x,mouse_y,buttons);
			break;
		case EDITMODE_GENERIC:
			E_EditGeneric(mouse_x,mouse_y,buttons);
			break;
		case EDITMODE_LIGHTS:
			E_EditLights(mouse_x,mouse_y,buttons);
			break;
	}	
}


/* Usefull routine to search every actor from a given actor root */
/* Support variable and callback routines */
static br_actor *e_thisactor;
static br_uint_32 BR_CALLBACK E_SearchTreeCallBack(br_actor *a,void *arg)
{
	br_actor *act;

	act=BrActorSearch(a, (char *) arg);
	if (act != NULL)
	{
		e_thisactor=act;
	}

	return BrActorEnum(a,E_SearchTreeCallBack,arg);
}

/* Actual function */
br_actor *Editor_SearchTree(br_actor *actor,char *identifier)
{
	e_thisactor = NULL;
	BrActorEnum( actor, E_SearchTreeCallBack, (void*) identifier );
	return e_thisactor;
}


static br_actor *found;

static void recursetree(br_actor *this,char *identifier)
{

	if (this->identifier != NULL)
	{
		if (strcmp(this->identifier,identifier)==0)
			found = this;
	}


	if (this->next != NULL)
		recursetree(this->next,identifier);
	if (this->children != NULL)
		recursetree(this->children,identifier);
}


br_actor *Editor_SearchTreeNew(br_actor *actor,char *identifier)
{

	found = NULL;

	recursetree(actor,identifier);

	return found;
}


/*******************************************************************************/
/*******************************************************************************/
/* Editor specific stuff for animations */
/*******************************************************************************/
/*******************************************************************************/


void Editor_SetupAnimEnvironment(void)
{
}

