view visuality.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -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
}