view visuality.c @ 89:5a195ee08eac

Fix memory leak and bug that was preventing First@Dictionary from working properly
author Mike Pavone <pavone@retrodev.com>
date Sat, 31 Jul 2010 00:19:15 -0400
parents 76568becd6d6
children
line wrap: on
line source



#include <stdio.h>
#include <math.h>

#include "structs.h"
#include "visuality.h"
#include "interp.h"
#include "parser.h"
#include "saveload.h"


#define	NUM_SPRITES	5


FILE * outfile;


HGLRC		hRC = NULL;
HDC			hDC = NULL;
HWND		hWnd = NULL;
HINSTANCE	hInstance;
GLuint	glyph_base;

BOOL mouse_left_down=FALSE;
BOOL mouse_leftstart_down=FALSE;
int mouse_lastx;
int mouse_lasty;
int mouse_curx;
int mouse_cury;
int start_wire_worker=-1;
int start_wire_ionum=-2;
BOOL start_wire_isinput;
BOOL checked_mouse_pos=FALSE;

char new_name_buf[256];
int buf_size=0;

extern char text_buf[256];
extern int text_buf_size=0;

extern BOOL execute_active;

worker * view_workerlist;
wire * view_wirelist;

int current_def=0;
/*
void save_program(char * filename)
{
	worker * aworkerlist;
	wire * awirelist;
	FILE * savefile;
	int def_num, version = 1;
	savefile = fopen(filename, "wb");
	if(!savefile)
		return;
	deflist[current_def].num_workers = num_workers;
	deflist[current_def].num_wires = num_wires;
	fwrite(&version, 4, 1, savefile);
	fwrite(&num_defs, 4, 1, savefile);
	fwrite(deflist, sizeof(worker_def), num_defs, savefile);
	for(def_num = 0; def_num < num_defs; ++def_num)
	{
		if(deflist[def_num].workerlist)
		{
			fwrite(&def_num, 4, 1, savefile);
			//fwrite(&(deflist[def_num].num_workers), 4, 1, savefile);
			fwrite(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, savefile);
			//fwrite(&(deflist[def_num].num_wires), 4, 1, savefile);
			fwrite(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, savefile);
		}
	}
	def_num = -1;
	fwrite(&def_num, 4, 1, savefile);
	fclose(savefile);
}

void load_program(char * filename)
{
	char msg[256];
	worker * aworkerlist;
	wire * awirelist;
	FILE * loadfile;
	int def_num, version;
	loadfile = fopen(filename, "rb");
	if(!loadfile)
	{
		MessageBox(NULL, "Could not open file","Error",MB_OK);
		return;
	}
	fread(&version, 4, 1, loadfile);
	if(version != 1)
	{
		MessageBox(NULL, "Can't read files of this version.","Error",MB_OK);
		return;
	}
	fread(&num_defs, 4, 1, loadfile);
	fread(deflist, sizeof(worker_def), num_defs, loadfile);
	fread(&def_num, 4, 1, loadfile);
	while(def_num >= 0 && !feof(loadfile))
	{
		sprintf(msg, "Reading def %X at %X", def_num, ftell(loadfile));
		MessageBox(NULL, msg, "debug",MB_OK);
		deflist[def_num].workerlist = malloc((deflist[def_num].num_workers+512)*sizeof(worker));
		fread(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, loadfile);
		deflist[def_num].wirelist = malloc((deflist[def_num].num_wires+1024)*sizeof(wire));
		fread(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, loadfile);
		deflist[def_num].workers_to_wires_up = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
		deflist[def_num].workers_to_wires_down = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
		fread(&def_num, 4, 1, loadfile);
	}
	fclose(loadfile);
	view_workerlist = deflist[0].workerlist;
	view_wirelist = deflist[0].wirelist;
	num_workers = deflist[0].num_workers;
	num_wires = deflist[0].num_wires;
	initpredefworkers();
	//sprintf(msg,"%d workers, %d wires in %s",deflist[0].num_workers,deflist[0].num_wires,deflist[0].name);
	//MessageBox(NULL,msg,"visdbg",MB_OK);
}*/



BOOL	keys[256];
BOOL	active = TRUE;
BOOL	fullscreen=TRUE;
BOOL	gameover = FALSE;

GLfloat		xrot;								// X Rotation ( NEW )
GLfloat		yrot;								// Y Rotation ( NEW )
GLfloat		zrot;								// Z Rotation ( NEW )

GLuint		texture[NUM_SPRITES];							// Storage For One Texture ( NEW )
float		xsizes[NUM_SPRITES] = {0.75f, 1.0f, 0.25f, 0.25f, 2.0f};
float		ysizes[NUM_SPRITES] = {1.0f, 0.5f, 0.25f, 0.25f, 2.0f};
float		xtexturefit[NUM_SPRITES] = {0.75f, 1.0f, 1.0f, 1.0f, 1.0f};
float		ytexturefit[NUM_SPRITES] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
float		gunxpos = 5.0f;
char	spritenames[NUM_SPRITES][32] = {"rini.bmp", "zapper.bmp", "heart.bmp", "fireball.bmp", "kiss.bmp"};

#define SCREEN_WIDTH_REL	8.8f
#define SCREEN_HEIGHT_REL	6.6f
#define PI 3.14159265

int selected_worker = -1;
int selected_wire = -1;


int killed = 0;


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
	

