#include <math.h>
#include <SDL/SDL.h>
#include <bzlib.h>

#if defined(OGLR)
#ifdef MACOSX
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
#endif

#include <defines.h>
#include <air.h>
#include <powder.h>
#include <graphics.h>
#include <powdergraphics.h>
#define INCLUDE_FONTDATA
#include <font.h>
#include <misc.h>


unsigned cmode = CM_FIRE;
SDL_Surface *sdl_scrn;
int sdl_scale = 1;

int sandcolour_r = 0;
int sandcolour_g = 0;
int sandcolour_b = 0;
int sandcolour_frame = 0;

unsigned char fire_r[YRES/CELL][XRES/CELL];
unsigned char fire_g[YRES/CELL][XRES/CELL];
unsigned char fire_b[YRES/CELL][XRES/CELL];

unsigned int fire_alpha[CELL*3][CELL*3];
pixel *fire_bg;
pixel *pers_bg;

void *ptif_pack(pixel *src, int w, int h, int *result_size){
	int i = 0, datalen = (w*h)*3, cx = 0, cy = 0;
	unsigned char *red_chan = calloc(1, w*h); 
	unsigned char *green_chan = calloc(1, w*h); 
	unsigned char *blue_chan = calloc(1, w*h); 
	unsigned char *data = malloc(((w*h)*3)+8);
	unsigned char *result = malloc(((w*h)*3)+8);
	
	for(cx = 0; cx<w; cx++){
		for(cy = 0; cy<h; cy++){
			red_chan[w*(cy)+(cx)] = PIXR(src[w*(cy)+(cx)]);
			green_chan[w*(cy)+(cx)] = PIXG(src[w*(cy)+(cx)]);
			blue_chan[w*(cy)+(cx)] = PIXB(src[w*(cy)+(cx)]);
		}
	}
	
	memcpy(data, red_chan, w*h);
	memcpy(data+(w*h), green_chan, w*h);
	memcpy(data+((w*h)*2), blue_chan, w*h);
	free(red_chan);
	free(green_chan);
	free(blue_chan);
	
	result[0] = 'P';
	result[1] = 'T';
	result[2] = 'i';
	result[3] = 1;
	result[4] = w;
	result[5] = w>>8;
	result[6] = h;
	result[7] = h>>8;
	
	i -= 8;
	
	if(BZ2_bzBuffToBuffCompress((char *)(result+8), (unsigned *)&i, (char *)data, datalen, 9, 0, 0) != BZ_OK){
		free(data);
		free(result);
		return NULL;
	}
	
	*result_size = i+8;
	free(data);
	return result;
}

pixel *ptif_unpack(void *datain, int size, int *w, int *h){
	int width, height, i, cx, cy, resCode;
	unsigned char *red_chan;
	unsigned char *green_chan;
	unsigned char *blue_chan;
	unsigned char *data = datain;
	unsigned char *undata;
	pixel *result;
	if(size<16){
		printf("Image empty\n");
		return NULL;
	}
	if(!(data[0]=='P' && data[1]=='T' && data[2]=='i')){
		printf("Image header invalid\n");
		return NULL;
	}
	width = data[4]|(data[5]<<8);
	height = data[6]|(data[7]<<8);
	
	i = (width*height)*3;
	undata = calloc(1, (width*height)*3);
	red_chan = calloc(1, width*height); 
	green_chan = calloc(1, width*height); 
	blue_chan = calloc(1, width*height); 
	result = calloc(width*height, PIXELSIZE);
	
	resCode = BZ2_bzBuffToBuffDecompress((char *)undata, (unsigned *)&i, (char *)(data+8), size-8, 0, 0);
	if (resCode){
		printf("Decompression failure, %d\n", resCode);
		free(red_chan);
		free(green_chan);
		free(blue_chan);
		free(undata);
		free(result);
		return NULL;
	}
	if(i != (width*height)*3){
		printf("Result buffer size mismatch, %d != %d\n", i, (width*height)*3);
		free(red_chan);
		free(green_chan);
		free(blue_chan);
		free(undata);
		free(result);
		return NULL;
	}
	memcpy(red_chan, undata, width*height);
	memcpy(green_chan, undata+(width*height), width*height);
	memcpy(blue_chan, undata+((width*height)*2), width*height);
	
	for(cx = 0; cx<width; cx++){
		for(cy = 0; cy<height; cy++){
			result[width*(cy)+(cx)] = PIXRGB(red_chan[width*(cy)+(cx)], green_chan[width*(cy)+(cx)], blue_chan[width*(cy)+(cx)]);
		}
	}
	
	*w = width;
	*h = height;
	free(red_chan);
	free(green_chan);
	free(blue_chan);
	free(undata);
	return result;
}

pixel *resample_img_nn(pixel * src, int sw, int sh, int rw, int rh)
{
	int y, x;
	pixel *q = NULL;
	q = malloc(rw*rh*PIXELSIZE);
	for (y=0; y<rh; y++)
		for (x=0; x<rw; x++){
			q[rw*y+x] = src[sw*(y*sh/rh)+(x*sw/rw)];
		}
	return q;
}

