/***
****  QuBE --- Graphical display of the level, if possible.
****
****  As usual, it still needs work; better support of, well, everyentity.
***/

#include "qube.h"
#include "entities.h"
#include "gfx.h"

#ifdef QUBE_MSDOS
#include "svgagfx.h"
#endif
#ifdef QUBE_UNIX
#include "xgfx.h"
#endif

static void DrawScrn(int blackify);
static void DrawScrnXOR(int blackify);
static void DrawScrnMove(void);
static void DrawOneEnt(int highlight, int entity);
static void MouseMove(void);
static void ReadEntList(void);
static void ReadVertices(void);
static void ReadEdgeList(void);
static void UpdateEntXOR(int i, int blackify);
static void UpdateEnt(int i, int blackify);
static void EditObject(void);
static void StatusUpdate(void);
static void UpdateEdge(int i, int blackify);
static void UpdateEdgeXOR(int i, int blackify);
static void UpdateVertex(int i, int blackify);
static void UpdateVertexXOR(int i, int blackify);

char WaitEvent(void);
int EventsPending(void);

static long int orgx = 0, orgy = 0;
static int scale = 4;
static long int deltax, deltay, deltascale;

static long int grid = 8;

static int omx, omy, omb, tbx = 0, tby = 0;

static int NeedUpdate = 0;

static char *filename;

static float *vlistx;
static float *vlisty;
static float *vlistz;

static unsigned int *edgestart;
static unsigned int *edgeend;

static long int edgecount;
static long int vertexcount;

static mouseready = 0;