AUX_RGBImageRec *LoadBMP(char *Filename)					// Loads A Bitmap Image
{
	FILE *File=NULL;							// File Handle
	if (!Filename)								// Make Sure A Filename Was Given
	{
		return NULL;							// If Not Return NULL
	}
	File=fopen(Filename,"r");						// Check To See If The File Exists
	if (File)								// Does The File Exist?
	{
		fclose(File);							// Close The Handle
		return auxDIBImageLoad(Filename);				// Load The Bitmap And Return A Pointer
	}
	return NULL;								// If Load Failed Return NULL
}
/*
int LoadGLTextures()								// Load Bitmaps And Convert To Textures
{
	int Status=FALSE;							// Status Indicator
	AUX_RGBImageRec *TextureImage[NUM_SPRITES];					// Create Storage Space For The Texture
	int i;
	

	for(i = 0; i < NUM_SPRITES; ++i)
	{
		
		TextureImage[i] = NULL;				// Set The Pointer To NULL
		// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
		if (TextureImage[i]=LoadBMP(spritenames[i]))
		{
			Status=TRUE;							// Set The Status To TRUE
			glGenTextures(1, &texture[i]);					// Create The Texture
	
			// Typical Texture Generation Using Data From The Bitmap
			glBindTexture(GL_TEXTURE_2D, texture[i]);
			// Generate The Texture
			glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[i]->data);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	// Linear Filtering
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	// Linear Filtering
		}
		if (TextureImage[i])							// If Texture Exists
		{
			if (TextureImage[i]->data)					// If Texture Image Exists
			{
				free(TextureImage[i]->data);				// Free The Texture Image Memory
			}
	
			free(TextureImage[i]);						// Free The Image Structure
		}
		//xsizes[i] = 0.5f;
		//ysizes[i] = 1.0f;
	}
	
	return Status;								// Return The Status
}

*/

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
	if(height ==0)
		height = 1;
	glViewport(0,0,width,height);

	glMatrixMode(GL_PROJECTION);	//Reset projection matrix
	glLoadIdentity();
	
	//Calculate aspect ratio
	gluPerspective(45.0f, (GLfloat)width/ (GLfloat)height, 0.1f, 100.0f);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();				//reset modelview matrix
}

int InitGL(GLvoid)
{
	//if (!LoadGLTextures())							// Jump To Texture Loading Routine ( NEW )
	//{
	//	return FALSE;							// If Texture Didn't Load Return FALSE ( NEW )
	//}
	HFONT font;
	glEnable(GL_TEXTURE_2D);
	glShadeModel(GL_SMOOTH);
	
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	//blackness
	
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glEnable(GL_COLOR_MATERIAL);


	
	font = CreateFont(-24, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, 
		ANTIALIASED_QUALITY, FF_SWISS || VARIABLE_PITCH, "Arial");
	SelectObject(hDC, font);

	glyph_base = glGenLists(224);
	wglUseFontOutlines(hDC, 32, 224, glyph_base, 0.0, 0.0, WGL_FONT_POLYGONS, NULL);
	DeleteObject(font);
	
	return TRUE;
}

void drawtriangle(double xpos, double ypos, double width, double height, double angle)
{
	if(xpos != 0.0 || ypos != 0.0)
		glTranslatef(xpos, ypos, 0.0);
	
	if(angle != 0.0)
		glRotatef(angle, 0.0,0.0,1.0);
		
	glBegin(GL_TRIANGLES);
		glVertex2f(0.0, height/2); //Top
		glVertex2f(0.0 - width/2, 0.0 - height/2); //Left
		glVertex2f(width/2, 0.0 - height/2); //Right
	glEnd();		
		
	if(angle != 0.0)
		glRotatef(0.0-angle, 0.0,0.0,1.0);//restore rotation without loading identity
	if(xpos != 0.0 || ypos != 0.0)
		glTranslatef(0.0-xpos, 0.0-ypos, 0.0);
}

void drawrect(double xpos, double ypos, double width, double height, double angle)
{
	if(xpos != 0.0 || ypos != 0.0)
		glTranslatef(xpos, ypos, 0.0);
	
	if(angle != 0.0)
		glRotatef(angle, 0.0,0.0,1.0);
		
	glBegin(GL_QUADS);
		glVertex2f(0.0 - width/2,  height/2.0); //Top Left
		glVertex2f(width/2, height/2.0); //Top Right
		glVertex2f(width/2, 0.0 - height/2.0); //Bottom Right
		glVertex2f(0.0 - width/2, 0.0 - height/2.0); //Bottom Left
		
	glEnd();
		
	if(angle != 0.0)
		glRotatef(0.0-angle, 0.0,0.0,1.0);//restore rotation without loading identity
	if(xpos != 0.0 || ypos != 0.0)
		glTranslatef(0.0-xpos, 0.0-ypos, 0.0);
}
void drawshapestrip(int shape_type, double length, double ypos, double width, double height, int num)
{
	double currentpos, spacing;
	int i;
	
	spacing = length/(double)num;
	currentpos = 0.0 - length/2.0 + spacing/2.0;
	for(i = 0; i < num; ++i)
	{
		if(shape_type == 0)
			drawtriangle(currentpos, ypos, width, height, 0.0);
		else
			drawrect(currentpos, ypos, width, height, 0.0);
		currentpos += spacing;
	}
}

double get_io_xpos(worker * some_worker, int output_num, BOOL is_input)
{
	double length, currentpos, spacing;
	if(is_input && output_num == -1)
		return some_worker->xpos + some_worker->width/2.0 + INPUT_SIZE/2.0;
	if(some_worker->type == 2 && is_input) //Trapezoid
		length = 2.0*(some_worker->width)/3.0;
	else
		length = some_worker->width;
	fprintf(outfile, "Worker length: %f, worker width: %f\n");
	if(is_input)
		spacing = length/(some_worker->num_inputs);
	else
		spacing = length/(some_worker->num_outputs);
	currentpos = some_worker->xpos - length/2.0 + spacing/2.0;
	return currentpos + spacing * (double)output_num;
}

double get_io_ypos(worker * some_worker, int output_num, BOOL is_input)
{
	if(is_input && output_num != -1)
		return some_worker->ypos + (some_worker->height)/2.0;
	else
		return some_worker->ypos - ((some_worker->height)/2.0);
}