pixel *resample_img(pixel *src, int sw, int sh, int rw, int rh)
{
	int y, x, fxceil, fyceil;
	//int i,j,x,y,w,h,r,g,b,c;
	pixel *q = NULL;
	//TODO: Actual resampling, this is just cheap nearest pixel crap
	if(rw == sw && rh == sh){
		//Don't resample
		q = malloc(rw*rh*PIXELSIZE);
		memcpy(q, src, rw*rh*PIXELSIZE);
	} else if(rw > sw && rh > sh){
		float fx, fy, fyc, fxc;
		double intp;
		pixel tr, tl, br, bl;
		q = malloc(rw*rh*PIXELSIZE);
		//Bilinear interpolation for upscaling
		for (y=0; y<rh; y++)
			for (x=0; x<rw; x++)
			{
				fx = ((float)x)*((float)sw)/((float)rw);
				fy = ((float)y)*((float)sh)/((float)rh);
				fxc = modf(fx, &intp);
				fyc = modf(fy, &intp);
				fxceil = (int)ceil(fx);
				fyceil = (int)ceil(fy);
				if (fxceil>=sw) fxceil = sw-1;
				if (fyceil>=sh) fyceil = sh-1;
				tr = src[sw*(int)floor(fy)+fxceil];
				tl = src[sw*(int)floor(fy)+(int)floor(fx)];
				br = src[sw*fyceil+fxceil];
				bl = src[sw*fyceil+(int)floor(fx)];
				q[rw*y+x] = PIXRGB(
					(int)(((((float)PIXR(tl))*(1.0f-fxc))+(((float)PIXR(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXR(bl))*(1.0f-fxc))+(((float)PIXR(br))*(fxc)))*(fyc)),
					(int)(((((float)PIXG(tl))*(1.0f-fxc))+(((float)PIXG(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXG(bl))*(1.0f-fxc))+(((float)PIXG(br))*(fxc)))*(fyc)),
					(int)(((((float)PIXB(tl))*(1.0f-fxc))+(((float)PIXB(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXB(bl))*(1.0f-fxc))+(((float)PIXB(br))*(fxc)))*(fyc))
					);				
			}
	} else {
		//Stairstepping
		float fx, fy, fyc, fxc;
		double intp;
		pixel tr, tl, br, bl;
		int rrw = rw, rrh = rh;
		pixel * oq;
		oq = malloc(sw*sh*PIXELSIZE);
		memcpy(oq, src, sw*sh*PIXELSIZE);
		rw = sw;
		rh = sh;
		while(rrw != rw && rrh != rh){
			rw *= 0.7;
			rh *= 0.7;
			if(rw <= rrw || rh <= rrh){
				rw = rrw;
				rh = rrh;
			}
			q = malloc(rw*rh*PIXELSIZE);
			//Bilinear interpolation for upscaling
			for (y=0; y<rh; y++)
				for (x=0; x<rw; x++)
				{
					fx = ((float)x)*((float)sw)/((float)rw);
					fy = ((float)y)*((float)sh)/((float)rh);
					fxc = modf(fx, &intp);
					fyc = modf(fy, &intp);
					fxceil = (int)ceil(fx);
					fyceil = (int)ceil(fy);
					if (fxceil>=sw) fxceil = sw-1;
					if (fyceil>=sh) fyceil = sh-1;
					tr = oq[sw*(int)floor(fy)+fxceil];
					tl = oq[sw*(int)floor(fy)+(int)floor(fx)];
					br = oq[sw*fyceil+fxceil];
					bl = oq[sw*fyceil+(int)floor(fx)];
					q[rw*y+x] = PIXRGB(
						(int)(((((float)PIXR(tl))*(1.0f-fxc))+(((float)PIXR(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXR(bl))*(1.0f-fxc))+(((float)PIXR(br))*(fxc)))*(fyc)),
						(int)(((((float)PIXG(tl))*(1.0f-fxc))+(((float)PIXG(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXG(bl))*(1.0f-fxc))+(((float)PIXG(br))*(fxc)))*(fyc)),
						(int)(((((float)PIXB(tl))*(1.0f-fxc))+(((float)PIXB(tr))*(fxc)))*(1.0f-fyc) + ((((float)PIXB(bl))*(1.0f-fxc))+(((float)PIXB(br))*(fxc)))*(fyc))
						);				
				}
			free(oq);
			oq = q;
			sw = rw;
			sh = rh;
		}
	}
	return q;
}

pixel *rescale_img(pixel *src, int sw, int sh, int *qw, int *qh, int f)
{
	int i,j,x,y,w,h,r,g,b,c;
	pixel p, *q;
	w = (sw+f-1)/f;
	h = (sh+f-1)/f;
	q = malloc(w*h*PIXELSIZE);
	for (y=0; y<h; y++)
		for (x=0; x<w; x++)
		{
			r = g = b = c = 0;
			for (j=0; j<f; j++)
				for (i=0; i<f; i++)
					if (x*f+i<sw && y*f+j<sh)
					{
						p = src[(y*f+j)*sw + (x*f+i)];
						if (p)
						{
							r += PIXR(p);
							g += PIXG(p);
							b += PIXB(p);
							c ++;
						}
					}
			if (c>1)
			{
				r = (r+c/2)/c;
				g = (g+c/2)/c;
				b = (b+c/2)/c;
			}
			q[y*w+x] = PIXRGB(r, g, b);
		}
	*qw = w;
	*qh = h;
	return q;
}

#ifdef OGLR
void ogl_blit(int x, int y, int w, int h, pixel *src, int pitch, int scale)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0 ,XRES*scale, 0, YRES*scale, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();


	glRasterPos2i(0, YRES*scale);
	glPixelZoom(scale, -scale);

	glDrawPixels(w,h,GL_RGBA,GL_UNSIGNED_BYTE,src);

	glPopMatrix();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);


	SDL_GL_SwapBuffers ();
}
#endif

void sdl_blit_1(int x, int y, int w, int h, pixel *src, int pitch)
{
	pixel *dst;
	int j;
	if (SDL_MUSTLOCK(sdl_scrn))
		if (SDL_LockSurface(sdl_scrn)<0)
			return;
	dst=(pixel *)sdl_scrn->pixels+y*sdl_scrn->pitch/PIXELSIZE+x;
	if (SDL_MapRGB(sdl_scrn->format,0x33,0x55,0x77)!=PIXPACK(0x335577))
	{
		//pixel format conversion
		int i;
		pixel px;
		SDL_PixelFormat *fmt = sdl_scrn->format;
		for (j=0; j<h; j++)
		{
			for (i=0; i<w; i++)
			{
				px = src[i];
				dst[i] = ((PIXR(px)>>fmt->Rloss)<<fmt->Rshift)|
						((PIXG(px)>>fmt->Gloss)<<fmt->Gshift)|
						((PIXB(px)>>fmt->Bloss)<<fmt->Bshift);
			}
			dst+=sdl_scrn->pitch/PIXELSIZE;
			src+=pitch;
		}
	}
	else
	{
		for (j=0; j<h; j++)
		{
			memcpy(dst, src, w*PIXELSIZE);
			dst+=sdl_scrn->pitch/PIXELSIZE;
			src+=pitch;
		}
	}
	if (SDL_MUSTLOCK(sdl_scrn))
		SDL_UnlockSurface(sdl_scrn);
	SDL_UpdateRect(sdl_scrn,0,0,0,0);
}

void sdl_blit_2(int x, int y, int w, int h, pixel *src, int pitch)
{
	pixel *dst;
	int j;
	int i,k;
	if (SDL_MUSTLOCK(sdl_scrn))
		if (SDL_LockSurface(sdl_scrn)<0)
			return;
	dst=(pixel *)sdl_scrn->pixels+y*sdl_scrn->pitch/PIXELSIZE+x;
	if (SDL_MapRGB(sdl_scrn->format,0x33,0x55,0x77)!=PIXPACK(0x335577))
	{
		//pixel format conversion
		pixel px;
		SDL_PixelFormat *fmt = sdl_scrn->format;
		for (j=0; j<h; j++)
		{
			for (k=0; k<sdl_scale; k++)
			{
				for (i=0; i<w; i++)
				{
					px = src[i];
					px = ((PIXR(px)>>fmt->Rloss)<<fmt->Rshift)|
						((PIXG(px)>>fmt->Gloss)<<fmt->Gshift)|
						((PIXB(px)>>fmt->Bloss)<<fmt->Bshift);
					dst[i*2]=px;
					dst[i*2+1]=px;
				}
				dst+=sdl_scrn->pitch/PIXELSIZE;
			}
			src+=pitch;
		}
	}
	else
	{
		for (j=0; j<h; j++)
		{
			for (k=0; k<sdl_scale; k++)
			{
				for (i=0; i<w; i++)
				{
					dst[i*2]=src[i];
					dst[i*2+1]=src[i];
				}
				dst+=sdl_scrn->pitch/PIXELSIZE;
			}
			src+=pitch;
		}
	}
	if (SDL_MUSTLOCK(sdl_scrn))
		SDL_UnlockSurface(sdl_scrn);
	SDL_UpdateRect(sdl_scrn,0,0,0,0);
}

void sdl_blit(int x, int y, int w, int h, pixel *src, int pitch)
{
#if defined(OGLR)
	ogl_blit(x, y, w, h, src, pitch, sdl_scale);
#else
	if (sdl_scale == 2)
		sdl_blit_2(x, y, w, h, src, pitch);
	else
		sdl_blit_1(x, y, w, h, src, pitch);
#endif
}

//an easy way to draw a blob
void drawblob(pixel *vid, int x, int y, unsigned char cr, unsigned char cg, unsigned char cb)
{
	blendpixel(vid, x+1, y, cr, cg, cb, 112);
	blendpixel(vid, x-1, y, cr, cg, cb, 112);
	blendpixel(vid, x, y+1, cr, cg, cb, 112);
	blendpixel(vid, x, y-1, cr, cg, cb, 112);

	blendpixel(vid, x+1, y-1, cr, cg, cb, 64);
	blendpixel(vid, x-1, y-1, cr, cg, cb, 64);
	blendpixel(vid, x+1, y+1, cr, cg, cb, 64);
	blendpixel(vid, x-1, y+1, cr, cg, cb, 64);
}

//draws walls and elements for menu
int draw_tool_xy(pixel *vid_buf, int x, int y, int b, unsigned pc)
{
	int i, j, c;
	pixel gc;
	if (x > XRES-26 || x < 0)
		return 26;
	if ((b&0xFF) == PT_LIFE)
	{
		for (j=1; j<15; j++)
		{
			for (i=1; i<27; i++)
			{
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
			}
		}
		c = PIXB(pc) + 3*PIXG(pc) + 2*PIXR(pc);
		if (c<544)
		{
			c = 255;
		}
		else
		{
			c = 0;
		}
		drawtext(vid_buf, x+14-textwidth((char *)gmenu[(b>>8)&0xFF].name)/2, y+4, (char *)gmenu[(b>>8)&0xFF].name, c, c, c, 255);
	}
	else if (b>=UI_WALLSTART)
	{
		int ds = 0;
		if (b-UI_WALLSTART>=0 && b-UI_WALLSTART<UI_WALLCOUNT)
		{
			ds = wtypes[b-UI_WALLSTART].drawstyle;
			gc = wtypes[b-UI_WALLSTART].eglow;
		}
		//x = (2+32*((b-22)/1));
		//y = YRES+2+40;
		if (ds==1)
		{
			for (j=1; j<15; j+=2)
				for (i=1+(1&(j>>1)); i<27; i+=2)
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
		}
		else if (ds==2)
		{
			for (j=1; j<15; j+=2)
				for (i=1; i<27; i+=2)
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
		}
		else if (ds==3)
		{
			for (j=1; j<15; j++)
				for (i=1; i<27; i++)
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
		}
		else if (ds==4)
		{
			for (j=1; j<15; j++)
				for (i=1; i<27; i++)
					if(i%CELL == j%CELL)
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
					else if  (i%CELL == (j%CELL)+1 || (i%CELL == 0 && j%CELL == CELL-1))
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = gc;
					else 
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = PIXPACK(0x202020);
		}
		else
		switch (b)
		{
		case WL_WALLELEC+100:
			for (j=1; j<15; j++)
			{
				for (i=1; i<27; i++)
				{
					if (!(i%2) && !(j%2))
					{
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
					}
					else
					{
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = PIXPACK(0x808080);
					}
				}
			}
			break;
		case WL_EWALL+100:
			for (j=1; j<15; j++)
			{
				for (i=1; i<6+j; i++)
				{
					if (!(i&j&1))
					{
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
					}
				}
				for (; i<27; i++)
				{
					if (i&j&1)
					{
						vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
					}
				}
			}
			break;
		case WL_STREAM+100:
			for (j=1; j<15; j++)
			{
				for (i=1; i<27; i++)
				{
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = i==1||i==26||j==1||j==14 ? PIXPACK(0xA0A0A0) : PIXPACK(0x000000);
					drawtext(vid_buf, x+4, y+3, "\x8D", 255, 255, 255, 255);
				}
			}
			for (i=9; i<27; i++)
			{
				drawpixel(vid_buf, x+i, y+8+(int)(3.9f*cos(i*0.3f)), 255, 255, 255, 255);
			}
			break;
		case WL_SIGN+100:
			for (j=1; j<15; j++)
			{
				for (i=1; i<27; i++)
				{
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = i==1||i==26||j==1||j==14 ? PIXPACK(0xA0A0A0) : PIXPACK(0x000000);
				}
			}
			drawtext(vid_buf, x+9, y+3, "\xA1", 32, 64, 128, 255);
			drawtext(vid_buf, x+9, y+3, "\xA0", 255, 255, 255, 255);
			break;
		case WL_ERASE+100:
			for (j=1; j<15; j+=2)
			{
				for (i=1+(1&(j>>1)); i<13; i+=2)
				{
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
				}
			}
			for (j=1; j<15; j++)
			{
				for (i=14; i<27; i++)
				{
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
				}
			}
			break;
		case SPC_AIR:
		case SPC_HEAT:
		case SPC_COOL:
		case SPC_VACUUM:
		case SPC_WIND:
		case SPC_PGRV:
		case SPC_NGRV:
		case SPC_PROP:
			for (j=1; j<15; j++)
				for (i=1; i<27; i++)
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
			c = PIXR(pc) + 3*PIXG(pc) + 2*PIXB(pc);
			if (c<544)
			{
				c = 255;
			}
			else
			{
				c = 0;
			}
			if (b==SPC_AIR)
				drawtext(vid_buf, x+14-textwidth("AIR")/2, y+4, "AIR", c, c, c, 255);
			else if (b==SPC_HEAT)
				drawtext(vid_buf, x+14-textwidth("HEAT")/2, y+4, "HEAT", c, c, c, 255);
			else if (b==SPC_COOL)
				drawtext(vid_buf, x+14-textwidth("COOL")/2, y+4, "COOL", c, c, c, 255);
			else if (b==SPC_VACUUM)
				drawtext(vid_buf, x+14-textwidth("VAC")/2, y+4, "VAC", c, c, c, 255);
			else if (b==SPC_WIND)
				drawtext(vid_buf, x+14-textwidth("WIND")/2, y+4, "WIND", c, c, c, 255);
			else if (b==SPC_PGRV)
				drawtext(vid_buf, x+14-textwidth("PGRV")/2, y+4, "PGRV", c, c, c, 255);
			else if (b==SPC_NGRV)
				drawtext(vid_buf, x+14-textwidth("NGRV")/2, y+4, "NGRV", c, c, c, 255);
			else if (b==SPC_PROP)
				drawtext(vid_buf, x+14-textwidth("PROP")/2, y+4, "PROP", c, c, c, 255);
			break;
		default:
			for (j=1; j<15; j++)
				for (i=1; i<27; i++)
					vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
		}
		if (b==WL_ERASE+100)
		{
			for (j=4; j<12; j++)
			{
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+j+6)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+j+7)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x-j+21)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x-j+22)] = PIXPACK(0xFF0000);
			}
		}
	}
	else
	{
		//x = 2+32*(b/2);
		//y = YRES+2+20*(b%2);
		for (j=1; j<15; j++)
		{
			for (i=1; i<27; i++)
			{
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+i)] = pc;
			}
		}
		if (b==0)
		{
			for (j=4; j<12; j++)
			{
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+j+6)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x+j+7)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x-j+21)] = PIXPACK(0xFF0000);
				vid_buf[(XRES+BARSIZE)*(y+j)+(x-j+22)] = PIXPACK(0xFF0000);
			}
		}
		c = PIXB(ptypes[b].pcolors) + 3*PIXG(ptypes[b].pcolors) + 2*PIXR(ptypes[b].pcolors);
		if (c<544)
		{
			c = 255;
		}
		else
		{
			c = 0;
		}
		drawtext(vid_buf, x+14-textwidth((char *)ptypes[b].name)/2, y+4, (char *)ptypes[b].name, c, c, c, 255);
	}
	return 26;
}

void draw_menu(pixel *vid_buf, int i, int hover)
{
	if (i==SEC&&SEC!=0)
		drawrect(vid_buf, (XRES+BARSIZE)-16, (i*16)+YRES+MENUSIZE-16-(SC_TOTAL*16), 14, 14, 0, 255, 255, 255);
	else
		drawrect(vid_buf, (XRES+BARSIZE)-16, (i*16)+YRES+MENUSIZE-16-(SC_TOTAL*16), 14, 14, 255, 255, 255, 255);
	if (hover==i)
	{
		fillrect(vid_buf, (XRES+BARSIZE)-16, (i*16)+YRES+MENUSIZE-16-(SC_TOTAL*16), 14, 14, 255, 255, 255, 255);
		drawtext(vid_buf, (XRES+BARSIZE)-13, (i*16)+YRES+MENUSIZE-14-(SC_TOTAL*16), msections[i].icon, 0, 0, 0, 255);
	}
	else
	{
		drawtext(vid_buf, (XRES+BARSIZE)-13, (i*16)+YRES+MENUSIZE-14-(SC_TOTAL*16), msections[i].icon, 255, 255, 255, 255);
	}
}

void draw_color_menu(pixel *vid_buf, int i, int hover)
{
	drawrect(vid_buf, (XRES+BARSIZE)-16, (i*16)+YRES+MENUSIZE-16-(DECO_SECTIONS*16), 14, 14, 255, 255, 255, 255);
	if (hover==i)
	{
		fillrect(vid_buf, (XRES+BARSIZE)-16, (i*16)+YRES+MENUSIZE-16-(DECO_SECTIONS*16), 14, 14, 255, 255, 255, 255);
		drawtext(vid_buf, (XRES+BARSIZE)-13, (i*16)+YRES+MENUSIZE-14-(DECO_SECTIONS*16), colorsections[i].icon, 0, 0, 0, 255);
	}
	else
	{
		drawtext(vid_buf, (XRES+BARSIZE)-13, (i*16)+YRES+MENUSIZE-14-(DECO_SECTIONS*16), colorsections[i].icon, 255, 255, 255, 255);
	}
}