void DoGraphics(int argnum, char **argv)
{
	entity *tt;
	long int i;
        char c;
        char *type;
	char *entry;
	int x, y;

	filename = argv[filenamearg];

	ReadEntList();
	ReadVertices();
	ReadEdgeList();

	InitScrn(M640x480x256);
	StatusUpdate();
        InitMouse(640, 480, 1, 1);
	mouseready = 1;
        StdCursor(CURarrow);
	MouseOn();

        DrawScrnXOR(0);

	omx = MouseX;
	omy = MouseY;
	omb = MouseButton();

	deltax = deltay = deltascale = 0;

	do {
		if (!EventsPending() && NeedUpdate) {
			if (NeedUpdate & 2) DrawScrnMove();
			else DrawScrnXOR(0);
			MouseOn();
			NeedUpdate = 0;
                }

                switch (c = WaitEvent()) {
		case 0x7F:				/* Refresh Screen */
			NeedUpdate |= 1;
			break;
		case 0x7E:				/* Mouse move */
			for (i = 0; i < nextentity; i++) {
				if (i != curentity && entityarray[i]->origin != NULL) {
					x = 320 + (((entityarray[i]->x + orgx) * scale) >> 5);
					y = 240 - (((entityarray[i]->y + orgy) * scale) >> 5);
					if (omx > x-4 && omy > y-4 && omx < x+4 && omy < y+4) {
						DrawOneEnt(0, curentity);
						DrawOneEnt(1, curentity = i);
						break;
					}
				}
			}
                        break;
		case 0x7D:				/* Mouse button 1 press */

/* This is commented out because it's not done yet.  Sorry. */
#if 0
                        if (entityarray[curentity]->origin != NULL) {
				x = 320 + (((entityarray[curentity]->x + orgx) * scale) >> 5);
				y = 240 - (((entityarray[curentity]->y + orgy) * scale) >> 5);
				if (omx > x-4 && omy > y-4 && omx < x+4 && omy < y+4) {
					char originstr[128];
					MouseOff();
					while ((c = WaitEvent()) != 0x7C) {
						switch (c) {
						case 0x7F:
							DrawScrn(1);
							DrawScrnXOR(0);
							MouseOn();
							break;
                                                case 0x7E:
							UpdateEntXOR(curentity, -1);
							entityarray[curentity]->x = (((omx - 320) * 32) / scale) - orgx;
							entityarray[curentity]->y = (((240 - omy) * 32) / scale) - orgy;
							UpdateEntXOR(curentity, -1);
							break;
						}
					}
					DrawOneEnt(0, curentity);
					DrawOneEnt(1, curentity);
					MouseOn();
					Qfree(entityarray[curentity]->origin);
					sprintf(originstr, "%ld %ld %ld", entityarray[curentity]->x,
						entityarray[curentity]->y, entityarray[curentity]->z);
					entityarray[curentity]->origin = Qmalloc(strlen(originstr)+1);
					strcpy(entityarray[curentity]->origin, originstr);
				}
			}
#endif
                        if ((omx > tbx && omy > tby+410 && omx < tbx+14 && omy < tby+479) ||
			    (omx > tbx+307 && omy > tby+410 && omx < tbx+320 && omy < tby+479)) {
                                int ox = omx-tbx, oy = omy-tby;
				int mx = omx, my = omy;
                                MouseOff();
				DrawScrnXOR(0);
				MouseOff();
                                BoxOutlnXOR(omx-ox, omy-oy+410, omx-ox+320, omy-oy+479, WHITE);
                                while ((c = WaitEvent()) != 0x7C) {
					switch (c) {
					case 0x7F:
						DrawScrn(1);
						DrawScrnXOR(0);
						break;
                                        case 0x7E:
						BoxOutlnXOR(mx-ox, my-oy+410, mx-ox+320, my-oy+479, WHITE);
                                                mx = omx;
						my = omy;
						BoxOutlnXOR(omx-ox, omy-oy+410, omx-ox+320, omy-oy+479, WHITE);
                                                break;
					}
				}
				BoxOutlnXOR(omx-ox, omy-oy+410, omx-ox+320, omy-oy+479, WHITE);
				BoxFill(tbx, tby+410, tbx+320, tby+479, BLACK);
				tbx = omx-ox;
				tby = omy-oy;
				NeedUpdate |= 1;
                                MouseOn();
                        }
                        break;
		case 0x7C:				/* Mouse button 1 release */
			break;
		case 0x7B:				/* Mouse button 2 press */
			break;
		case 0x7A:				/* Mouse button 2 release */
			break;
		case 0x1C:				/* Enter/edit key */
			EditObject();
			break;
                case 0x48:                              /* Up arrow */
			deltay -= (10 * 32) / scale;
			NeedUpdate |= 2;
                        break;
		case 0x4B:				/* Left arrow */
			deltax += (10 * 32) / scale;
			NeedUpdate |= 2;
			break;
		case 0x4D:				/* Right arrow */
			deltax -= (10 * 32) / scale;
			NeedUpdate |= 2;
			break;
		case 0x50:				/* Down arrow */
			deltay += (10 * 32) / scale;
			NeedUpdate |= 2;
			break;
		case 0xC:				/* Minus/zoom out */
			if (scale+deltascale > 1) {
				deltascale--;
				NeedUpdate |= 2;
			}
			break;
		case 0xD:				/* Plus/zoom in */
			if (scale+deltascale < 32) {
				deltascale++;
				NeedUpdate |= 2;
			}
			break;
		case 0x31:				/* N/next object */
			DrawOneEnt(0, curentity);
			do {
				if (++curentity >= nextentity) curentity = 0;
			} while (entityarray[curentity]->type == ENTITY_LIGHT);
			DrawOneEnt(1, curentity);
                        break;
		case 0x19:				/* P/previous object */
			DrawOneEnt(0, curentity);
			do {
				if (--curentity < 0) curentity = nextentity - 1;
			} while (entityarray[curentity]->type == ENTITY_LIGHT);
			DrawOneEnt(1, curentity);
                        break;
		case 0x22:				/* G/grid */
			/* This was for manipulating a grid which could overlay the level.
			   The code sucked rocks, so it's been removed. */
                        break;

                }
	} while (c != 0x1);

	MouseOff();
        KillMouse();
        InitScrn(M80x25x16);
}

static void ReadVertices(void)
{
	int i, j, k;
	int readcount;
	vertex v;

	vlistx = Qmalloc(header.verticeslen/3);
	vlisty = Qmalloc(header.verticeslen/3);
	vlistz = Qmalloc(header.verticeslen/3);

	fseek(fi, header.vertices, SEEK_SET);

        for (i = 0, readcount = 0L; readcount < header.verticeslen; readcount += 12, i++) {
		fread((char *)(&v), 1, 12, fi);
		vlistx[i] = v.x;
		vlisty[i] = v.y;
		vlistz[i] = v.z;
        }
	vertexcount = i;
}

