#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); } }