void drawshape(int shape_type, double xpos, double ypos, double width, double height, double angle, int inputs, int outputs, char *text, BOOL selected)
{
	double x, y,temp, currentpos, spacing;
	double *inputx, *inputy, *outputx, *outputy;
	double ioangle, hypot;
	int i;
	glLoadIdentity();
	glTranslatef(SCREEN_WIDTH_REL / (-2.0f) + xpos, SCREEN_HEIGHT_REL / (-2.0f) + ypos,-8.0f);
	xpos = 0.0; ypos = 0.0;
	glRotatef(angle, 0.0,0.0,1.0);
	if(selected)
		glColor3f(SELECT_RED, SELECT_GREEN, SELECT_BLUE);
	else
		glColor3f(BODY_RED, BODY_GREEN, BODY_BLUE);
	switch(shape_type)
	{
	case 0: //Triangle
		drawtriangle(0.0, 0.0, width, height, 0.0);
		glTranslatef(0.0-width/4.0, 0.0-height/4.0,0);
		
		break;
	case 1: //Rectangle
		drawrect(0.0, 0.0, width, height, angle);
		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
		if(inputs)
			drawshapestrip(0, width, height/2.0 + INPUT_SIZE/2.0,INPUT_SIZE, INPUT_SIZE, inputs);
		drawtriangle(xpos + width/2.0 + INPUT_SIZE/2.0, ypos-height/2.0+INPUT_SIZE/2.0, INPUT_SIZE, INPUT_SIZE, 0.0);
		glColor3f(OUTPUT_RED, OUTPUT_GREEN, OUTPUT_BLUE);
		if(outputs)
			drawshapestrip(1, width, 0.0-(height/2.0 + OUTPUT_SIZE/2.0),OUTPUT_SIZE, OUTPUT_SIZE, outputs);
		glTranslatef(0.0-width/2.0 + width/16.0, 0.0-height/3.0, 0.0);
		
		break;
	case 2: //Trapezoid
		glBegin(GL_QUADS);
			glVertex2f(xpos - width/3.0 , ypos + height/2.0); //Top Left
			glVertex2f(xpos + width/3.0, ypos + height/2.0); //Top Right
			glVertex2f(xpos + width/2.0, ypos - height/2.0); //Bottom Right
			glVertex2f(xpos - width/2.0, ypos - height/2.0); //Bottom Left
		glEnd();
		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
		if(inputs)
			drawshapestrip(0, 2.0*(width/3.0), height/2.0 + INPUT_SIZE/2.0,INPUT_SIZE, INPUT_SIZE, inputs);
		drawtriangle(xpos + width/2.0 + INPUT_SIZE/2.0, ypos-height/2.0+INPUT_SIZE/2.0, INPUT_SIZE, INPUT_SIZE, 0.0);
		glColor3f(OUTPUT_RED, OUTPUT_GREEN, OUTPUT_BLUE);
		if(outputs)
			drawshapestrip(1, width, 0.0-(height/2.0 + OUTPUT_SIZE/2.0),OUTPUT_SIZE, OUTPUT_SIZE, outputs);
		glTranslatef(0.0-width/3.0, 0.0-height/3.0, 0.0);
		break;
		
	case 3: //Ellipse
	
		x = 3.4587;
		y = 2293.784;
		
		glBegin(GL_TRIANGLE_FAN);
			glVertex2f(0.0, 0.0);
			
			if(inputs)
			{
				spacing = width/(double)inputs;
				currentpos = 0.0-width/2.0 + spacing/2.0;
				inputx = (double *)malloc(inputs*sizeof(double));
				inputy = (double *)malloc(inputs*sizeof(double));
				i = 0;
			}
			for(x = 0.0-width/2 ; x <= width/2.0+CIRCLE_STEP; x += CIRCLE_STEP)
			{
				y = sqrt(fabs(pow(height/2.0,2) - (pow(height/2.0,2)*pow(x, 2))/pow(width/2.0, 2)));
				glVertex2f(x, y);
				if(inputs && x >= currentpos)
				{
					inputx[i] = x;
					inputy[i] = y;
					++i;
					currentpos += spacing;
				}
			}
			x -= CIRCLE_STEP;
			while(x >= 0.0-width/2)
			{
				y = 0.0-sqrt(fabs(pow(height/2.0,2) - (pow(height/2.0,2)*pow(x, 2))/pow(width/2.0, 2)));
				glVertex2f(x+xpos, y+ypos);
				x -= CIRCLE_STEP;
			}
				
		glEnd();
			
		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
		for(i = 0; i < inputs; ++i)
		{
			ioangle = atan2(inputy[i], inputx[i]);
			hypot = sqrt(pow(inputx[i],2) + pow(inputy[i], 2)) + INPUT_SIZE/2;
			x = hypot * cos(ioangle);
			y = hypot * sin(ioangle);
			ioangle *= (180/PI);
			fprintf(outfile, "oldx: %f, oldy: %f, newx: %f, newy %f, hypot %f, angle %f\n",inputx[i],inputy[i],x,y,hypot, ioangle);
			drawtriangle(x,y,INPUT_SIZE,INPUT_SIZE, 90-ioangle);
		}
		glTranslatef(0.0-width/8.0, 0.0, 0.0);
		break;
	default:
		break;
	}
	if(text)
	{
		glColor3f(TEXT_RED, TEXT_GREEN, TEXT_BLUE);
		glPushAttrib(GL_LIST_BIT);
			glListBase(glyph_base-32);
		glScalef(0.25,0.25,0.25);
		
		glCallLists(strlen(text),GL_UNSIGNED_BYTE, text);
	
		glPopAttrib();
		
	}
}

#define INTX_TO_FLOAT_REL(val)	(((double)val)*SCREEN_WIDTH_REL/640.0)
#define INTY_TO_FLOAT_REL(val)	(((double)val)*SCREEN_HEIGHT_REL/480.0)