//draws a pixel, identical to blendpixel(), except blendpixel has OpenGL support
#if defined(WIN32) && !defined(__GNUC__)
_inline void drawpixel(pixel *vid, int x, int y, int r, int g, int b, int a)
#else
inline void drawpixel(pixel *vid, int x, int y, int r, int g, int b, int a)
#endif
{
	pixel t;
	if (x<0 || y<0 || x>=XRES+BARSIZE || y>=YRES+MENUSIZE)
		return;
	if (a!=255)
	{
		t = vid[y*(XRES+BARSIZE)+x];
		r = (a*r + (255-a)*PIXR(t)) >> 8;
		g = (a*g + (255-a)*PIXG(t)) >> 8;
		b = (a*b + (255-a)*PIXB(t)) >> 8;
	}
	vid[y*(XRES+BARSIZE)+x] = PIXRGB(r,g,b);
}

#if defined(WIN32) && !defined(__GNUC__)
_inline int drawchar(pixel *vid, int x, int y, int c, int r, int g, int b, int a)
#else
inline int drawchar(pixel *vid, int x, int y, int c, int r, int g, int b, int a)
#endif
{
	int i, j, w, bn = 0, ba = 0;
	char *rp = font_data + font_ptrs[c];
	w = *(rp++);
	for (j=0; j<FONT_H; j++)
		for (i=0; i<w; i++)
		{
			if (!bn)
			{
				ba = *(rp++);
				bn = 8;
			}
			drawpixel(vid, x+i, y+j, r, g, b, ((ba&3)*a)/3);
			ba >>= 2;
			bn -= 2;
		}
	return x + w;
}

int drawtext(pixel *vid, int x, int y, const char *s, int r, int g, int b, int a)
{
	int sx = x;
	for (; *s; s++)
	{
		if (*s == '\n')
		{
			x = sx;
			y += FONT_H+2;
		}
		else if (*s == '\b')
		{
			switch (s[1])
			{
			case 'w':
				r = g = b = 255;
				break;
			case 'g':
				r = g = b = 192;
				break;
			case 'o':
				r = 255;
				g = 216;
				b = 32;
				break;
			case 'r':
				r = 255;
				g = b = 0;
				break;
			case 'b':
				r = g = 0;
				b = 255;
				break;
			case 't':
				b = 255;
				g = 170;
				r = 32;
				break;
			}
			s++;
		}
		else
			x = drawchar(vid, x, y, *(unsigned char *)s, r, g, b, a);
	}
	return x;
}

//Draw text with an outline
int drawtext_outline(pixel *vid, int x, int y, const char *s, int r, int g, int b, int a, int or, int og, int ob, int oa)
{
	drawtext(vid, x-1, y-1, s, or, og, ob, oa);
	drawtext(vid, x+1, y+1, s, or, og, ob, oa);
	
	drawtext(vid, x-1, y+1, s, or, og, ob, oa);
	drawtext(vid, x+1, y-1, s, or, og, ob, oa);
	
	return drawtext(vid, x, y, s, r, g, b, a);
}
int drawtextwrap(pixel *vid, int x, int y, int w, const char *s, int r, int g, int b, int a)
{
	int sx = x;
	int rh = 12;
	int rw = 0;
	int cw = x;
	int wordlen;
	int charspace;
	while (*s)
	{
		wordlen = strcspn(s," .,!?\n");
		charspace = textwidthx((char *)s, w-(x-cw));
		if (charspace<wordlen && wordlen && w-(x-cw)<w/3)
		{
			x = sx;
			rw = 0;
			y+=FONT_H+2;
			rh+=FONT_H+2;
		}
		for (; *s && --wordlen>=-1; s++)
		{
			if (*s == '\n')
			{
				x = sx;
				rw = 0;
				y += FONT_H+2;
			}
			else if (*s == '\b')
			{
				switch (s[1])
				{
				case 'w':
					r = g = b = 255;
					break;
				case 'g':
					r = g = b = 192;
					break;
				case 'o':
					r = 255;
					g = 216;
					b = 32;
					break;
				case 'r':
					r = 255;
					g = b = 0;
					break;
				case 'b':
					r = g = 0;
					b = 255;
					break;
				}
				s++;
			}
			else
			{

				if (x-cw>=w)
				{
					x = sx;
					rw = 0;
					y+=FONT_H+2;
					rh+=FONT_H+2;
				}
				x = drawchar(vid, x, y, *(unsigned char *)s, r, g, b, a);
			}
		}
	}

	return rh;
}

//draws a rectange, (x,y) are the top left coords.
void drawrect(pixel *vid, int x, int y, int w, int h, int r, int g, int b, int a)
{
	int i;
	for (i=0; i<=w; i++)
	{
		drawpixel(vid, x+i, y, r, g, b, a);
		drawpixel(vid, x+i, y+h, r, g, b, a);
	}
	for (i=1; i<h; i++)
	{
		drawpixel(vid, x, y+i, r, g, b, a);
		drawpixel(vid, x+w, y+i, r, g, b, a);
	}
}

//draws a rectangle and fills it in as well.
void fillrect(pixel *vid, int x, int y, int w, int h, int r, int g, int b, int a)
{
	int i,j;
	for (j=1; j<h; j++)
		for (i=1; i<w; i++)
			drawpixel(vid, x+i, y+j, r, g, b, a);
}

void clearrect(pixel *vid, int x, int y, int w, int h)
{
	int i;
	for (i=1; i<h; i++)
		memset(vid+(x+1+(XRES+BARSIZE)*(y+i)), 0, PIXELSIZE*(w-1));
}
//draws a line of dots, where h is the height. (why is this even here)
void drawdots(pixel *vid, int x, int y, int h, int r, int g, int b, int a)
{
	int i;
	for (i=0; i<=h; i+=2)
		drawpixel(vid, x, y+i, r, g, b, a);
}

int textwidth(char *s)
{
	int x = 0;
	for (; *s; s++)
		x += font_data[font_ptrs[(int)(*(unsigned char *)s)]];
	return x-1;
}

int drawtextmax(pixel *vid, int x, int y, int w, char *s, int r, int g, int b, int a)
{
	int i;
	w += x-5;
	for (; *s; s++)
	{
		if (x+font_data[font_ptrs[(int)(*(unsigned char *)s)]]>=w && x+textwidth(s)>=w+5)
			break;
		x = drawchar(vid, x, y, *(unsigned char *)s, r, g, b, a);
	}
	if (*s)
		for (i=0; i<3; i++)
			x = drawchar(vid, x, y, '.', r, g, b, a);
	return x;
}

int textnwidth(char *s, int n)
{
	int x = 0;
	for (; *s; s++)
	{
		if (!n)
			break;
		x += font_data[font_ptrs[(int)(*(unsigned char *)s)]];
		n--;
	}
	return x-1;
}
void textnpos(char *s, int n, int w, int *cx, int *cy)
{
	int x = 0;
	int y = 0;
	int wordlen, charspace;
	while (*s&&n)
	{
		wordlen = strcspn(s," .,!?\n");
		charspace = textwidthx(s, w-x);
		if (charspace<wordlen && wordlen && w-x<w/3)
		{
			x = 0;
			y += FONT_H+2;
		}
		for (; *s && --wordlen>=-1; s++)
		{
			if (!n) {
				break;
			}
			x += font_data[font_ptrs[(int)(*(unsigned char *)s)]];
			if (x>=w)
			{
				x = 0;
				y += FONT_H+2;
			}
			n--;
		}
	}
	*cx = x-1;
	*cy = y;
}

int textwidthx(char *s, int w)
{
	int x=0,n=0,cw;
	for (; *s; s++)
	{
		cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]];
		if (x+(cw/2) >= w)
			break;
		x += cw;
		n++;
	}
	return n;
}
int textposxy(char *s, int width, int w, int h)
{
	int x=0,y=0,n=0,cw, wordlen, charspace;
	while (*s)
	{
		wordlen = strcspn(s," .,!?\n");
		charspace = textwidthx(s, width-x);
		if (charspace<wordlen && wordlen && width-x<width/3)
		{
			x = 0;
			y += FONT_H+2;
		}
		for (; *s && --wordlen>=-1; s++)
		{
			cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]];
			if ((x+(cw/2) >= w && y+6 >= h)||(y+6 >= h+FONT_H+2))
				return n++;
			x += cw;
			if (x>=width) {
				x = 0;
				y += FONT_H+2;
			}
			n++;
		}
	}
	return n;
}
int textwrapheight(char *s, int width)
{
	int x=0, height=FONT_H+2, cw;
	int wordlen;
	int charspace;
	while (*s)
	{
		wordlen = strcspn(s," .,!?\n");
		charspace = textwidthx(s, width-x);
		if (charspace<wordlen && wordlen && width-x<width/3)
		{
			x = 0;
			height += FONT_H+2;
		}
		for (; *s && --wordlen>=-1; s++)
		{
			if (*s == '\n')
			{
				x = 0;
				height += FONT_H+2;
			}
			else if (*s == '\b')
			{
				s++;
			}
			else
			{
				cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]];
				if (x+cw>=width)
				{
					x = 0;
					height += FONT_H+2;
				}
				x += cw;
			}
		}
	}
	return height;
}

//the most used function for drawing a pixel, because it has OpenGL support, which is not fully implemented.
#if defined(WIN32) && !defined(__GNUC__)
_inline void blendpixel(pixel *vid, int x, int y, int r, int g, int b, int a)
#else
inline void blendpixel(pixel *vid, int x, int y, int r, int g, int b, int a)
#endif
{
	pixel t;
	if (x<0 || y<0 || x>=XRES+BARSIZE || y>=YRES+MENUSIZE)
		return;
	if (a!=255)
	{
		t = vid[y*(XRES+BARSIZE)+x];
		r = (a*r + (255-a)*PIXR(t)) >> 8;
		g = (a*g + (255-a)*PIXG(t)) >> 8;
		b = (a*b + (255-a)*PIXB(t)) >> 8;
	}
	vid[y*(XRES+BARSIZE)+x] = PIXRGB(r,g,b);
}

void draw_icon(pixel *vid_buf, int x, int y, char ch, int flag)
{
	char t[2];
	t[0] = ch;
	t[1] = 0;
	if (flag)
	{
		fillrect(vid_buf, x-1, y-1, 17, 17, 255, 255, 255, 255);
		drawtext(vid_buf, x+3, y+2, t, 0, 0, 0, 255);
	}
	else
	{
		drawrect(vid_buf, x, y, 15, 15, 255, 255, 255, 255);
		drawtext(vid_buf, x+3, y+2, t, 255, 255, 255, 255);
	}
}