static void ReadEdgeList(void)
{
	int i, j, k;
	int readcount;
	struct {
		int start, end;
	} edge;

	edgestart = Qmalloc(header.edgeslen/2);
	edgeend  = Qmalloc(header.edgeslen/2);

	fseek(fi, header.edges, SEEK_SET);

	for (i = 0, readcount = 0L; readcount < header.edgeslen; readcount += 4, i++) {
		fread((char *)(&edge), 1, 4, fi);
		edgestart[i] = edge.start;
		edgeend[i] = edge.end;
		if (edge.start < 0 || edge.end < 0) i--;
        }
	edgecount = i;
}

static void ReadEntList(void)
{
	entity *tt;
	long int i;
        char c;
        char *type;
	char *entry;
	int x, y;

	maxlen = header.entitieslen;
        if (header.id != 0x17)
		Error("Not a valid .BSP file");

	fseek(fi, header.entities, SEEK_SET);
	do {
		tt = (entity *)Qmalloc(sizeof(entity));

		tt->classname = NULL;
		tt->origin = NULL;
		tt->model = NULL;
		tt->light = NULL;
		tt->angle = NULL;
		tt->wad = NULL;
		tt->style = NULL;
		tt->spawnflags = NULL;

		skipspace(fi);
		getopenbrace(fi);
		nextchar(fi);

		if (fileend()) break;

		do {
			putback = 1;
			skipspace(fi);
			type = getstring(fi);
			skipspace(fi);
			entry = getstring(fi);
			skipspace(fi);
			if (strcmp(type, "classname") == 0) tt->classname = entry;
			if (strcmp(type, "origin") == 0) tt->origin = entry;
			if (strcmp(type, "model") == 0) tt->model = entry;
			if (strcmp(type, "light") == 0) tt->light = entry;
			if (strcmp(type, "angle") == 0) tt->angle = entry;
			if (strcmp(type, "style") == 0) tt->style = entry;
			if (strcmp(type, "wad") == 0) tt->wad = entry;
			if (strcmp(type, "spawnflags") == 0) tt->spawnflags = entry;

			c = nextchar(fi);
		} while (c != '}' && c != EOF && c != '\0');

		if (tt->classname != NULL) {
			if (strncmp(tt->classname, "weapon_", 7) == 0) tt->type = ENTITY_WEAPON;
			else if (strncmp(tt->classname, "monster_", 7) == 0) tt->type = ENTITY_MONSTER;
			else if (strncmp(tt->classname, "item_health", 11) == 0) tt->type = ENTITY_HEALTH;
			else if (strncmp(tt->classname, "item_", 5) == 0) tt->type = ENTITY_ITEM;
			else if (strcmp(tt->classname, "light") == 0) tt->type = ENTITY_LIGHT;
			else if (strncmp(tt->classname, "light", 5) == 0) tt->type = ENTITY_VISILIGHT;
			else if (strncmp(tt->classname, "info_player_start", 17) == 0) tt->type = ENTITY_START;
			else if (strncmp(tt->classname, "info_player_deathmatch", 22) == 0) tt->type = ENTITY_DMSTART;
			else tt->type = ENTITY_NONE;
                }

		if (tt->origin != NULL)
			sscanf(tt->origin, "%ld%ld%ld", &(tt->x), &(tt->y), &(tt->z));

		entityarray[nextentity++] = tt;

		skipspace(fi);

	} while (!fileend());
}

static void DrawScrnXOR(int blackify)
{
	long int x, y, z, s, so;
	int i, color;

	blackify = 0;

	MouseOff();
	if (blackify) DrawOneEnt(0, curentity);
        MouseOff();

	for (i = 0; i < vertexcount; i++) UpdateVertexXOR(i, blackify);
        for (i = 0; i < nextentity; i++) UpdateEntXOR(i, blackify);

	color = BLUE;
	if (blackify == 1) color = BLACK;

	if (blackify != -2) {
		i = (orgx * scale) >> 5;
		LineXOR(320+i, 0, 320+i, 479, color);
		i = (orgy * scale) >> 5;
		LineXOR(0, 240-i, 639, 240-i, color);
	}

	if (!blackify) DrawOneEnt(1, curentity);
        MouseOn();
}