//void drawshape(int shape_type, double xpos, double ypos, double width, double height, double angle, int inputs, int outputs)
int DrawGLScene(GLvoid)
{
	double line_startx;
	double line_starty;
	double line_endx;
	double line_endy;
	double m,b,x,y,mousey;
	int i,j;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	for(i = 0; i < num_workers; ++i)
	{
		if(mouse_leftstart_down 
			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos - view_workerlist[i].width/2.0) 
			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0)
			&& INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0) 
			&& INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos + view_workerlist[i].height/2.0))
		{
			view_workerlist[i].grabbed = TRUE;
			selected_worker = i;
			selected_wire = -1;
			mouse_leftstart_down = FALSE;
		}
		else if(mouse_leftstart_down
			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos - view_workerlist[i].width/2.0) //Check for mouse in input or output area
			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0)
			&& (INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0 - OUTPUT_SIZE))
			&& (INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos + view_workerlist[i].height/2.0 + INPUT_SIZE)))
		{
			if(INTY_TO_FLOAT_REL(mouse_cury) > view_workerlist[i].ypos && view_workerlist[i].num_inputs > 0)//is mouse above or below worker (inputs are above, outputs below)?
			{
				fputs("Hit on input region.\n", outfile);
				for(j = 0; j < view_workerlist[i].num_inputs; ++j)
				{
					if(INTX_TO_FLOAT_REL(mouse_curx) > (get_io_xpos(&view_workerlist[i], j, TRUE)-INPUT_SIZE/2.0) && INTX_TO_FLOAT_REL(mouse_curx) < (get_io_xpos(&view_workerlist[i], j, TRUE)+INPUT_SIZE/2.0))
					{
						fprintf(outfile, "Hit on input number %d on worker %d.\n", j, i);
						mouse_leftstart_down = FALSE;
						if(start_wire_worker >= 0)
						{
							fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires,start_wire_ionum, j);
							//Add wire
							view_wirelist[num_wires].start_worker = start_wire_worker;
							view_wirelist[num_wires].end_worker = i;
							view_wirelist[num_wires].output_num = start_wire_ionum;;
							view_wirelist[num_wires].input_num = j;
							++num_wires;
							start_wire_worker = start_wire_ionum = -1;
							
						}
						else
						{
							fputs("Saving information for later wire creation.\n", outfile);
							start_wire_worker = i;
							start_wire_ionum = j;
							start_wire_isinput=TRUE;
						}
						break;
					}
				}
			}
			else if(view_workerlist[i].num_outputs > 0)
			{
				fputs("Hit on output region.\n", outfile);
				for(j = 0; j < view_workerlist[i].num_outputs; ++j)
				{
					fprintf(outfile, "Checking mouse x(%f) for hit on output number %d with position %f\n", INTX_TO_FLOAT_REL(mouse_curx), j, get_io_xpos(&view_workerlist[i], j, FALSE));
					if(INTX_TO_FLOAT_REL(mouse_curx) > (get_io_xpos(&view_workerlist[i], j, FALSE)-OUTPUT_SIZE/2.0) && INTX_TO_FLOAT_REL(mouse_curx) < (get_io_xpos(&view_workerlist[i], j, FALSE)+OUTPUT_SIZE/2.0))
					{
						fprintf(outfile, "Hit on output number %d on worker %d.\n", j, i);
						mouse_leftstart_down = FALSE;
						if(start_wire_worker >= 0)
						{
							fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires, j, start_wire_ionum);
							//Add wire
							view_wirelist[num_wires].start_worker = i;
							view_wirelist[num_wires].end_worker = start_wire_worker;
							view_wirelist[num_wires].output_num = j;
							view_wirelist[num_wires].input_num = start_wire_ionum;
							if(start_wire_ionum == -1)
								view_workerlist[start_wire_worker].null_input = TRUE;
							++num_wires;
							start_wire_worker = start_wire_ionum = -1;
						}
						else
						{
							fputs("Saving information for later wire creation.\n", outfile);
							start_wire_worker = i;
							start_wire_ionum = j;
							start_wire_isinput=FALSE;
						}
						break;
					}
				}
			}
			
		}
		else if(mouse_leftstart_down
			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos + view_workerlist[i].width/2.0) //Check for mouse in input or output area
			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0+INPUT_SIZE)
			&& (INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0))
			&& (INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos - view_workerlist[i].height/2.0 + INPUT_SIZE)))
		{
			fprintf(outfile, "Click on NULL input at %f,%f\n", INTX_TO_FLOAT_REL(mouse_curx), INTY_TO_FLOAT_REL(mouse_cury));
			mouse_leftstart_down = FALSE;
			if(start_wire_worker >= 0)
			{
				fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires,start_wire_ionum, -1);
				//Add wire
				view_wirelist[num_wires].start_worker = start_wire_worker;
				view_wirelist[num_wires].end_worker = i;
				view_wirelist[num_wires].output_num = start_wire_ionum;;
				view_wirelist[num_wires].input_num = -1;
				view_workerlist[i].null_input = TRUE;
				++num_wires;
				start_wire_worker = start_wire_ionum = -1;
				
			}
			else
			{
				fputs("Saving information for later wire creation.\n", outfile);
				start_wire_worker = i;
				start_wire_ionum = -1;
				start_wire_isinput=TRUE;
			}
		}
		else if(mouse_leftstart_down)
		{
			fprintf(outfile, "Click at %f,%f, worker at %f,%f with size %f,%f\n", INTX_TO_FLOAT_REL(mouse_curx), INTY_TO_FLOAT_REL(mouse_cury), view_workerlist[i].xpos, view_workerlist[i].ypos, view_workerlist[i].width, view_workerlist[i].height);
		}
				
		if(!mouse_left_down)
			view_workerlist[i].grabbed= FALSE;
		if(mouse_left_down && view_workerlist[i].grabbed && (mouse_curx != mouse_lastx || mouse_cury != mouse_lasty))
		{
			view_workerlist[i].xpos += INTX_TO_FLOAT_REL(mouse_curx-mouse_lastx);
			view_workerlist[i].ypos += INTY_TO_FLOAT_REL(mouse_cury-mouse_lasty);
		}
		drawshape(view_workerlist[i].display_type, view_workerlist[i].xpos, view_workerlist[i].ypos, view_workerlist[i].width, view_workerlist[i].height, 
			view_workerlist[i].angle, view_workerlist[i].num_inputs, view_workerlist[i].num_outputs, view_workerlist[i].name, selected_worker==i);
	}
	

	glLoadIdentity();
	glTranslatef(SCREEN_WIDTH_REL / (-2.0f), SCREEN_HEIGHT_REL / (-2.0f),-8.0f);

	glColor3f(WIRE_RED, WIRE_GREEN, WIRE_BLUE);
	for(i = 0; i < num_wires; ++i)
	{
		fprintf(outfile, "Wire %d starts in worker %d at output %d of %d and ends in worker %d at input %d of %d\n", i, view_wirelist[i].start_worker,
			view_wirelist[i].output_num, view_workerlist[view_wirelist[i].start_worker].num_outputs, view_wirelist[i].end_worker, view_wirelist[i].input_num, view_workerlist[view_wirelist[i].end_worker].num_inputs);
		line_startx = get_io_xpos(&view_workerlist[view_wirelist[i].start_worker], view_wirelist[i].output_num, FALSE);
		line_starty = get_io_ypos(&view_workerlist[view_wirelist[i].start_worker], view_wirelist[i].output_num, FALSE)-OUTPUT_SIZE;
		line_endx = get_io_xpos(&view_workerlist[view_wirelist[i].end_worker], view_wirelist[i].input_num, TRUE);
		line_endy = get_io_ypos(&view_workerlist[view_wirelist[i].end_worker], view_wirelist[i].input_num, TRUE)+OUTPUT_SIZE;
		
		x = INTX_TO_FLOAT_REL(mouse_curx);
		mousey = INTY_TO_FLOAT_REL(mouse_cury);
		if(mouse_leftstart_down)
		{
			//y = mx=b
			
			if(line_startx < line_endx)
			{
				if(x >= line_startx && x <= line_endx)
				{
					m = (line_endy-line_starty)/(line_endx-line_starty);
					b = line_starty;
					x -= line_startx;
					y = m*x + b;
					fprintf(outfile, "y: %f, m: %f, x: %f, b: %f, mousey: %f\n", y,m,x,b,mousey);
					if(mousey >= (y-0.05) && mousey <= (y+0.05))
					{
						selected_wire = i;
						selected_worker = -1;
					}
				}
			} 
			else if(line_endx > line_startx)
			{
				if(x <= line_startx && x >= line_endx)
				{
					m = (line_starty-line_endy)/(line_startx-line_endy);
					b = line_endy;
					y = m*x + b;
					x -= line_endx;
					if(mousey >= (y-0.05) && mousey <= (y+0.05))
					{
						selected_wire = i;
						selected_worker = -1;
					}
				}
			}
			else	//avoid divide by zero error
			{
				if(x >= (line_startx-0.05) && x <= (line_startx+0.05))
				{
					if(line_starty > line_endy)
					{
						if(mousey >= line_endy && mousey <= line_starty)
						{
							selected_wire = i;
							selected_worker = -1;
						}
					}
					else
					{
						if(mousey <= line_endy && mousey >= line_starty)
						{
							selected_wire = i;
							selected_worker = -1;
						}
					}
				}
			}
		}
		if(i == selected_wire)
			glColor3f(SELECT_RED, SELECT_GREEN, SELECT_BLUE);

		fprintf(outfile, "Start (%f,%f), End (%f, %f), Mouse(%f, %f)\n", line_startx, line_starty, line_endx, line_endy, x, mousey);

		glBegin(GL_QUADS);
			glVertex2f(line_startx, line_starty);
			glVertex2f(line_startx+0.1, line_starty);
			glVertex2f(line_endx+0.1, line_endy);
			glVertex2f(line_endx, line_endy);
		glEnd();
		
		if(i == selected_wire)
			glColor3f(WIRE_RED, WIRE_GREEN, WIRE_BLUE);
	}
	mouse_leftstart_down = FALSE;
	//view_workerlist[3].angle += 1.0;
	checked_mouse_pos=TRUE;

	if(buf_size)
	{
		glColor3f(1.0, 1.0, 1.0);
		glPushAttrib(GL_LIST_BIT);
		glListBase(glyph_base-32);

		glScalef(0.25,0.25,0.25);
		
		glCallLists(buf_size,GL_UNSIGNED_BYTE, new_name_buf);
	
		glPopAttrib();
	}