void draw_air(pixel *vid)
{
	int x, y, i, j;
	pixel c;

	if (cmode == CM_PERS)//this should never happen anyway
		return;

	for (y=0; y<YRES/CELL; y++)
		for (x=0; x<XRES/CELL; x++)
		{
			if (cmode == CM_PRESS)
			{
				if (pv[y][x] > 0.0f)
					c  = PIXRGB(clamp_flt(pv[y][x], 0.0f, 8.0f), 0, 0);//positive pressure is red!
				else
					c  = PIXRGB(0, 0, clamp_flt(-pv[y][x], 0.0f, 8.0f));//negative pressure is blue!
			}
			else if (cmode == CM_VEL)
			{
				c  = PIXRGB(clamp_flt(fabsf(vx[y][x]), 0.0f, 8.0f),//vx adds red
					clamp_flt(pv[y][x], 0.0f, 8.0f),//pressure adds green
					clamp_flt(fabsf(vy[y][x]), 0.0f, 8.0f));//vy adds blue
			}
			else if (cmode == CM_HEAT && aheat_enable)
			{
				float ttemp = hv[y][x]+(-MIN_TEMP);
				int caddress = restrict_flt((int)( restrict_flt(ttemp, 0.0f, MAX_TEMP+(-MIN_TEMP)) / ((MAX_TEMP+(-MIN_TEMP))/1024) ) *3, 0.0f, (1024.0f*3)-3);
				c = PIXRGB((int)((unsigned char)color_data[caddress]*0.7f), (int)((unsigned char)color_data[caddress+1]*0.7f), (int)((unsigned char)color_data[caddress+2]*0.7f));
				//c  = PIXRGB(clamp_flt(fabsf(vx[y][x]), 0.0f, 8.0f),//vx adds red
				//	clamp_flt(hv[y][x], 0.0f, 1600.0f),//heat adds green
				//	clamp_flt(fabsf(vy[y][x]), 0.0f, 8.0f));//vy adds blue
			}
			else if (cmode == CM_CRACK)
			{
				int r;
				int g;
				int b;
				// velocity adds grey
				r = clamp_flt(fabsf(vx[y][x]), 0.0f, 24.0f) + clamp_flt(fabsf(vy[y][x]), 0.0f, 20.0f);
				g = clamp_flt(fabsf(vx[y][x]), 0.0f, 20.0f) + clamp_flt(fabsf(vy[y][x]), 0.0f, 24.0f);
				b = clamp_flt(fabsf(vx[y][x]), 0.0f, 24.0f) + clamp_flt(fabsf(vy[y][x]), 0.0f, 20.0f);
				if (pv[y][x] > 0.0f)
				{
					r += clamp_flt(pv[y][x], 0.0f, 16.0f);//pressure adds red!
					if (r>255)
						r=255;
					if (g>255)
						g=255;
					if (b>255)
						b=255;
					c  = PIXRGB(r, g, b);
				}
				else
				{
					b += clamp_flt(-pv[y][x], 0.0f, 16.0f);//pressure adds blue!
					if (r>255)
						r=255;
					if (g>255)
						g=255;
					if (b>255)
						b=255;
					c  = PIXRGB(r, g, b);
				}
			}
			for (j=0; j<CELL; j++)//draws the colors
				for (i=0; i<CELL; i++)
					vid[(x*CELL+i) + (y*CELL+j)*(XRES+BARSIZE)] = c;
		}
}

void draw_grav_zones(pixel * vid)
{
	int x, y, i, j;
	for (y=0; y<YRES/CELL; y++)
	{
		for (x=0; x<XRES/CELL; x++)
		{
			if(gravmask[y][x])
			{
				for (j=0; j<CELL; j++)//draws the colors
					for (i=0; i<CELL; i++)
						if(i == j)
							drawpixel(vid, x*CELL+i, y*CELL+j, 255, 200, 0, 120);
						else 
							drawpixel(vid, x*CELL+i, y*CELL+j, 32, 32, 32, 120);
			}
		}
	}
}

void draw_grav(pixel *vid)
{
	int x, y, i;
	float nx, ny, dist;

	for (y=0; y<YRES/CELL; y++)
	{
		for (x=0; x<XRES/CELL; x++)
		{
			if(fabsf(gravx[y][x]) <= 0.001f && fabsf(gravy[y][x]) <= 0.001f)
				continue;
			nx = x*CELL;
			ny = y*CELL;
			dist = fabsf(gravx[y][x])+fabsf(gravy[y][x]);
			for(i = 0; i < 4; i++)
			{
				nx -= gravx[y][x]*0.5f;
				ny -= gravy[y][x]*0.5f;
				addpixel(vid, (int)(nx+0.5f), (int)(ny+0.5f), 255, 255, 255, (int)(dist*20.0f));
			}
		}
	}
}

void draw_line(pixel *vid, int x1, int y1, int x2, int y2, int r, int g, int b, int a)  //Draws a line
{
	int dx, dy, i, sx, sy, check, e, x, y;

	dx = abs(x1-x2);
	dy = abs(y1-y2);
	sx = isign(x2-x1);
	sy = isign(y2-y1);
	x = x1;
	y = y1;
	check = 0;

	if (dy>dx)
	{
		dx = dx+dy;
		dy = dx-dy;
		dx = dx-dy;
		check = 1;
	}

	e = (dy<<2)-dx;
	for (i=0; i<=dx; i++)
	{
		if (x>=0 && y>=0 && x<a && y<YRES+MENUSIZE)
			vid[x+y*a] =PIXRGB(r, g, b);
		if (e>=0)
		{
			if (check==1)
				x = x+sx;
			else
				y = y+sy;
			e = e-(dx<<2);
		}
		if (check==1)
			y = y+sy;
		else
			x = x+sx;
		e = e+(dy<<2);
	}
}

//adds color to a pixel, does not overwrite.
void addpixel(pixel *vid, int x, int y, int r, int g, int b, int a)
{
	pixel t;
	if (x<0 || y<0 || x>=XRES || y>=YRES)
		return;
	t = vid[y*(XRES+BARSIZE)+x];
	r = (a*r + 255*PIXR(t)) >> 8;
	g = (a*g + 255*PIXG(t)) >> 8;
	b = (a*b + 255*PIXB(t)) >> 8;
	if (r>255)
		r = 255;
	if (g>255)
		g = 255;
	if (b>255)
		b = 255;
	vid[y*(XRES+BARSIZE)+x] = PIXRGB(r,g,b);
}

//draws one of two colors, so that it is always clearly visible
void xor_pixel(int x, int y, pixel *vid)
{
	int c;
	if (x<0 || y<0 || x>=XRES || y>=YRES)
		return;
	c = vid[y*(XRES+BARSIZE)+x];
	c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c);
	if (c<512)
		vid[y*(XRES+BARSIZE)+x] = PIXPACK(0xC0C0C0);
	else
		vid[y*(XRES+BARSIZE)+x] = PIXPACK(0x404040);
}

//same as xor_pixel, but draws a line of it
void xor_line(int x1, int y1, int x2, int y2, pixel *vid)
{
	int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
	float e, de;
	if (cp)
	{
		y = x1;
		x1 = y1;
		y1 = y;
		y = x2;
		x2 = y2;
		y2 = y;
	}
	if (x1 > x2)
	{
		y = x1;
		x1 = x2;
		x2 = y;
		y = y1;
		y1 = y2;
		y2 = y;
	}
	dx = x2 - x1;
	dy = abs(y2 - y1);
	e = 0.0f;
	if (dx)
		de = dy/(float)dx;
	else
		de = 0.0f;
	y = y1;
	sy = (y1<y2) ? 1 : -1;
	for (x=x1; x<=x2; x++)
	{
		if (cp)
			xor_pixel(y, x, vid);
		else
			xor_pixel(x, y, vid);
		e += de;
		if (e >= 0.5f)
		{
			y += sy;
			e -= 1.0f;
		}
	}
}

//same as blend_pixel, but draws a line of it
void blend_line(pixel *vid, int x1, int y1, int x2, int y2, int r, int g, int b, int a)
{
	int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
	float e, de;
	if (cp)
	{
		y = x1;
		x1 = y1;
		y1 = y;
		y = x2;
		x2 = y2;
		y2 = y;
	}
	if (x1 > x2)
	{
		y = x1;
		x1 = x2;
		x2 = y;
		y = y1;
		y1 = y2;
		y2 = y;
	}
	dx = x2 - x1;
	dy = abs(y2 - y1);
	e = 0.0f;
	if (dx)
		de = dy/(float)dx;
	else
		de = 0.0f;
	y = y1;
	sy = (y1<y2) ? 1 : -1;
	for (x=x1; x<=x2; x++)
	{
		if (cp)
			blendpixel(vid, y, x, r, g, b, a);
		else
			blendpixel(vid, x, y, r, g, b, a);
		e += de;
		if (e >= 0.5f)
		{
			y += sy;
			e -= 1.0f;
		}
	}
}

//same as xor_pixel, but draws a rectangle
void xor_rect(pixel *vid, int x, int y, int w, int h)
{
	int i;
	for (i=0; i<w; i+=2)
	{
		xor_pixel(x+i, y, vid);
		xor_pixel(x+i, y+h-1, vid);
	}
	for (i=2; i<h; i+=2)
	{
		xor_pixel(x, y+i, vid);
		xor_pixel(x+w-1, y+i, vid);
	}
}