static void DrawScrnMove(void)
{
	long int x, y, z, s, so;
	int i;

	MouseOff();
	DrawOneEnt(0, curentity);
        MouseOff();

	for (i = 0; i < vertexcount; i++) {
                orgx += deltax;
		orgy += deltay;
		scale += deltascale;
		UpdateVertexXOR(i, 0);
		orgx -= deltax;
		orgy -= deltay;
		scale -= deltascale;
		UpdateVertexXOR(i, 0);
        }
	for (i = 0; i < nextentity; i++) {
                orgx += deltax;
		orgy += deltay;
		scale += deltascale;
		UpdateEntXOR(i, 0);
		orgx -= deltax;
		orgy -= deltay;
		scale -= deltascale;
		UpdateEntXOR(i, 0);
        }

        orgx += deltax;
	orgy += deltay;
	scale += deltascale;
        i = (orgx * scale) >> 5;
	LineXOR(320+i, 0, 320+i, 479, BLUE);
	i = (orgy * scale) >> 5;
	LineXOR(0, 240-i, 639, 240-i, BLUE);
	orgx -= deltax;
	orgy -= deltay;
	scale -= deltascale;
	i = (orgx * scale) >> 5;
	LineXOR(320+i, 0, 320+i, 479, BLUE);
	i = (orgy * scale) >> 5;
	LineXOR(0, 240-i, 639, 240-i, BLUE);

        orgx += deltax;
	orgy += deltay;
	scale += deltascale;

        deltax = deltay = deltascale = 0;

	DrawOneEnt(1, curentity);
        MouseOn();
}

static void DrawScrn(int blackify)
{
	int i, color;

	MouseOff();

	for (i = 0; i < nextentity; i++) UpdateEnt(i, blackify);
	for (i = 0; i < vertexcount; i++) UpdateVertex(i, blackify);

	color = BLUE;
	if (blackify == 1) color = BLACK;

        i = (orgx * scale) >> 5;
	Line(320+i, 0, 320+i, 479, color);
	i = (orgy * scale) >> 5;
	Line(0, 240-i, 639, 240-i, color);

	if (!blackify) DrawOneEnt(1, curentity);
        MouseOn();
}

static void UpdateEdge(int i, int blackify)
{
	int x, y, color;
	long int sx, sy, ex, ey;
	long int dsx, dsy, dex, dey;

	sx = (long int)(vlistx[edgestart[i]]);
	sy = (long int)(vlisty[edgestart[i]]);
	ex = (long int)(vlistx[edgeend[i]]);
	ey = (long int)(vlisty[edgeend[i]]);

	dsx = (((sx + orgx) * scale) >> 5);
	dsy = (((sy + orgy) * scale) >> 5);
	dex = (((ex + orgx) * scale) >> 5);
	dey = (((ey + orgy) * scale) >> 5);

	color = GRAY;
	if (blackify == 1) color = BLACK;

	Pixel(320+dsx, 240-dsy, color);
}

static void UpdateEdgeXOR(int i, int blackify)
{
	int x, y, color;
	long int sx, sy, ex, ey;
	long int dsx, dsy, dex, dey;

	sx = (long int)(vlistx[edgestart[i]]);
	sy = (long int)(vlisty[edgestart[i]]);
	ex = (long int)(vlistx[edgeend[i]]);
	ey = (long int)(vlisty[edgeend[i]]);

	dsx = (((sx + orgx) * scale) >> 5);
	dsy = (((sy + orgy) * scale) >> 5);
	dex = (((ex + orgx) * scale) >> 5);
	dey = (((ey + orgy) * scale) >> 5);

	color = GRAY;
	if (blackify == 1) color = BLACK;

        if (blackify != -2) {
		PixelXOR(320+dsx, 240-dsy, color);
        }
}

static void UpdateVertex(int i, int blackify)
{
	int x, y, color;
	long int vx, vy;

	vx = (long int)(vlistx[i]);
	vy = (long int)(vlisty[i]);

	x = (((vx + orgx) * scale) >> 5);
	y = (((vy + orgy) * scale) >> 5);

	color = GRAY;
	if (blackify == 1) color = BLACK;

	Pixel(320+x, 240-y, color);
}

static void UpdateVertexXOR(int i, int blackify)
{
	int x, y, color;
	long int vx, vy;

	vx = (long int)(vlistx[i]);
	vy = (long int)(vlisty[i]);

	x = (((vx + orgx) * scale) >> 5);
	y = (((vy + orgy) * scale) >> 5);

	color = GRAY;
	if (blackify == 1) color = BLACK;

        if (blackify != -2) {
		PixelXOR(320+x, 240-y, color);
        }
}