/*
	if(execute_active)
	{
		for(i = 0; i < num_workers; ++i)
			process_worker(i);
		if(!execute_active)
		{
			for(i = 0; i < num_datum; ++i)
			{
				if(data[i].type & 0x80)
					free(data[i].contents);
			}
		}
	}
*/

	mouse_lastx = mouse_curx;
	mouse_lasty = mouse_cury;

	return TRUE;
}

GLvoid KillGLWindow(GLvoid)
{
	if(fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
		ShowCursor(TRUE);
	}
	if(hRC)
	{
		glDeleteLists(glyph_base, 224);
		if(!wglMakeCurrent(NULL,NULL))
			MessageBox(NULL, "Release of DC and RC failed.","SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

		if(!wglDeleteContext(hRC))
			MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		hRC = NULL;
		if(hDC && !ReleaseDC(hWnd,hDC))
		{
			MessageBox(NULL,"Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
			hDC = NULL;
		}
	}
		
	if(hWnd && !DestroyWindow(hWnd))
	{
		MessageBox(NULL, "Could not Release hWnd", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		hWnd = NULL;
	}
	
	if(!UnregisterClass("OpenGL", hInstance))
	{
		MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;
	}
}

BOOL CreateGLWindow(char * title, int width, int height, int bits, BOOL fullscreenflag)
{
	GLuint	PixelFormat;
	WNDCLASS	wc;
	DWORD		dwExStyle;
	DWORD		dwStyle;
	
	static	PIXELFORMATDESCRIPTOR pfd=					// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),					// Size Of This Pixel Format Descriptor
		1,								// Version Number
		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,						// Must Support Double Buffering
		PFD_TYPE_RGBA,							// Request An RGBA Format
		0,								// Select Our Color Depth
		0, 0, 0, 0, 0, 0,						// Color Bits Ignored
		0,								// No Alpha Buffer
		0,								// Shift Bit Ignored
		0,								// No Accumulation Buffer
		0, 0, 0, 0,							// Accumulation Bits Ignored
		16,								// 16Bit Z-Buffer (Depth Buffer)
		0,								// No Stencil Buffer
		0,								// No Auxiliary Buffer
		PFD_MAIN_PLANE,							// Main Drawing Layer
		0,								// Reserved
		0, 0, 0								// Layer Masks Ignored
	};
	
	RECT	WindowRect;
	WindowRect.left = (long)0;
	WindowRect.right = (long)width;
	WindowRect.top = (long)0;
	WindowRect.bottom=(long)height;
	
	fullscreen = fullscreenflag;

	hInstance		= GetModuleHandle(NULL);			// Grab An Instance For Our Window
	wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// Redraw On Move, And Own DC For Window
	wc.lpfnWndProc		= (WNDPROC) WndProc;				// WndProc Handles Messages
	wc.cbClsExtra		= 0;						// No Extra Window Data
	wc.cbWndExtra		= 0;						// No Extra Window Data
	wc.hInstance		= hInstance;					// Set The Instance
	wc.hIcon		= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;						// No Background Required For GL
	wc.lpszMenuName		= NULL;						// We Don't Want A Menu
	wc.lpszClassName	= "OpenGL";					// Set The Class Name

	if (!RegisterClass(&wc))						// Attempt To Register The Window Class
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Exit And Return FALSE
	}

	if (fullscreen)								// Attempt Fullscreen Mode?
	{
		DEVMODE dmScreenSettings;					// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));		// Makes Sure Memory's Cleared
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= width;			// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= height;			// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= bits;				// Selected Bits Per Pixel
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{

			// If The Mode Fails, Offer Two Options.  Quit Or Run In A Window.
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;				// Select Windowed Mode (Fullscreen=FALSE)
			}
			else
			{

				// Pop Up A Message Box Letting User Know The Program Is Closing.
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;					// Exit And Return FALSE
			}
		}
	}
	if (fullscreen)								// Are We Still In Fullscreen Mode?
	{
		dwExStyle=WS_EX_APPWINDOW;					// Window Extended Style
		dwStyle=WS_POPUP;						// Windows Style
		ShowCursor(FALSE);						// Hide Mouse Pointer
	}
	else
	{

		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
		dwStyle=WS_OVERLAPPEDWINDOW;					// Windows Style
	}
	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size
	if (!(hWnd=CreateWindowEx(	dwExStyle,				// Extended Style For The Window
					"OpenGL",				// Class Name
					title,					// Window Title
					WS_CLIPSIBLINGS |			// Required Window Style
					WS_CLIPCHILDREN |			// Required Window Style
					dwStyle,				// Selected Window Style
					0, 0,					// Window Position
					WindowRect.right-WindowRect.left,	// Calculate Adjusted Window Width
					WindowRect.bottom-WindowRect.top,	// Calculate Adjusted Window Height
					NULL,					// No Parent Window
					NULL,					// No Menu
					hInstance,				// Instance
					NULL)))					// Don't Pass Anything To WM_CREATE
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	
	pfd.cColorBits = bits;
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))				// Did Windows Find A Matching Pixel Format?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	if(!SetPixelFormat(hDC,PixelFormat,&pfd))				// Are We Able To Set The Pixel Format?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	if (!(hRC=wglCreateContext(hDC)))					// Are We Able To Get A Rendering Context?
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	if(!wglMakeCurrent(hDC,hRC))						// Try To Activate The Rendering Context
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	ShowWindow(hWnd,SW_SHOW);						// Show The Window
	SetForegroundWindow(hWnd);						// Slightly Higher Priority
	SetFocus(hWnd);								// Sets Keyboard Focus To The Window
	ReSizeGLScene(width, height);						// Set Up Our Perspective GL Screen
	if (!InitGL())								// Initialize Our Newly Created GL Window
	{
		KillGLWindow();							// Reset The Display
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							// Return FALSE
	}
	return TRUE;								// Success
}