//New function for drawing particles
void render_parts(pixel *vid)
{
	//TODO: Replace cmode with a set of flags
	int deca, decr, decg, decb, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, i, t, nx, ny, x, y, caddress;
	float gradv, flicker;
	for(i = 0; i<=parts_lastActiveIndex; i++) {
		if (parts[i].type) {
			t = parts[i].type;

			nx = (int)(parts[i].x+0.5f);
			ny = (int)(parts[i].y+0.5f);

			if(photons[ny][nx]&0xFF && !(ptypes[t].properties & TYPE_ENERGY))
				continue;
				
			//Defaults
			pixel_mode = 0 | PMODE_FLAT;
			colr = PIXR(ptypes[t].pcolors);
			colg = PIXG(ptypes[t].pcolors);
			colb = PIXB(ptypes[t].pcolors);
			firea = 0;
			
			deca = (parts[i].dcolour>>24)&0xFF;
			decr = (parts[i].dcolour>>16)&0xFF;
			decg = (parts[i].dcolour>>8)&0xFF;
			decb = (parts[i].dcolour)&0xFF;
				
			if (ptypes[t].graphics_func)
			{
				if ((*(ptypes[t].graphics_func))(i, nx, ny, &pixel_mode, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better
				{
					//Data can be cached!
				}
			}
			else
			{
				//Property based defaults
				if(ptypes[t].properties & PROP_RADIOACTIVE) pixel_mode |= PMODE_GLOW;
				if(ptypes[t].properties & PROP_HOT_GLOW && parts[i].temp>(ptransitions[t].thv-800.0f))
				{
					gradv = 3.1415/(2*ptransitions[t].thv-(ptransitions[t].thv-800.0f));
					caddress = (parts[i].temp>ptransitions[t].thv)?ptransitions[t].thv-(ptransitions[t].thv-800.0f):parts[i].temp-(ptransitions[t].thv-800.0f);
					colr += sin(gradv*caddress) * 226;;
					colg += sin(gradv*caddress*4.55 +3.14) * 34;
					colb += sin(gradv*caddress*2.22 +3.14) * 64;
				}
				if(ptypes[t].properties & TYPE_LIQUID)
				{
					pixel_mode |= PMODE_BLUR;
				}
				if(ptypes[t].properties & TYPE_GAS)
				{
					pixel_mode &= ~PMODE;
					pixel_mode |= FIRE_BLEND;
					firer = colr/2;
					fireg = colg/2;
					fireb = colb/2;
					firea = 125;
				}
			}
			
			if(cmode == CM_NOTHING)
			{
				vid[ny*(XRES+BARSIZE)+nx] = PIXRGB(colr,colg,colb);
			}
			else
			{
				//Alter colour based on display mode
				switch(cmode)
				{
				case CM_HEAT:
					caddress = restrict_flt((int)( restrict_flt((float)(parts[i].temp+(-MIN_TEMP)), 0.0f, MAX_TEMP+(-MIN_TEMP)) / ((MAX_TEMP+(-MIN_TEMP))/1024) ) *3, 0.0f, (1024.0f*3)-3);
					firea = 255;
					firer = colr = (unsigned char)color_data[caddress];
					fireg = colg = (unsigned char)color_data[caddress+1];
					fireb = colb = (unsigned char)color_data[caddress+2];
				case CM_PERS:
				case CM_CRACK:
				case CM_VEL:
				case CM_PRESS:
				case CM_LIFE:
				case CM_GRAD:
					if(pixel_mode & FIRE_ADD) pixel_mode = (pixel_mode & ~FIRE_ADD) | PMODE_GLOW;
					if(pixel_mode & FIRE_BLEND) pixel_mode = (pixel_mode & ~FIRE_BLEND) | PMODE_BLUR;
				case CM_FIRE:
					if(pixel_mode & PMODE_BLOB) pixel_mode = (pixel_mode & ~PMODE_BLOB) | PMODE_FLAT;
					if(pixel_mode & PMODE_BLUR) pixel_mode = (pixel_mode & ~PMODE_BLUR) | PMODE_FLAT;
					break;
				case CM_BLOB:
					if(pixel_mode & PMODE_FLAT) pixel_mode = (pixel_mode & ~PMODE_FLAT) | PMODE_BLOB;
					break;
				case CM_FANCY:
					break;
				default:
					break;
				}
				
				//Apply decoration colour
				colr = (deca*decr + (255-deca)*colr) >> 8;
				colg = (deca*decg + (255-deca)*colg) >> 8;
				colb = (deca*decb + (255-deca)*colb) >> 8;
				
				//All colours are now set, check ranges
				if(colr>255) colr = 255;
				else if(colr<0) colr = 0;
				if(colg>255) colg = 255;
				else if(colg<0) colg = 0;
				if(colb>255) colb = 255;
				else if(colb<0) colb = 0;
				
				//Pixel rendering
				if(pixel_mode & PMODE_FLAT)
				{
					vid[ny*(XRES+BARSIZE)+nx] = PIXRGB(colr,colg,colb);
				}
				if(pixel_mode & PMODE_BLOB)
				{
					blendpixel(vid, nx+1, ny, colr, colg, colb, 223);
					blendpixel(vid, nx-1, ny, colr, colg, colb, 223);
					blendpixel(vid, nx, ny+1, colr, colg, colb, 223);
					blendpixel(vid, nx, ny-1, colr, colg, colb, 223);

					blendpixel(vid, nx+1, ny-1, colr, colg, colb, 112);
					blendpixel(vid, nx-1, ny-1, colr, colg, colb, 112);
					blendpixel(vid, nx+1, ny+1, colr, colg, colb, 112);
					blendpixel(vid, nx-1, ny+1, colr, colg, colb, 112);
				}
				if(pixel_mode & PMODE_GLOW)
				{
					addpixel(vid, nx, ny, colr, colg, colb, 192);
					addpixel(vid, nx+1, ny, colr, colg, colb, 96);
					addpixel(vid, nx-1, ny, colr, colg, colb, 96);
					addpixel(vid, nx, ny+1, colr, colg, colb, 96);
					addpixel(vid, nx, ny-1, colr, colg, colb, 96);
					
					for (x = 1; x < 6; x++) {
						addpixel(vid, nx, ny-x, colr, colg, colb, 5);
						addpixel(vid, nx, ny+x, colr, colg, colb, 5);
						addpixel(vid, nx-x, ny, colr, colg, colb, 5);
						addpixel(vid, nx+x, ny, colr, colg, colb, 5);
						for (y = 1; y < 6; y++) {
							if(x + y > 7)
								continue;
							addpixel(vid, nx+x, ny-y, colr, colg, colb, 5);
							addpixel(vid, nx-x, ny+y, colr, colg, colb, 5);
							addpixel(vid, nx+x, ny+y, colr, colg, colb, 5);
							addpixel(vid, nx-x, ny-y, colr, colg, colb, 5);
						}
					}
				}
				if(pixel_mode & PMODE_BLUR)
				{
					for (x=-3; x<4; x++)
					{
						for (y=-3; y<4; y++)
						{
							if (abs(x)+abs(y) <2 && !(abs(x)==2||abs(y)==2))
								blendpixel(vid, x+nx, y+ny, colr, colg, colb, 30);
							if (abs(x)+abs(y) <=3 && abs(x)+abs(y))
								blendpixel(vid, x+nx, y+ny, colr, colg, colb, 20);
							if (abs(x)+abs(y) == 2)
								blendpixel(vid, x+nx, y+ny, colr, colg, colb, 10);
						}
					}
				}
				if(pixel_mode & PMODE_SPARK)
				{
					flicker = rand()%20;
					gradv = 4*parts[i].life + flicker;
					for (x = 0; gradv>0.5; x++) {
						addpixel(vid, nx+x, ny, colr, colg, colb, gradv);
						addpixel(vid, nx-x, ny, colr, colg, colb, gradv);

						addpixel(vid, nx, ny+x, colr, colg, colb, gradv);
						addpixel(vid, nx, ny-x, colr, colg, colb, gradv);
						gradv = gradv/1.5f;
					}
				}
				if(pixel_mode & PMODE_FLARE)
				{
					flicker = rand()%20;
					gradv = flicker + fabs(parts[i].vx)*17 + fabs(parts[i].vy)*17;
					blendpixel(vid, nx, ny, colr, colg, colb, (gradv*4)>255?255:(gradv*4) );
					blendpixel(vid, nx+1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx-1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx, ny+1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx, ny-1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					if (gradv>255) gradv=255;
					blendpixel(vid, nx+1, ny-1, colr, colg, colb, gradv);
					blendpixel(vid, nx-1, ny-1, colr, colg, colb, gradv);
					blendpixel(vid, nx+1, ny+1, colr, colg, colb, gradv);
					blendpixel(vid, nx-1, ny+1, colr, colg, colb, gradv);
					for (x = 1; gradv>0.5; x++) {
						addpixel(vid, nx+x, ny, colr, colg, colb, gradv);
						addpixel(vid, nx-x, ny, colr, colg, colb, gradv);
						addpixel(vid, nx, ny+x, colr, colg, colb, gradv);
						addpixel(vid, nx, ny-x, colr, colg, colb, gradv);
						gradv = gradv/1.2f;
					}
				}
				if(pixel_mode & PMODE_LFLARE)
				{
					flicker = rand()%20;
					gradv = flicker + fabs(parts[i].vx)*17 + fabs(parts[i].vy)*17;
					blendpixel(vid, nx, ny, colr, colg, colb, (gradv*4)>255?255:(gradv*4) );
					blendpixel(vid, nx+1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx-1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx, ny+1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					blendpixel(vid, nx, ny-1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) );
					if (gradv>255) gradv=255;
					blendpixel(vid, nx+1, ny-1, colr, colg, colb, gradv);
					blendpixel(vid, nx-1, ny-1, colr, colg, colb, gradv);
					blendpixel(vid, nx+1, ny+1, colr, colg, colb, gradv);
					blendpixel(vid, nx-1, ny+1, colr, colg, colb, gradv);
					for (x = 1; gradv>0.5; x++) {
						addpixel(vid, nx+x, ny, colr, colg, colb, gradv);
						addpixel(vid, nx-x, ny, colr, colg, colb, gradv);
						addpixel(vid, nx, ny+x, colr, colg, colb, gradv);
						addpixel(vid, nx, ny-x, colr, colg, colb, gradv);
						gradv = gradv/1.01f;
					}
				}
				//Fire effects
				if(firea && (pixel_mode & FIRE_BLEND))
				{
					if(cmode==CM_FIRE || cmode==CM_BLOB || cmode==CM_FANCY)
					{
						fire_r[ny/CELL][nx/CELL] = (firea*firer + (255-firea)*fire_r[ny/CELL][nx/CELL]) >> 8;
						fire_g[ny/CELL][nx/CELL] = (firea*fireg + (255-firea)*fire_g[ny/CELL][nx/CELL]) >> 8;
						fire_b[ny/CELL][nx/CELL] = (firea*fireb + (255-firea)*fire_b[ny/CELL][nx/CELL]) >> 8;
					} else {
						//This smoke rendering style is horrendously slow, optimise, optimise, optimise!
						for (x=-3; x<4; x++)
						{
							for (y=-3; y<4; y++)
							{
								if (abs(x)+abs(y) <2 && !(abs(x)==2||abs(y)==2))
									blendpixel(vid, x+nx, y+ny, firer, fireg, fireb, (30*(firea))>>8);
								if (abs(x)+abs(y) <=3 && abs(x)+abs(y))
									blendpixel(vid, x+nx, y+ny, firer, fireg, fireb, (20*(firea))>>8);
								if (abs(x)+abs(y) == 2)
									blendpixel(vid, x+nx, y+ny, firer, fireg, fireb, (10*(firea))>>8);
							}
						}
					}
				}
				if(firea && (pixel_mode & FIRE_ADD))
				{
					if(cmode==CM_FIRE || cmode==CM_BLOB || cmode==CM_FANCY)
					{
						firer = ((firea*firer) >> 8) + fire_r[ny/CELL][nx/CELL];
						fireg = ((firea*fireg) >> 8) + fire_g[ny/CELL][nx/CELL];
						fireb = ((firea*fireb) >> 8) + fire_b[ny/CELL][nx/CELL];
					
						if(firer>255)
							firer = 255;
						if(fireg>255)
							fireg = 255;
						if(fireb>255)
							fireb = 255;
						
						fire_r[ny/CELL][nx/CELL] = firer;
						fire_g[ny/CELL][nx/CELL] = fireg;
						fire_b[ny/CELL][nx/CELL] = fireb;
					} else {
						for (x=-3; x<4; x++)
						{
							for (y=-3; y<4; y++)
							{
								if (abs(x)+abs(y) <2 && !(abs(x)==2||abs(y)==2))
									addpixel(vid, x+nx, y+ny, firer, fireg, fireb, (175*(firea))>>8);
								if (abs(x)+abs(y) <=3 && abs(x)+abs(y))
									addpixel(vid, x+nx, y+ny, firer, fireg, fireb, (100*(firea))>>8);
								if (abs(x)+abs(y) == 2)
									addpixel(vid, x+nx, y+ny, firer, fireg, fireb, (55*(firea))>>8);
							}
						}
					}
				}
			}
		}
	}
}

void draw_walls(pixel *vid)
{
	int x, y, i, j, cr, cg, cb;
	unsigned char wt;
	pixel pc;
	pixel gc;
	for (y=0; y<YRES/CELL; y++)
		for (x=0; x<XRES/CELL; x++)
			if (bmap[y][x])
			{
				wt = bmap[y][x]-UI_ACTUALSTART;
				if (wt<0 || wt>=UI_WALLCOUNT)
					continue;
				pc = wtypes[wt].colour;
				gc = wtypes[wt].eglow;

				// standard wall patterns
				if (wtypes[wt].drawstyle==1)
				{
					for (j=0; j<CELL; j+=2)
						for (i=(j>>1)&1; i<CELL; i+=2)
							vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
				}
				else if (wtypes[wt].drawstyle==2)
				{
					for (j=0; j<CELL; j+=2)
						for (i=0; i<CELL; i+=2)
							vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
				}
				else if (wtypes[wt].drawstyle==3)
				{
					for (j=0; j<CELL; j++)
						for (i=0; i<CELL; i++)
							vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
				}
				else if (wtypes[wt].drawstyle==4)
				{
					for (j=0; j<CELL; j++)
						for (i=0; i<CELL; i++)
							if(i == j)
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
							else if  (i == j+1 || (i == 0 && j == CELL-1))
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = gc;
							else 
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x202020);
				}

				// special rendering for some walls
				if (bmap[y][x]==WL_EWALL)
				{
					if (emap[y][x])
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
								if (i&j&1)
									vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
					}
					else
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
								if (!(i&j&1))
									vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
					}
				}
				else if (bmap[y][x]==WL_WALLELEC)
				{
					for (j=0; j<CELL; j++)
						for (i=0; i<CELL; i++)
						{
							if (!((y*CELL+j)%2) && !((x*CELL+i)%2))
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = pc;
							else
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x808080);
						}
				}
				else if (bmap[y][x]==WL_EHOLE)
				{
					if (emap[y][x])
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x242424);
						for (j=0; j<CELL; j+=2)
							for (i=0; i<CELL; i+=2)
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x000000);
					}
					else
					{
						for (j=0; j<CELL; j+=2)
							for (i=0; i<CELL; i+=2)
								vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x242424);
					}
				}
				
				if (cmode==CM_BLOB)
				{
					// when in blob view, draw some blobs...
					if (wtypes[wt].drawstyle==1)
					{
						for (j=0; j<CELL; j+=2)
							for (i=(j>>1)&1; i<CELL; i+=2)
								drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(pc), PIXG(pc), PIXB(pc));
					}
					else if (wtypes[wt].drawstyle==2)
					{
						for (j=0; j<CELL; j+=2)
							for (i=0; i<CELL; i+=2)
								drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(pc), PIXG(pc), PIXB(pc));
					}
					else if (wtypes[wt].drawstyle==3)
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
								drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(pc), PIXG(pc), PIXB(pc));
					}
					else if (wtypes[wt].drawstyle==4)
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
								if(i == j)
									drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(pc), PIXG(pc), PIXB(pc));
								else if  (i == j+1 || (i == 0 && j == CELL-1))
									drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(gc), PIXG(gc), PIXB(gc));
								else 
									drawblob(vid, (x*CELL+i), (y*CELL+j), 0x20, 0x20, 0x20);
					}
					if (bmap[y][x]==WL_EWALL)
					{
						if (emap[y][x])
						{
							for (j=0; j<CELL; j++)
								for (i=0; i<CELL; i++)
									if (i&j&1)
										drawblob(vid, (x*CELL+i), (y*CELL+j), 0x80, 0x80, 0x80);
						}
						else
						{
							for (j=0; j<CELL; j++)
								for (i=0; i<CELL; i++)
									if (!(i&j&1))
										drawblob(vid, (x*CELL+i), (y*CELL+j), 0x80, 0x80, 0x80);
						}
					}
					else if (bmap[y][x]==WL_WALLELEC)
					{
						for (j=0; j<CELL; j++)
							for (i=0; i<CELL; i++)
							{
								if (!((y*CELL+j)%2) && !((x*CELL+i)%2))
									drawblob(vid, (x*CELL+i), (y*CELL+j), PIXR(pc), PIXG(pc), PIXB(pc));
								else
									drawblob(vid, (x*CELL+i), (y*CELL+j), 0x80, 0x80, 0x80);
							}
					}
					else if (bmap[y][x]==WL_EHOLE)
					{
						if (emap[y][x])
						{
							for (j=0; j<CELL; j++)
								for (i=0; i<CELL; i++)
									drawblob(vid, (x*CELL+i), (y*CELL+j), 0x24, 0x24, 0x24);
							for (j=0; j<CELL; j+=2)
								for (i=0; i<CELL; i+=2)
									vid[(y*CELL+j)*(XRES+BARSIZE)+(x*CELL+i)] = PIXPACK(0x000000);
						}
						else
						{
							for (j=0; j<CELL; j+=2)
								for (i=0; i<CELL; i+=2)
									drawblob(vid, (x*CELL+i), (y*CELL+j), 0x24, 0x24, 0x24);
						}
					}
				}

				if (wtypes[wt].eglow && emap[y][x])
				{
					// glow if electrified
					pc = wtypes[wt].eglow;
					cr = fire_r[y][x] + PIXR(pc);
					if (cr > 255) cr = 255;
					fire_r[y][x] = cr;
					cg = fire_g[y][x] + PIXG(pc);
					if (cg > 255) cg = 255;
					fire_g[y][x] = cg;
					cb = fire_b[y][x] + PIXB(pc);
					if (cb > 255) cb = 255;
					fire_b[y][x] = cb;
					
				}
			}
}