static void UpdateEnt(int i, int blackify)
{
	int x, y, color;

	if (entityarray[i]->origin != NULL) {
		x = (((entityarray[i]->x + orgx) * scale) >> 5);
		y = (((entityarray[i]->y + orgy) * scale) >> 5);

		if (i == curentity) {
			if (blackify == 0) BoxOutln(317+x, 237-y, 323+x, 243-y, LRED);
			else BoxOutln(317+x, 237-y, 323+x, 243-y, BLACK);
		}

		switch(entityarray[i]->type) {
		case ENTITY_LIGHT:
			color = WHITE;
			if (blackify == 1) color = BLACK;
			Pixel(320+x, 240-y, color);
                        break;
		case ENTITY_ITEM:
			color = LBLUE;
			if (blackify == 1) color = BLACK;
			BoxFill(319+x, 239-y, 321+x, 241-y, color);
			break;
		case ENTITY_HEALTH:
			color = LRED;
			if (blackify == 1) color = BLACK;
			Line(317+x, 240-y, 323+x, 240-y, color);
			Line(320+x, 237-y, 320+x, 243-y, color);
			break;
		case ENTITY_START:
			color = GREEN;
			if (blackify == 1) color = BLACK;
			BoxOutln(318+x, 238-y, 322+x, 242-y, color);
			BoxFill(320+x, 240-y, 320+x, 240-y, color);
			break;
		case ENTITY_DMSTART:
			color = LGREEN;
			if (blackify == 1) color = BLACK;
			BoxFill(319+x, 239-y, 321+x, 241-y, color);
			break;
		case ENTITY_WEAPON:
			color = BROWN;
			if (blackify == 1) color = BLACK;
			BoxOutln(318+x, 238-y, 322+x, 242-y, color);
			Pixel(320+x, 240-y, color);
                        if (color == BROWN) color = YELLOW;
			BoxOutln(319+x, 239-y, 321+x, 241-y, color);
                        break;
		case ENTITY_MONSTER:
			color = LRED;
			if (blackify == 1) color = BLACK;
			Line(318+x, 238-y, 322+x, 242-y, color);
			Line(318+x, 242-y, 322+x, 238-y, color);
			Line(320+x, 240-y, 320+x, 240-y, color);
			break;
		case ENTITY_VISILIGHT:
			color = WHITE;
			if (blackify == 1) color = BLACK;
			BoxFill(319+x, 239-y, 321+x, 241-y, color);
                        break;
                default:
			color = VIOLET;
			if (blackify == 1) color = BLACK;
			BoxFill(319+x, 239-y, 321+x, 241-y, color);
			break;
		}
	}
}

static void UpdateEntXOR(int i, int blackify)
{
	int x, y, color;

	if (entityarray[i]->origin != NULL) {
		x = (((entityarray[i]->x + orgx) * scale) >> 5);
		y = (((entityarray[i]->y + orgy) * scale) >> 5);

		if (blackify < 0)
			BoxOutlnXOR(317+x, 237-y, 323+x, 243-y, LRED);

		if (blackify != -2) {
			switch(entityarray[i]->type) {
			case ENTITY_LIGHT:
				color = WHITE;
				if (blackify == 1) color = BLACK;
				PixelXOR(320+x, 240-y, color);
                                break;
			case ENTITY_ITEM:
				color = LBLUE;
				if (blackify == 1) color = BLACK;
				BoxFillXOR(319+x, 239-y, 321+x, 241-y, color);
				break;
			case ENTITY_HEALTH:
				color = LRED;
				if (blackify == 1) color = BLACK;
				LineXOR(317+x, 240-y, 323+x, 240-y, color);
				LineXOR(320+x, 237-y, 320+x, 243-y, color);
				break;
			case ENTITY_START:
				color = GREEN;
				if (blackify == 1) color = BLACK;
				BoxOutlnXOR(318+x, 238-y, 322+x, 242-y, color);
				BoxFillXOR(320+x, 240-y, 320+x, 240-y, color);
				break;
			case ENTITY_DMSTART:
				color = LGREEN;
				if (blackify == 1) color = BLACK;
				BoxFillXOR(319+x, 239-y, 321+x, 241-y, color);
				break;
			case ENTITY_WEAPON:
				color = BROWN;
				if (blackify == 1) color = BLACK;
				BoxOutlnXOR(318+x, 238-y, 322+x, 242-y, color);
				PixelXOR(320+x, 240-y, color);
				if (color == BROWN) color = YELLOW;
				BoxOutlnXOR(319+x, 239-y, 321+x, 241-y, color);
                                break;
			case ENTITY_MONSTER:
				color = LRED;
				if (blackify == 1) color = BLACK;
				LineXOR(318+x, 238-y, 322+x, 242-y, color);
				LineXOR(318+x, 242-y, 322+x, 238-y, color);
				LineXOR(320+x, 240-y, 320+x, 240-y, color);
				break;
			case ENTITY_VISILIGHT:
				color = WHITE;
				if (blackify == 1) color = BLACK;
				BoxFillXOR(319+x, 239-y, 321+x, 241-y, color);
                                break;
                        default:
				color = VIOLET;
                                if (blackify == 1) color = BLACK;
				BoxFillXOR(319+x, 239-y, 321+x, 241-y, color);
				break;
			}
		}
        }
}