LRESULT CALLBACK WndProc(	HWND	hWnd,					// Handle For This Window
				UINT	uMsg,					// Message For This Window
				WPARAM	wParam,					// Additional Message Information
				LPARAM	lParam)					// Additional Message Information
{
	int i;
	worker_def * def;
	FILE * loadfile;
	char * code;
	int size;
	switch (uMsg)								// Check For Windows Messages
	{

		case WM_ACTIVATE:						// Watch For Window Activate Message
		{
			if (!HIWORD(wParam))					// Check Minimization State
			{
				active=TRUE;					// Program Is Active
			}
			else
			{
				active=FALSE;					// Program Is No Longer Active
			}

			return 0;						// Return To The Message Loop
		}
		case WM_SYSCOMMAND:						// Intercept System Commands
		{
			switch (wParam)						// Check System Calls
			{
				case SC_SCREENSAVE:				// Screensaver Trying To Start?
				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
				return 0;					// Prevent From Happening
			}
			break;							// Exit
		}
		case WM_CLOSE:							// Did We Receive A Close Message?
		{
			PostQuitMessage(0);					// Send A Quit Message
			return 0;						// Jump Back
		}
		case WM_KEYDOWN:						// Is A Key Being Held Down?
		{
			if(wParam == VK_BACK && buf_size > 0)
				--buf_size;
			else if(wParam == VK_F5 && !execute_active)
			{
				deflist[current_def].implement_func->num_workers = num_workers;
				deflist[current_def].implement_func->num_wires = num_wires;
				fprintf(outfile, "Starting execution.\n");
				interp_start(-1,FALSE,0,NULL);
			}
			else if(wParam == VK_RETURN && buf_size > 0)
			{
				text_buf_size = buf_size;
				memcpy(text_buf, new_name_buf, buf_size);
				buf_size = 0;
				if(memcmp(text_buf, "Save:", strlen("Save:")) == 0)
				{
					text_buf[text_buf_size]='\0';
					deflist[current_def].implement_func->num_workers = num_workers;
					deflist[current_def].implement_func->num_wires = num_wires;
					save_program(text_buf + strlen("Save:"));
					text_buf_size = 0;
				}
				else if(memcmp(text_buf, "Load:", strlen("Load:")) == 0)
				{
					text_buf[text_buf_size]='\0';
					load_program(text_buf + strlen("Load:"));
					view_workerlist = deflist[0].implement_func->workerlist;
					view_wirelist = deflist[0].implement_func->wirelist;
					num_workers = deflist[0].implement_func->num_workers;
					num_wires = deflist[0].implement_func->num_wires;
					text_buf_size = 0;
				}
				else if (memcmp(text_buf, "View:", strlen("View:")) == 0)
				{
					text_buf[text_buf_size]='\0';
					deflist[current_def].implement_func->num_workers = num_workers;
					deflist[current_def].implement_func->num_wires = num_wires;
					i = find_worker(text_buf+strlen("View:"), NULL, NULL);
					if(i < 0)
						current_def = create_worker(text_buf+strlen("View:"), 0, 0, USER_FLAG | WORKER_TYPE) - deflist;
					else
						current_def = i;
					num_workers = deflist[current_def].implement_func->num_workers;
					num_wires = deflist[current_def].implement_func->num_wires;
					view_workerlist = deflist[current_def].implement_func->workerlist;
					view_wirelist = deflist[current_def].implement_func->wirelist;
					text_buf_size = 0;
					selected_worker = -1;
				}
				else if(memcmp(text_buf, "Import:", strlen("Import:")) == 0)
				{
					deflist[current_def].implement_func->num_workers = num_workers;
					deflist[current_def].implement_func->num_wires = num_wires;
					text_buf[text_buf_size]='\0';
					loadfile = fopen(text_buf+strlen("Import:"), "rb");
					fseek(loadfile, 0, SEEK_END);
					size = ftell(loadfile);
					fseek(loadfile, 0, SEEK_SET);
					code = malloc(size+1);
					fread(code, 1, size, loadfile);
					parse(code, size);
				}
			}
			else if(wParam == VK_DELETE)
			{
				if(selected_worker != -1)
				{
					for(i = 0; i < num_wires; ++i)
					{
						if(view_wirelist[i].start_worker == selected_worker || view_wirelist[i].end_worker == selected_worker)
						{
							view_wirelist[i] = view_wirelist[num_wires-1];
							--num_wires;
							--i;
						}
						
					}
					view_workerlist[selected_worker] = view_workerlist[num_workers-1];
					for(i = 0; i < num_wires; ++i)
					{
						if(view_wirelist[i].start_worker == num_workers-1)
							view_wirelist[i].start_worker = selected_worker;
						if(view_wirelist[i].end_worker == num_workers-1)
							view_wirelist[i].end_worker = selected_worker;
					}
					--num_workers;
					selected_worker = -1;
						
				}
			}


			keys[wParam] = TRUE;					// If So, Mark It As TRUE
			return 0;						// Jump Back
		}
		case WM_KEYUP:							// Has A Key Been Released?
		{
			keys[wParam] = FALSE;					// If So, Mark It As FALSE
			return 0;						// Jump Back
		}
		case WM_SIZE:							// Resize The OpenGL Window
		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));		// LoWord=Width, HiWord=Height
			return 0;						// Jump Back
		}
		case WM_RBUTTONDOWN:
		{
			view_workerlist[num_workers].xpos = INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam));
			view_workerlist[num_workers].ypos = INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam));
			
			view_workerlist[num_workers].height = 0.25;
			view_workerlist[num_workers].grabbed=FALSE;
			if(buf_size > strlen("Data:") && memcmp("Data:", new_name_buf, strlen("Data:")) == 0)
			{
				
				view_workerlist[num_workers].display_type=1;//Rectangle
				view_workerlist[num_workers].type=0;//Constant
				view_workerlist[num_workers].num_inputs=0;//Constants don't have inputs
				view_workerlist[num_workers].num_outputs=1;//Constants have one output
				view_workerlist[num_workers].null_input = FALSE;
				memcpy(view_workerlist[num_workers].name, new_name_buf+strlen("Data:"), buf_size-strlen("Data:"));
				view_workerlist[num_workers].name[buf_size-strlen("Data:")]='\0';
				view_workerlist[num_workers].width = ((double)(buf_size-strlen("Data:"))+0.5) * INPUT_SIZE;
				++num_workers;
				buf_size = 0;
			}
			else if(buf_size > strlen("Room:") && memcmp("Room:", new_name_buf, strlen("Room:")) == 0)
			{
				view_workerlist[num_workers].type=1;//Room
				view_workerlist[num_workers].display_type=1;//Rectangle
				view_workerlist[num_workers].num_inputs=1;
				view_workerlist[num_workers].num_outputs=1;
				view_workerlist[num_workers].null_input = FALSE;
				memcpy(view_workerlist[num_workers].name, new_name_buf+strlen("Room:"), buf_size-strlen("Room:"));
				view_workerlist[num_workers].name[buf_size-strlen("Room:")]='\0';
				view_workerlist[num_workers].width = ((double)(buf_size-strlen("Room:"))+0.5) * INPUT_SIZE;
				++num_workers;
				buf_size = 0;
			}
			else if(buf_size > strlen("Input:") && memcmp("Input:", new_name_buf, strlen("Input:")) == 0)
			{
				deflist[current_def].implement_func->num_workers = num_workers;
				new_name_buf[buf_size] = '\0';
				MessageBox(NULL, new_name_buf,"Error",MB_OK);
				add_input(deflist+current_def, new_name_buf + strlen("Input:"), INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
				num_workers = deflist[current_def].implement_func->num_workers;
			}
			else if(buf_size > strlen("Output:") && memcmp("Output:", new_name_buf, strlen("Output:")) == 0)
			{
				deflist[current_def].implement_func->num_workers = num_workers;
				new_name_buf[buf_size] = '\0';
				add_output(deflist+current_def, new_name_buf + strlen("Output:"), INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
				num_workers = deflist[current_def].implement_func->num_workers;
			}
			else if(buf_size > strlen("Express:") && memcmp("Express:", new_name_buf, strlen("Express:")) == 0)
			{
				deflist[current_def].implement_func->num_workers = num_workers;
				new_name_buf[buf_size] = '\0';
				def = create_worker(new_name_buf+strlen("Express:"), 0, 0, USER_FLAG | WORKER_TYPE);
				parse_body(def, new_name_buf+strlen("Express:"), buf_size-strlen("Express:"));
				add_worker_to_def(deflist+current_def, def-deflist, INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
				num_workers = deflist[current_def].implement_func->num_workers;
				buf_size = 0;
			}
			else
			{
				memcpy(view_workerlist[num_workers].name, new_name_buf, buf_size);
				view_workerlist[num_workers].name[buf_size] = '\0';
				for(i = 0; i < num_defs; ++i)
				{
					fprintf(outfile, "Comparing %s with %s(%d)\n", view_workerlist[num_workers].name, deflist[i].name, i);
					if(strcmp(view_workerlist[num_workers].name, deflist[i].name)==0)
					{
						view_workerlist[num_workers].display_type=2;//Trapezoid
						view_workerlist[num_workers].type=2;//Worker
						view_workerlist[num_workers].num_inputs=deflist[i].num_inputs;
						view_workerlist[num_workers].num_outputs=deflist[i].num_outputs;
						view_workerlist[num_workers].null_input = FALSE;
						view_workerlist[num_workers].value_index = i;
						view_workerlist[num_workers].width = ((double)buf_size+0.5) * INPUT_SIZE;
						
						++num_workers;
						buf_size = 0;
						break;
					}
				}
				if(i >= num_defs)
				{
					strcpy(new_name_buf, "I don't know a worker with that name.");
					buf_size = strlen(new_name_buf);
				}
			}
			if(view_workerlist[num_workers-1].width <= (double)view_workerlist[num_workers-1].num_outputs * OUTPUT_SIZE)
				view_workerlist[num_workers-1].width = (double)view_workerlist[num_workers-1].num_outputs * (OUTPUT_SIZE*1.1);
			if(view_workerlist[num_workers-1].width <= (double)view_workerlist[num_workers-1].num_inputs * INPUT_SIZE)
				view_workerlist[num_workers-1].width = (double)view_workerlist[num_workers-1].num_inputs * (INPUT_SIZE*1.1);
			
			
			break;
		}

		case WM_LBUTTONDOWN:
		{
			mouse_leftstart_down=mouse_left_down=TRUE;
			mouse_lastx = mouse_curx = GET_X_LPARAM(lParam);
			mouse_lasty = mouse_cury = 480-GET_Y_LPARAM(lParam);
			checked_mouse_pos=FALSE;
			return 0;
		}
		case WM_LBUTTONUP:
		{
			mouse_leftstart_down=mouse_left_down=FALSE;
			return 0;
		}
		case WM_MOUSEMOVE:
		{
			//If no one has checked the mouse position vars, this could cause bugs
			if(checked_mouse_pos)
			{
				mouse_lastx = mouse_curx;
				mouse_lasty = mouse_cury;
			}
			mouse_curx = GET_X_LPARAM(lParam);
			mouse_cury = 480-GET_Y_LPARAM(lParam);
			checked_mouse_pos=FALSE;
			return 0;
		}
		case WM_CHAR:
		{
			if(wParam >= 0x20)
			{
				new_name_buf[buf_size++]=wParam&0xFF;
			}
			return 0;
		}
			
	}
	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

VOID CALLBACK DoFrame(HWND myhWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
	if(active)
	{
		DrawGLScene();				// Draw The Scene
		SwapBuffers(hDC);			// Swap Buffers (Double Buffering)
	}
}

int WINAPI WinMain(	HINSTANCE	hInstance,				// Instance
			HINSTANCE	hPrevInstance,				// Previous Instance
			LPSTR		lpCmdLine,				// Command Line Parameters
			int		nCmdShow)				// Window Show State
{
	MSG	msg;								// Windows Message Structure
	BOOL	done=FALSE;							// Bool Variable To Exit Loop
	// Ask The User Which Screen Mode They Prefer
	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
		fullscreen=FALSE;						// Windowed Mode
	}
	// Create Our OpenGL Window
	if (!CreateGLWindow("Visuality",640,480,16,fullscreen))
	{
		return 0;							// Quit If Window Was Not Created
	}

	initworkers();
	view_workerlist = deflist[0].implement_func->workerlist;
	view_wirelist = deflist[0].implement_func->wirelist;
	
	
	outfile = fopen("output.txt", "w");
	
	SetTimer(hWnd, 1, 17, DoFrame);

	
	while(!done)								// Loop That Runs Until done=TRUE
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))			// Is There A Message Waiting?
		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
			{
				done=TRUE;					// If So done=TRUE
			}
			else							// If Not, Deal With Window Messages
			{
				TranslateMessage(&msg);				// Translate The Message
				DispatchMessage(&msg);				// Dispatch The Message
			}
		}
		// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
		if (active)						// Program Active?
		{
			if (keys[VK_ESCAPE])				// Was ESC Pressed?
			{
				done=TRUE;				// ESC Signalled A Quit
			}
			else						// Not Time To Quit, Update Screen
			{

				
			}
			
			if (keys[VK_F1])					// Is F1 Being Pressed?
			{
				keys[VK_F1]=FALSE;				// If So Make Key FALSE
				KillTimer(hWnd, 1);
				KillGLWindow();					// Kill Our Current Window
				fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode
				// Recreate Our OpenGL Window
				if (!CreateGLWindow("Rini's Love Quest",640,480,16,fullscreen))
				{
					return 0;				// Quit If Window Was Not Created
				}
				SetTimer(hWnd, 1, 17, DoFrame);
			}
		}
		Sleep(0);
	}
	KillTimer(hWnd, 1);

	// Shutdown
	KillGLWindow();								// Kill The Window
	return (msg.wParam);							// Exit The Program
}