void create_decorations(int x, int y, int rx, int ry, int r, int g, int b, int click, int tool)
{
	int i,j,rp;
	if (rx==0 && ry==0)
	{
		create_decoration(x,y,r,g,b,click,tool);
		return;
	}
	for (j=-ry; j<=ry; j++)
		for (i=-rx; i<=rx; i++)
			if(y+j>=0 && x+i>=0 && x+i<XRES && y+j<YRES)
				if (InCurrentBrush(i, j, rx, ry)){
					create_decoration(x+i,y+j,r,g,b,click,tool);
				}
}
void create_decoration(int x, int y, int r, int g, int b, int click, int tool)
{
	int rp, tr,tg,tb;
	rp = pmap[y][x];
	if (!rp)
		return;
	if (tool == DECO_DRAW)
	{
		if (click == 4)
			parts[rp>>8].dcolour = 0;
		else
			parts[rp>>8].dcolour = ((255<<24)|(r<<16)|(g<<8)|b);
	}
	else if (tool == DECO_LIGHTEN)
	{//maybe get a better lighten/darken?
		if (parts[rp>>8].dcolour == 0)
			return;
		tr = (parts[rp>>8].dcolour>>16)&0xFF;
		tg = (parts[rp>>8].dcolour>>8)&0xFF;
		tb = (parts[rp>>8].dcolour)&0xFF;
		parts[rp>>8].dcolour = ((parts[rp>>8].dcolour&0xFF000000)|(clamp_flt(tr+(255-tr)*0.02+1, 0,255)<<16)|(clamp_flt(tg+(255-tg)*0.02+1, 0,255)<<8)|clamp_flt(tb+(255-tb)*0.02+1, 0,255));
	}
	else if (tool == DECO_DARKEN)
	{
		if (parts[rp>>8].dcolour == 0)
			return;
		tr = (parts[rp>>8].dcolour>>16)&0xFF;
		tg = (parts[rp>>8].dcolour>>8)&0xFF;
		tb = (parts[rp>>8].dcolour)&0xFF;
		parts[rp>>8].dcolour = ((parts[rp>>8].dcolour&0xFF000000)|(clamp_flt(tr-(tr)*0.02, 0,255)<<16)|(clamp_flt(tg-(tg)*0.02, 0,255)<<8)|clamp_flt(tb-(tb)*0.02, 0,255));
	}
}
void line_decorations(int x1, int y1, int x2, int y2, int rx, int ry, int r, int g, int b, int click, int tool)
{
	int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
	float e, de;
	if (cp)
	{
		y = x1;
		x1 = y1;
		y1 = y;
		y = x2;
		x2 = y2;
		y2 = y;
	}
	if (x1 > x2)
	{
		y = x1;
		x1 = x2;
		x2 = y;
		y = y1;
		y1 = y2;
		y2 = y;
	}
	dx = x2 - x1;
	dy = abs(y2 - y1);
	e = 0.0f;
	if (dx)
		de = dy/(float)dx;
	else
		de = 0.0f;
	y = y1;
	sy = (y1<y2) ? 1 : -1;
	for (x=x1; x<=x2; x++)
	{
		if (cp)
			create_decorations(y, x, rx, ry, r, g, b, click, tool);
		else
			create_decorations(x, y, rx, ry, r, g, b, click, tool);
		e += de;
		if (e >= 0.5f)
		{
			y += sy;
			if (!(rx+ry))
			{
				if (cp)
					create_decorations(y, x, rx, ry, r, g, b, click, tool);
				else
					create_decorations(x, y, rx, ry, r, g, b, click, tool);
			}
			e -= 1.0f;
		}
	}
}
void box_decorations(int x1, int y1, int x2, int y2, int r, int g, int b, int click, int tool)
{
	int i, j;
	if (x1>x2)
	{
		i = x2;
		x2 = x1;
		x1 = i;
	}
	if (y1>y2)
	{
		j = y2;
		y2 = y1;
		y1 = j;
	}
	for (j=y1; j<=y2; j++)
		for (i=x1; i<=x2; i++)
			create_decorations(i, j, 0, 0, r, g, b, click, tool);
}

//draws the photon colors in the HUD
void draw_wavelengths(pixel *vid, int x, int y, int h, int wl)
{
	int i,cr,cg,cb,j;
	int tmp;
	fillrect(vid,x-1,y-1,30+1,h+1,64,64,64,255); // coords -1 size +1 to work around bug in fillrect - TODO: fix fillrect
	for (i=0; i<30; i++)
	{
		if ((wl>>i)&1)
		{
			// Need a spread of wavelengths to get a smooth spectrum, 5 bits seems to work reasonably well
			if (i>2) tmp = 0x1F << (i-2);
			else tmp = 0x1F >> (2-i);
			cg = 0;
			cb = 0;
			cr = 0;
			for (j=0; j<12; j++) {
				cr += (tmp >> (j+18)) & 1;
				cb += (tmp >>  j)     & 1;
			}
			for (j=0; j<13; j++)
				cg += (tmp >> (j+9))  & 1;
			tmp = 624/(cr+cg+cb+1);
			cr *= tmp;
			cg *= tmp;
			cb *= tmp;
			for (j=0; j<h; j++) blendpixel(vid,x+29-i,y+j,cr>255?255:cr,cg>255?255:cg,cb>255?255:cb,255);
		}
	}
}

void render_signs(pixel *vid_buf)
{
	int i, j, x, y, w, h, dx, dy,mx,my,b=1,bq;
	for (i=0; i<MAXSIGNS; i++)
		if (signs[i].text[0])
		{
			char buff[256];  //Buffer
			get_sign_pos(i, &x, &y, &w, &h);
			clearrect(vid_buf, x, y, w, h);
			drawrect(vid_buf, x, y, w, h, 192, 192, 192, 255);

			//Displaying special information
			if (strcmp(signs[i].text, "{p}")==0)
			{
				sprintf(buff, "Pressure: %3.2f", pv[signs[i].y/CELL][signs[i].x/CELL]);  //...pressure
				drawtext(vid_buf, x+3, y+3, buff, 255, 255, 255, 255);
			}
			if (strcmp(signs[i].text, "{t}")==0)
			{
				if (pmap[signs[i].y][signs[i].x])
					sprintf(buff, "Temp: %4.2f", parts[pmap[signs[i].y][signs[i].x]>>8].temp-273.15);  //...tempirature
				else
					sprintf(buff, "Temp: 0.00");  //...tempirature
				drawtext(vid_buf, x+3, y+3, buff, 255, 255, 255, 255);
			}

			if (sregexp(signs[i].text, "^{c:[0-9]*|.*}$")==0)
			{
				int sldr, startm;
				memset(buff, 0, sizeof(buff));
				for (sldr=3; signs[i].text[sldr-1] != '|'; sldr++)
					startm = sldr + 1;
				sldr = startm;
				while (signs[i].text[sldr] != '}')
				{
					buff[sldr - startm] = signs[i].text[sldr];
					sldr++;
				}
				drawtext(vid_buf, x+3, y+3, buff, 0, 191, 255, 255);
			}

			//Usual text
			if (strcmp(signs[i].text, "{p}") && strcmp(signs[i].text, "{t}") && sregexp(signs[i].text, "^{c:[0-9]*|.*}$"))
				drawtext(vid_buf, x+3, y+3, signs[i].text, 255, 255, 255, 255);

			x = signs[i].x;
			y = signs[i].y;
			dx = 1 - signs[i].ju;
			dy = (signs[i].y > 18) ? -1 : 1;
			for (j=0; j<4; j++)
			{
				drawpixel(vid_buf, x, y, 192, 192, 192, 255);
				x+=dx;
				y+=dy;
			}
			if (MSIGN==i)
			{
				bq = b;
				b = SDL_GetMouseState(&mx, &my);
				mx /= sdl_scale;
				my /= sdl_scale;
				signs[i].x = mx;
				signs[i].y = my;
			}
		}
}