static void DrawOneEnt(int highlight, int entity)
{
	long int x, y, z;
	int i = entity, color;

	x = (((entityarray[i]->x + orgx) * scale) >> 5);
	y = (((entityarray[i]->y + orgy) * scale) >> 5);

	MouseOff();
	color = LRED;
	if (entityarray[entity]->origin != NULL)
		BoxOutlnXOR(317+x, 237-y, 323+x, 243-y, color);

	if (highlight) {
		BoxFill(tbx+14, tby+411, tbx+306, tby+478, LGRAY);
		BoxFill(tbx+1, tby+411, tbx+13, tby+478, GRAY);
		BoxFill(tbx+307, tby+411, tbx+319, tby+478, GRAY);
                BoxOutln(tbx+0, tby+410, tbx+320, tby+479, WHITE);

		Gprintf(tbx+16, tby+415, Sans14N, BLACK, "#%d. \"%s\"", i, entityarray[i]->classname);

		x = tbx+16;
		if (entityarray[i]->origin != NULL)
			x = Gprintf(x, tby+430, Sans14N, BLACK, "(%s) ", entityarray[i]->origin);
		if (entityarray[i]->angle != NULL)
			Gprintf(x, tby+430, Sans14N, BLACK, "Angle=%s", entityarray[i]->angle);

		if (entityarray[i]->spawnflags != NULL)
			Gprintf(tbx+16, tby+445, Sans14N, BLACK, "SpawnFlags=%s", entityarray[i]->spawnflags);

		x = tbx+16;
		if (entityarray[i]->model != NULL)
			x = Gprintf(x, tby+460, Sans14N, BLACK, "Model=%s ", entityarray[i]->model);
		if (entityarray[i]->style != NULL)
			Gprintf(x, tby+460, Sans14N, BLACK, "Style=%s", entityarray[i]->style);
	}

        MouseOn();
}

char WaitEvent(void)
{
	int i, j;

        while (1) {
		if (KeyStatus()) return(ReadKeyScan());
		else if (omb != (i = MouseButton())) {
			ReadMouse();
			omx = MouseX;
			omy = MouseY;
                        j = omb ^ i;
			omb = i;
			if ((j & 1) && (omb & 1)) return(0x7D);
			if ((j & 1) && !(omb & 1)) return(0x7C);
			if ((j & 2) && (omb & 2)) return(0x7B);
			if ((j & 2) && !(omb & 2)) return(0x7A);
                }
		else {
			ReadMouse();

			if (omx != MouseX || omy != MouseY) {
				omx = MouseX;
				omy = MouseY;
				return(0x7E);
                        }
                }
        }
}

int EventsPending(void)
{
	if (KeyStatus() || omb != MouseButton()) return(1);
	ReadMouse();
	if (omx != MouseX || omy != MouseY) return(1);
	return(0);
}

static void EditObject(void)
{
	DrawScrn(1);
	DrawScrnXOR(0);
	MouseOn();
}

static void StatusUpdate(void)
{
	if (mouseready) MouseOff();
	LimitY1 = 0;
        BoxOutln(0, 0, 319, 18, WHITE);
	BoxFill(1, 1, 318, 17, LGRAY);
	BoxOutln(320, 0, 639, 18, WHITE);
	BoxFill(321, 1, 638, 17, LGRAY);

	Gprintf(5, 2, Sans14N, BLACK, "%s", filename);
	Gprintf(325, 2, Sans14N, BLACK, "Entities");
	LimitY1 = 19;
	if (mouseready) MouseOn();
}