void render_gravlensing(pixel *src, pixel * dst)
{
	int nx, ny, rx, ry, gx, gy, bx, by;
	int r, g, b;
	pixel t;
	for(nx = 0; nx < XRES; nx++)
	{
		for(ny = 0; ny < YRES; ny++)
		{
			rx = (int)(nx-gravxf[(ny*XRES)+nx]*0.75f+0.5f);
			ry = (int)(ny-gravyf[(ny*XRES)+nx]*0.75f+0.5f);
			gx = (int)(nx-gravxf[(ny*XRES)+nx]*0.875f+0.5f);
			gy = (int)(ny-gravyf[(ny*XRES)+nx]*0.875f+0.5f);
			bx = (int)(nx-gravxf[(ny*XRES)+nx]+0.5f);
			by = (int)(ny-gravyf[(ny*XRES)+nx]+0.5f);
			if(rx > 0 && rx < XRES && ry > 0 && ry < YRES && gx > 0 && gx < XRES && gy > 0 && gy < YRES && bx > 0 && bx < XRES && by > 0 && by < YRES)
			{
				t = dst[ny*(XRES+BARSIZE)+nx];
				r = PIXR(src[ry*(XRES+BARSIZE)+rx]) + PIXR(t);
				g = PIXG(src[gy*(XRES+BARSIZE)+gx]) + PIXG(t);
				b = PIXB(src[by*(XRES+BARSIZE)+bx]) + PIXB(t);
				if (r>255)
					r = 255;
				if (g>255)
					g = 255;
				if (b>255)
					b = 255;
				dst[ny*(XRES+BARSIZE)+nx] = PIXRGB(r,g,b);
				//	addpixel(dst, nx, ny, PIXR(src[ry*(XRES+BARSIZE)+rx]), PIXG(src[gy*(XRES+BARSIZE)+gx]), PIXB(src[by*(XRES+BARSIZE)+bx]), 255);
			}

			/*rx = nx+(gravxf[(ny*XRES)+nx]*0.5f);
			ry = ny+(gravyf[(ny*XRES)+nx]*0.5f);
			gx = nx+(gravxf[(ny*XRES)+nx]*0.75f);
			gy = ny+(gravyf[(ny*XRES)+nx]*0.75f);
			bx = nx+(gravxf[(ny*XRES)+nx]);
			by = ny+(gravyf[(ny*XRES)+nx]);
			if(rx > 0 && rx < XRES && ry > 0 && ry < YRES && gravp[ny/CELL][nx/CELL]*0.5f > -8.0f)
				addpixel(dst, rx, ry, PIXR(src[ry*(XRES+BARSIZE)+rx]), 0, 0, 255);
			if(gx > 0 && gx < XRES && gy > 0 && gy < YRES && gravp[ny/CELL][nx/CELL]*0.75f > -8.0f)
				addpixel(dst, gx, gy, 0, PIXG(src[ry*(XRES+BARSIZE)+rx]), 0, 255);
			if(bx > 0 && bx < XRES && by > 0 && by < YRES && gravp[ny/CELL][nx/CELL] > -8.0f)
				addpixel(dst, bx, by, 0, 0, PIXB(src[ry*(XRES+BARSIZE)+rx]), 255);*/
		}
	}
}

void render_fire(pixel *vid)
{
	int i,j,x,y,r,g,b,nx,ny;
	for (j=0; j<YRES/CELL; j++)
		for (i=0; i<XRES/CELL; i++)
		{
			r = fire_r[j][i];
			g = fire_g[j][i];
			b = fire_b[j][i];
			if (r || g || b)
				for (y=-CELL+1; y<2*CELL; y++)
					for (x=-CELL+1; x<2*CELL; x++)
						addpixel(vid, i*CELL+x, j*CELL+y, r, g, b, fire_alpha[y+CELL][x+CELL]);
			r *= 8;
			g *= 8;
			b *= 8;
			for (y=-1; y<2; y++)
				for (x=-1; x<2; x++)
					if ((x || y) && i+x>=0 && j+y>=0 && i+x<XRES/CELL && j+y<YRES/CELL)
					{
						r += fire_r[j+y][i+x];
						g += fire_g[j+y][i+x];
						b += fire_b[j+y][i+x];
					}
			r /= 16;
			g /= 16;
			b /= 16;
			fire_r[j][i] = r>4 ? r-4 : 0;
			fire_g[j][i] = g>4 ? g-4 : 0;
			fire_b[j][i] = b>4 ? b-4 : 0;
		}
}

void prepare_alpha(int size, float intensity)
{
	//TODO: implement size
	int x,y,i,j;
	float multiplier = 255.0f*intensity;
	float temp[CELL*3][CELL*3];
	memset(temp, 0, sizeof(temp));
	for (x=0; x<CELL; x++)
		for (y=0; y<CELL; y++)
			for (i=-CELL; i<CELL; i++)
				for (j=-CELL; j<CELL; j++)
					temp[y+CELL+j][x+CELL+i] += expf(-0.1f*(i*i+j*j));
	for (x=0; x<CELL*3; x++)
		for (y=0; y<CELL*3; y++)
			fire_alpha[y][x] = (int)(multiplier*temp[y][x]/(CELL*CELL));
}

pixel *render_packed_rgb(void *image, int width, int height, int cmp_size)
{
	unsigned char *tmp;
	pixel *res;
	int i;

	tmp = malloc(width*height*3);
	if (!tmp)
		return NULL;
	res = malloc(width*height*PIXELSIZE);
	if (!res)
	{
		free(tmp);
		return NULL;
	}

	i = width*height*3;
	if (BZ2_bzBuffToBuffDecompress((char *)tmp, (unsigned *)&i, (char *)image, cmp_size, 0, 0))
	{
		free(res);
		free(tmp);
		return NULL;
	}

	for (i=0; i<width*height; i++)
		res[i] = PIXRGB(tmp[3*i], tmp[3*i+1], tmp[3*i+2]);

	free(tmp);
	return res;
}

void draw_rgba_image(pixel *vid, unsigned char *data, int x, int y, float alpha)
{
	unsigned char w, h;
	int i, j;
	unsigned char r, g, b, a;
	if (!data) return;
	w = *(data++)&0xFF;
	h = *(data++)&0xFF;
	for (j=0; j<h; j++)
	{
		for (i=0; i<w; i++)
		{
			r = *(data++)&0xFF;
			g = *(data++)&0xFF;
			b = *(data++)&0xFF;
			a = *(data++)&0xFF;
			drawpixel(vid, x+i, y+j, r, g, b, a*alpha);
		}
	}
}

void draw_image(pixel *vid, pixel *img, int x, int y, int w, int h, int a)
{
	int i, j, r, g, b;
	if (!img) return;
	for (j=0; j<h; j++)
		for (i=0; i<w; i++)
		{
			r = PIXR(*img);
			g = PIXG(*img);
			b = PIXB(*img);
			drawpixel(vid, x+i, y+j, r, g, b, a);
			img++;
		}
}

void dim_copy(pixel *dst, pixel *src) //old persistent, unused
{
	int i,r,g,b;
	for (i=0; i<XRES*YRES; i++)
	{
		r = PIXR(src[i]);
		g = PIXG(src[i]);
		b = PIXB(src[i]);
		if (r>0)
			r--;
		if (g>0)
			g--;
		if (b>0)
			b--;
		dst[i] = PIXRGB(r,g,b);
	}
}

void dim_copy_pers(pixel *dst, pixel *src) //for persistent view, reduces rgb slowly
{
	int i,r,g,b;
	for (i=0; i<(XRES+BARSIZE)*YRES; i++)
	{
		r = PIXR(src[i]);
		g = PIXG(src[i]);
		b = PIXB(src[i]);
		if (r>0)
			r--;
		if (g>0)
			g--;
		if (b>0)
			b--;
		dst[i] = PIXRGB(r,g,b);
	}
}

void render_zoom(pixel *img) //draws the zoom box
{
	int x, y, i, j;
	pixel pix;
	drawrect(img, zoom_wx-2, zoom_wy-2, ZSIZE*ZFACTOR+2, ZSIZE*ZFACTOR+2, 192, 192, 192, 255);
	drawrect(img, zoom_wx-1, zoom_wy-1, ZSIZE*ZFACTOR, ZSIZE*ZFACTOR, 0, 0, 0, 255);
	clearrect(img, zoom_wx, zoom_wy, ZSIZE*ZFACTOR, ZSIZE*ZFACTOR);
	for (j=0; j<ZSIZE; j++)
		for (i=0; i<ZSIZE; i++)
		{
			pix = img[(j+zoom_y)*(XRES+BARSIZE)+(i+zoom_x)];
			for (y=0; y<ZFACTOR-1; y++)
				for (x=0; x<ZFACTOR-1; x++)
					img[(j*ZFACTOR+y+zoom_wy)*(XRES+BARSIZE)+(i*ZFACTOR+x+zoom_wx)] = pix;
		}
	if (zoom_en)
	{
		for (j=-1; j<=ZSIZE; j++)
		{
			xor_pixel(zoom_x+j, zoom_y-1, img);
			xor_pixel(zoom_x+j, zoom_y+ZSIZE, img);
		}
		for (j=0; j<ZSIZE; j++)
		{
			xor_pixel(zoom_x-1, zoom_y+j, img);
			xor_pixel(zoom_x+ZSIZE, zoom_y+j, img);
		}
	}
}

//gets the thumbnail preview for stamps
pixel *prerender_save(void *save, int size, int *width, int *height)
{
	unsigned char *d,*c=save;
	int i,j,k,x,y,rx,ry,p=0;
	int bw,bh,w,h,new_format = 0;
	pixel *fb;

	if (size<16)
		return NULL;
	if (!(c[2]==0x43 && c[1]==0x75 && c[0]==0x66) && !(c[2]==0x76 && c[1]==0x53 && c[0]==0x50))
		return NULL;
	if (c[2]==0x43 && c[1]==0x75 && c[0]==0x66) {
		new_format = 1;
	}
	if (c[4]>SAVE_VERSION)
		return NULL;

	bw = c[6];
	bh = c[7];
	w = bw*CELL;
	h = bh*CELL;

	if (c[5]!=CELL)
		return NULL;

	i = (unsigned)c[8];
	i |= ((unsigned)c[9])<<8;
	i |= ((unsigned)c[10])<<16;
	i |= ((unsigned)c[11])<<24;
	d = malloc(i);
	if (!d)
		return NULL;
	fb = calloc(w*h, PIXELSIZE);
	if (!fb)
	{
		free(d);
		return NULL;
	}

	if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+12), size-12, 0, 0))
		goto corrupt;
	size = i;

	if (size < bw*bh)
		goto corrupt;

	k = 0;
	for (y=0; y<bh; y++)
		for (x=0; x<bw; x++)
		{
			rx = x*CELL;
			ry = y*CELL;
			switch (d[p])
			{
			case 1:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case 2:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case 3:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(j%2) && !(i%2))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0xC0C0C0);
				break;
			case 4:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x8080FF);
				k++;
				break;
			case 6:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0xFF8080);
				break;
			case 7:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(i&j&1))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case 8:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(j%2) && !(i%2))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0xC0C0C0);
						else
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case WL_WALL:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case WL_DESTROYALL:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case WL_ALLOWLIQUID:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(j%2) && !(i%2))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0xC0C0C0);
				break;
			case WL_FAN:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0x8080FF);
				k++;
				break;
			case WL_DETECT:
				for (j=0; j<CELL; j+=2)
					for (i=(j>>1)&1; i<CELL; i+=2)
						fb[(ry+j)*w+(rx+i)] = PIXPACK(0xFF8080);
				break;
			case WL_EWALL:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(i&j&1))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			case WL_WALLELEC:
				for (j=0; j<CELL; j++)
					for (i=0; i<CELL; i++)
						if (!(j%2) && !(i%2))
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0xC0C0C0);
						else
							fb[(ry+j)*w+(rx+i)] = PIXPACK(0x808080);
				break;
			}
			p++;
		}
	p += 2*k;
	if (p>=size)
		goto corrupt;

	for (y=0; y<h; y++)
		for (x=0; x<w; x++)
		{
			if (p >= size)
				goto corrupt;
			j=d[p++];
			if (j<PT_NUM && j>0)
			{
				if (j==PT_STKM || j==PT_STKM2)
				{
					pixel lc, hc=PIXRGB(255, 224, 178);
					if (j==PT_STKM) lc = PIXRGB(255, 255, 255);
					else lc = PIXRGB(100, 100, 255);
					//only need to check upper bound of y coord - lower bounds and x<w are checked in draw_line
					draw_line(fb , x-2, y-2, x+2, y-2, PIXR(hc), PIXG(hc), PIXB(hc), w);
					if (y+2<h)
					{
						draw_line(fb , x-2, y+2, x+2, y+2, PIXR(hc), PIXG(hc), PIXB(hc), w);
						draw_line(fb , x-2, y-2, x-2, y+2, PIXR(hc), PIXG(hc), PIXB(hc), w);
						draw_line(fb , x+2, y-2, x+2, y+2, PIXR(hc), PIXG(hc), PIXB(hc), w);
					}
					if (y+6<h)
					{
						draw_line(fb , x, y+3, x-1, y+6, PIXR(lc), PIXG(lc), PIXB(lc), w);
						draw_line(fb , x, y+3, x+1, y+6, PIXR(lc), PIXG(lc), PIXB(lc), w);
					}
					if (y+12<h)
					{
						draw_line(fb , x-1, y+6, x-3, y+12, PIXR(lc), PIXG(lc), PIXB(lc), w);
						draw_line(fb , x+1, y+6, x+3, y+12, PIXR(lc), PIXG(lc), PIXB(lc), w);
					}
				}
				else
					fb[y*w+x] = ptypes[j].pcolors;
			}
		}

	free(d);
	*width = w;
	*height = h;
	return fb;

corrupt:
	free(d);
	free(fb);
	return NULL;
}

int render_thumb(void *thumb, int size, int bzip2, pixel *vid_buf, int px, int py, int scl)
{
	unsigned char *d,*c=thumb;
	int i,j,x,y,a,t,r,g,b,sx,sy;

	if (bzip2)
	{
		if (size<16)
			return 1;
		if (c[3]!=0x74 || c[2]!=0x49 || c[1]!=0x68 || c[0]!=0x53)
			return 1;
		if (c[4]>PT_NUM)
			return 2;
		if (c[5]!=CELL || c[6]!=XRES/CELL || c[7]!=YRES/CELL)
			return 3;
		i = XRES*YRES;
		d = malloc(i);
		if (!d)
			return 1;

		if (BZ2_bzBuffToBuffDecompress((char *)d, (unsigned *)&i, (char *)(c+8), size-8, 0, 0))
			return 1;
		size = i;
	}
	else
		d = c;

	if (size < XRES*YRES)
	{
		if (bzip2)
			free(d);
		return 1;
	}

	sy = 0;
	for (y=0; y+scl<=YRES; y+=scl)
	{
		sx = 0;
		for (x=0; x+scl<=XRES; x+=scl)
		{
			a = 0;
			r = g = b = 0;
			for (j=0; j<scl; j++)
				for (i=0; i<scl; i++)
				{
					t = d[(y+j)*XRES+(x+i)];
					if (t==0xFF)
					{
						r += 256;
						g += 256;
						b += 256;
						a += 2;
					}
					else if (t)
					{
						if (t>=PT_NUM)
							goto corrupt;
						r += PIXR(ptypes[t].pcolors);
						g += PIXG(ptypes[t].pcolors);
						b += PIXB(ptypes[t].pcolors);
						a ++;
					}
				}
			if (a)
			{
				a = 256/a;
				r = (r*a)>>8;
				g = (g*a)>>8;
				b = (b*a)>>8;
			}

			drawpixel(vid_buf, px+sx, py+sy, r, g, b, 255);
			sx++;
		}
		sy++;
	}

	if (bzip2)
		free(d);
	return 0;

corrupt:
	if (bzip2)
		free(d);
	return 1;
}

//draws the cursor
void render_cursor(pixel *vid, int x, int y, int t, int rx, int ry)
{
	int i,j,c;
	if (t<PT_NUM||(t&0xFF)==PT_LIFE||t==SPC_AIR||t==SPC_HEAT||t==SPC_COOL||t==SPC_VACUUM||t==SPC_WIND||t==SPC_PGRV||t==SPC_NGRV)
	{
		if (rx<=0)
			xor_pixel(x, y, vid);
		else if (ry<=0)
			xor_pixel(x, y, vid);
		if (rx+ry<=0)
			xor_pixel(x, y, vid);
		else if (CURRENT_BRUSH==SQUARE_BRUSH)
		{
			for (j=0; j<=ry; j++)
				for (i=0; i<=rx; i++)
					if (i*j<=ry*rx && ((i+1)>rx || (j+1)>ry))
					{
						xor_pixel(x+i, y+j, vid);
						xor_pixel(x-i, y-j, vid);
						if (i&&j)xor_pixel(x+i, y-j, vid);
						if (i&&j)xor_pixel(x-i, y+j, vid);
					}
		}
		else if (CURRENT_BRUSH==CIRCLE_BRUSH)
		{
			for (j=0; j<=ry; j++)
				for (i=0; i<=rx; i++)
					if (pow(i,2)*pow(ry,2)+pow(j,2)*pow(rx,2)<=pow(rx,2)*pow(ry,2) &&
					  (pow(i+1,2)*pow(ry,2)+pow(j,2)*pow(rx,2)>pow(rx,2)*pow(ry,2) ||
					   pow(i,2)*pow(ry,2)+pow(j+1,2)*pow(rx,2)>pow(rx,2)*pow(ry,2)))
					{
						xor_pixel(x+i, y+j, vid);
						if (j) xor_pixel(x+i, y-j, vid);
						if (i) xor_pixel(x-i, y+j, vid);
						if (i&&j) xor_pixel(x-i, y-j, vid);
					}
		}
		else if (CURRENT_BRUSH==TRI_BRUSH)
 		{
			for (j=-ry; j<=ry; j++)
				for (i=-rx; i<=0; i++)
					if ((j <= ry ) && ( j >= (((-2.0*ry)/(rx))*i)-ry ) && (j+1>ry || ( j-1 < (((-2.0*ry)/(rx))*i)-ry )) )
						{
							xor_pixel(x+i, y+j, vid);
							if (i) xor_pixel(x-i, y+j, vid);
						}
		}
	}
	else //wall cursor
	{
		int tc;
		c = (rx/CELL) * CELL;
		x = (x/CELL) * CELL;
		y = (y/CELL) * CELL;

		tc = !((c%(CELL*2))==0);

		x -= c/2;
		y -= c/2;

		x += tc*(CELL/2);
		y += tc*(CELL/2);

		for (i=0; i<CELL+c; i++)
		{
			xor_pixel(x+i, y, vid);
			xor_pixel(x+i, y+CELL+c-1, vid);
		}
		for (i=1; i<CELL+c-1; i++)
		{
			xor_pixel(x, y+i, vid);
			xor_pixel(x+CELL+c-1, y+i, vid);
		}
	}
}

int sdl_open(void)
{
	if (SDL_Init(SDL_INIT_VIDEO)<0)
	{
		fprintf(stderr, "Initializing SDL: %s\n", SDL_GetError());
		return 0;
	}
	atexit(SDL_Quit);
#if defined(OGLR)
	sdl_scrn=SDL_SetVideoMode(XRES*sdl_scale + BARSIZE*sdl_scale,YRES*sdl_scale + MENUSIZE*sdl_scale,32,SDL_OPENGL);
	SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
#else
#ifdef PIX16
	if (kiosk_enable)
		sdl_scrn=SDL_SetVideoMode(XRES*sdl_scale + BARSIZE*sdl_scale,YRES*sdl_scale + MENUSIZE*sdl_scale,16,SDL_FULLSCREEN|SDL_SWSURFACE);
	else
		sdl_scrn=SDL_SetVideoMode(XRES*sdl_scale + BARSIZE*sdl_scale,YRES*sdl_scale + MENUSIZE*sdl_scale,16,SDL_SWSURFACE);
#else
	if (kiosk_enable)
		sdl_scrn=SDL_SetVideoMode(XRES*sdl_scale + BARSIZE*sdl_scale,YRES*sdl_scale + MENUSIZE*sdl_scale,32,SDL_FULLSCREEN|SDL_SWSURFACE);
	else
		sdl_scrn=SDL_SetVideoMode(XRES*sdl_scale + BARSIZE*sdl_scale,YRES*sdl_scale + MENUSIZE*sdl_scale,32,SDL_SWSURFACE);
#endif
#endif
	if (!sdl_scrn)
	{
		fprintf(stderr, "Creating window: %s\n", SDL_GetError());
		return 0;
	}
	SDL_WM_SetCaption("The Powder Toy", "Powder Toy");
	sdl_seticon();
	SDL_EnableUNICODE(1);
	//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
#if (defined(LIN32) || defined(LIN64)) && defined(SDL_VIDEO_DRIVER_X11)
	SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
	SDL_VERSION(&sdl_wminfo.version);
	SDL_GetWMInfo(&sdl_wminfo);
	sdl_wminfo.info.x11.lock_func();
	XA_CLIPBOARD = XInternAtom(sdl_wminfo.info.x11.display, "CLIPBOARD", 1);
	XA_TARGETS = XInternAtom(sdl_wminfo.info.x11.display, "TARGETS", 1);
	sdl_wminfo.info.x11.unlock_func();
#endif
	return 1;
}

int draw_debug_info(pixel* vid, int lm, int lx, int ly, int cx, int cy, int line_x, int line_y)
{
	char infobuf[256];
	if(debug_flags & DEBUG_DRAWTOOL)
	{
		if(lm == 1) //Line tool
		{
			blend_line(vid, 0, line_y, XRES, line_y, 255, 255, 255, 120);
			blend_line(vid, line_x, 0, line_x, YRES, 255, 255, 255, 120);
	
			blend_line(vid, 0, ly, XRES, ly, 255, 255, 255, 120);
			blend_line(vid, lx, 0, lx, YRES, 255, 255, 255, 120);
			
			sprintf(infobuf, "%d x %d", lx, ly);
			drawtext_outline(vid, lx+(lx>line_x?3:-textwidth(infobuf)-3), ly+(ly<line_y?-10:3), infobuf, 255, 255, 255, 200, 0, 0, 0, 120);
			
			sprintf(infobuf, "%d x %d", line_x, line_y);
			drawtext_outline(vid, line_x+(lx<line_x?3:-textwidth(infobuf)-2), line_y+(ly>line_y?-10:3), infobuf, 255, 255, 255, 200, 0, 0, 0, 120);
			
			sprintf(infobuf, "%d", abs(line_x-lx));
			drawtext_outline(vid, (line_x+lx)/2-textwidth(infobuf)/2, line_y+(ly>line_y?-10:3), infobuf, 255, 255, 255, 200, 0, 0, 0, 120);
			
			sprintf(infobuf, "%d", abs(line_y-ly));
			drawtext_outline(vid, line_x+(lx<line_x?3:-textwidth(infobuf)-2), (line_y+ly)/2-3, infobuf, 255, 255, 255, 200, 0, 0, 0, 120);
		}
	}
	if(debug_flags & DEBUG_PARTS)
	{
		int i = 0, x = 0, y = 0, lpx = 0, lpy = 0;
		sprintf(infobuf, "%d/%d (%.2f%%)", parts_lastActiveIndex, NPART, (((float)parts_lastActiveIndex)/((float)NPART))*100.0f);
		for(i = 0; i < NPART; i++){
			if(parts[i].type){
				drawpixel(vid, x, y, 255, 255, 255, 180);
			} else {
				drawpixel(vid, x, y, 0, 0, 0, 180);
			}
			if(i == parts_lastActiveIndex)
			{
				lpx = x;
				lpy = y;
			}
			x++;
			if(x>=XRES){
				y++;
				x = 0;
			}
		}
		draw_line(vid, 0, lpy, XRES, lpy, 0, 255, 120, XRES+BARSIZE);
		draw_line(vid, lpx, 0, lpx, YRES, 0, 255, 120, XRES+BARSIZE);
		drawpixel(vid, lpx, lpy, 255, 50, 50, 220);
				
		drawpixel(vid, lpx+1, lpy, 255, 50, 50, 120);
		drawpixel(vid, lpx-1, lpy, 255, 50, 50, 120);
		drawpixel(vid, lpx, lpy+1, 255, 50, 50, 120);
		drawpixel(vid, lpx, lpy-1, 255, 50, 50, 120);
		
		fillrect(vid, 7, YRES-26, textwidth(infobuf)+5, 14, 0, 0, 0, 180);		
		drawtext(vid, 10, YRES-22, infobuf, 255, 255, 255, 255);
	}
}