diff options
| author | Simon Robertshaw <simon@hardwired.org.uk> | 2012-11-17 19:44:09 (GMT) |
|---|---|---|
| committer | Simon Robertshaw <simon@hardwired.org.uk> | 2012-11-17 19:44:09 (GMT) |
| commit | 058a2edd75debbd0297f92572316daa704bd379f (patch) | |
| tree | ad303f091f9a08b209b91eb34a9fcad996a3de69 /src/graphics | |
| parent | e3594aba9e05c6865d396418c028049cda92c2f3 (diff) | |
| parent | 7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff) | |
| download | powder-058a2edd75debbd0297f92572316daa704bd379f.zip powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz | |
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/graphics')
| -rw-r--r-- | src/graphics/DrawMethodsDef.inc | 17 | ||||
| -rw-r--r-- | src/graphics/Graphics.cpp | 1028 | ||||
| -rw-r--r-- | src/graphics/Graphics.h | 248 | ||||
| -rw-r--r-- | src/graphics/OpenGLDrawMethods.inl | 350 | ||||
| -rw-r--r-- | src/graphics/OpenGLGraphics.cpp | 95 | ||||
| -rw-r--r-- | src/graphics/OpenGLHeaders.h | 24 | ||||
| -rw-r--r-- | src/graphics/RasterDrawMethods.inl | 366 | ||||
| -rw-r--r-- | src/graphics/RasterGraphics.cpp | 45 | ||||
| -rw-r--r-- | src/graphics/Renderer.cpp | 2719 | ||||
| -rw-r--r-- | src/graphics/Renderer.h | 184 |
10 files changed, 5076 insertions, 0 deletions
diff --git a/src/graphics/DrawMethodsDef.inc b/src/graphics/DrawMethodsDef.inc new file mode 100644 index 0000000..4aee0c9 --- /dev/null +++ b/src/graphics/DrawMethodsDef.inc @@ -0,0 +1,17 @@ + int drawtext(int x, int y, const char *s, int r, int g, int b, int a); + int drawtext(int x, int y, std::string s, int r, int g, int b, int a); + int drawchar(int x, int y, int c, int r, int g, int b, int a); + int addchar(int x, int y, int c, int r, int g, int b, int a); + + void xor_pixel(int x, int y); + void xor_line(int x, int y, int x2, int y2); + void xor_rect(int x, int y, int width, int height); + void xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h); + + void draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a); + void drawrect(int x, int y, int width, int height, int r, int g, int b, int a); + void fillrect(int x, int y, int width, int height, int r, int g, int b, int a); + void clearrect(int x, int y, int width, int height); + void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); + + void draw_image(pixel *img, int x, int y, int w, int h, int a);
\ No newline at end of file diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp new file mode 100644 index 0000000..11dcac3 --- /dev/null +++ b/src/graphics/Graphics.cpp @@ -0,0 +1,1028 @@ +#include <cmath> +#include <iostream> +#include <bzlib.h> +#include <string> +#include "Config.h" +#include "Misc.h" +#include "Graphics.h" +#define INCLUDE_FONTDATA +#include "font.h" + +VideoBuffer::VideoBuffer(int width, int height): + Width(width), + Height(height) +{ + Buffer = new pixel[width*height]; + std::fill(Buffer, Buffer+(width*height), 0); +}; + +VideoBuffer::VideoBuffer(const VideoBuffer & old): + Width(old.Width), + Height(old.Height) +{ + Buffer = new pixel[old.Width*old.Height]; + std::copy(old.Buffer, old.Buffer+(old.Width*old.Height), Buffer); +}; + +VideoBuffer::VideoBuffer(VideoBuffer * old): + Width(old->Width), + Height(old->Height) +{ + Buffer = new pixel[old->Width*old->Height]; + std::copy(old->Buffer, old->Buffer+(old->Width*old->Height), Buffer); +}; + +void VideoBuffer::Resize(float factor, bool resample) +{ + int newWidth = ((float)Width)*factor; + int newHeight = ((float)Height)*factor; + pixel * newBuffer; + if(resample) + newBuffer = Graphics::resample_img(Buffer, Width, Height, newWidth, newHeight); + else + newBuffer = Graphics::resample_img_nn(Buffer, Width, Height, newWidth, newHeight); + + if(newBuffer) + { + delete[] Buffer; + Buffer = newBuffer; + Width = newWidth; + Height = newHeight; + } +} + +int VideoBuffer::SetCharacter(int x, int y, int c, int r, int g, int b, int a) +{ + 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; + } + SetPixel(x+i, y+j, r, g, b, ((ba&3)*a)/3); + ba >>= 2; + bn -= 2; + } + return x + w; +} + +int VideoBuffer::BlendCharacter(int x, int y, int c, int r, int g, int b, int a) +{ + 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; + } + BlendPixel(x+i, y+j, r, g, b, ((ba&3)*a)/3); + ba >>= 2; + bn -= 2; + } + return x + w; +} + +int VideoBuffer::AddCharacter(int x, int y, int c, int r, int g, int b, int a) +{ + 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; + } + AddPixel(x+i, y+j, r, g, b, ((ba&3)*a)/3); + ba >>= 2; + bn -= 2; + } + return x + w; +} + +VideoBuffer::~VideoBuffer() +{ + delete[] Buffer; +}; + +/** + * Common graphics functions, mostly static methods that provide + * encoding/decoding of different formats and font metrics + */ + +char * Graphics::GenerateGradient(pixel * colours, float * points, int pointcount, int size) +{ + int cp, i, j; + pixel ptemp; + char * newdata = (char*)malloc(size * 3); + float poss, pose, temp; + memset(newdata, 0, size*3); + //Sort the Colours and Points + for (i = (pointcount - 1); i > 0; i--) + { + for (j = 1; j <= i; j++) + { + if (points[j-1] > points[j]) + { + temp = points[j-1]; + points[j-1] = points[j]; + points[j] = temp; + + ptemp = colours[j-1]; + colours[j-1] = colours[j]; + colours[j] = ptemp; + } + } + } + i = 0; + j = 1; + poss = points[i]; + pose = points[j]; + for (cp = 0; cp < size; cp++) + { + float cpos = (float)cp / (float)size, ccpos, cccpos; + if(cpos > pose && j+1 < pointcount) + { + poss = points[++i]; + pose = points[++j]; + } + ccpos = cpos - poss; + cccpos = ccpos / (pose - poss); + if(cccpos > 1.0f) + cccpos = 1.0f; + newdata[(cp*3)] = PIXR(colours[i])*(1.0f-cccpos) + PIXR(colours[j])*(cccpos); + newdata[(cp*3)+1] = PIXG(colours[i])*(1.0f-cccpos) + PIXG(colours[j])*(cccpos); + newdata[(cp*3)+2] = PIXB(colours[i])*(1.0f-cccpos) + PIXB(colours[j])*(cccpos); + } + return newdata; +} + +void *Graphics::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 = (unsigned char*)calloc(1, w*h); + unsigned char *green_chan = (unsigned char*)calloc(1, w*h); + unsigned char *blue_chan = (unsigned char*)calloc(1, w*h); + unsigned char *data = (unsigned char*)malloc(((w*h)*3)+8); + unsigned char *result = (unsigned char*)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) != 0){ + free(data); + free(result); + return NULL; + } + + *result_size = i+8; + free(data); + return result; +} + +pixel *Graphics::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 = (unsigned char*)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 = (unsigned char*)calloc(1, (width*height)*3); + red_chan = (unsigned char*)calloc(1, width*height); + green_chan = (unsigned char*)calloc(1, width*height); + blue_chan = (unsigned char *)calloc(1, width*height); + result = (pixel *)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 *Graphics::resample_img_nn(pixel * src, int sw, int sh, int rw, int rh) +{ + int y, x; + pixel *q = NULL; + q = (pixel *)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 *Graphics::resample_img(pixel *src, int sw, int sh, int rw, int rh) +{ +#ifdef DEBUG + std::cout << "Resampling " << sw << "x" << sh << " to " << rw << "x" << rh << std::endl; +#endif + bool stairstep = false; + if(rw < sw || rh < sh) + { + float fx = (float)(((float)sw)/((float)rw)); + float fy = (float)(((float)sh)/((float)rh)); + + int fxint, fyint; + double fxintp_t, fyintp_t; + + float fxf = modf(fx, &fxintp_t), fyf = modf(fy, &fyintp_t); + fxint = fxintp_t; + fyint = fyintp_t; + + if(((fxint & (fxint-1)) == 0 && fxf < 0.1f) || ((fyint & (fyint-1)) == 0 && fyf < 0.1f)) + stairstep = true; + +#ifdef DEBUG + if(stairstep) + std::cout << "Downsampling by " << fx << "x" << fy << " using stairstepping" << std::endl; + else + std::cout << "Downsampling by " << fx << "x" << fy << " without stairstepping" << std::endl; +#endif + } + + int y, x, fxceil, fyceil; + //int i,j,x,y,w,h,r,g,b,c; + pixel *q = NULL; + if(rw == sw && rh == sh){ + //Don't resample + q = (pixel *)malloc(rw*rh*PIXELSIZE); + memcpy(q, src, rw*rh*PIXELSIZE); + } else if(!stairstep) { + float fx, fy, fyc, fxc; + double intp; + pixel tr, tl, br, bl; + q = (pixel *)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 = (pixel *)malloc(sw*sh*PIXELSIZE); + memcpy(oq, src, sw*sh*PIXELSIZE); + rw = sw; + rh = sh; + while(rrw != rw && rrh != rh){ + if(rw > rrw) + rw *= 0.7; + if(rh > rrh) + rh *= 0.7; + if(rw <= rrw) + rw = rrw; + if(rh <= rrh) + rh = rrh; + q = (pixel *)malloc(rw*rh*PIXELSIZE); + //Bilinear interpolation + 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 *Graphics::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 = (pixel *)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; +} + +int Graphics::textwidth(const char *s) +{ + int x = 0; + for (; *s; s++) + x += font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + return x-1; +} + +int Graphics::CharWidth(char c) +{ + return font_data[font_ptrs[(int)c]]; +} + +int Graphics::textnwidth(char *s, int n) +{ + int x = 0; + for (; *s; s++) + { + if (!n) + break; + if(((char)*s)=='\b') + { + if(!s[1]) break; + s++; + continue; + } else if(*s == '\x0F') { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + continue; + } + x += font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + n--; + } + return x-1; +} + +void Graphics::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 Graphics::textwidthx(char *s, int w) +{ + int x=0,n=0,cw; + for (; *s; s++) + { + if((char)*s == '\b') + { + if(!s[1]) break; + s++; + continue; + } else if (*s == '\x0F') + { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + continue; + } + cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + if (x+(cw/2) >= w) + break; + x += cw; + n++; + } + return n; +} + +int Graphics::PositionAtCharIndex(char *s, int charIndex, int & positionX, int & positionY) +{ + int x = 0, y = 0, lines = 1; + for (; *s; s++) + { + if (!charIndex) + break; + if(*s == '\n') { + lines++; + x = 0; + y += FONT_H+2; + charIndex--; + continue; + } else if(*s =='\b') { + if(!s[1]) break; + s++; + charIndex-=2; + continue; + } else if(*s == '\x0F') { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + charIndex-=4; + continue; + } + x += font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + charIndex--; + } + positionX = x; + positionY = y; + return lines; +} + +int Graphics::CharIndexAtPosition(char *s, int positionX, int positionY) +{ + int x=0, y=0,charIndex=0,cw; + for (; *s; s++) + { + if(*s == '\n') { + x = 0; + y += FONT_H+2; + charIndex++; + continue; + } else if(*s == '\b') { + if(!s[1]) break; + s++; + charIndex+=2; + continue; + } else if (*s == '\x0F') { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + charIndex+=4; + continue; + } + cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + if ((x+(cw/2) >= positionX && y+FONT_H >= positionY) || y > positionY) + break; + x += cw; + charIndex++; + } + return charIndex; +} + + +int Graphics::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 Graphics::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') + { + if(!s[1]) break; + s++; + } + else if (*s == '\x0F') + { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + } + else + { + cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + if (x+cw>=width) + { + x = 0; + height += FONT_H+2; + } + x += cw; + } + } + } + return height; +} + +void Graphics::textsize(const char * s, int & width, int & height) +{ + if(!strlen(s)) + { + width = 0; + height = FONT_H; + return; + } + + int cHeight = FONT_H, cWidth = 0, lWidth = 0; + for (; *s; s++) + { + if (*s == '\n') + { + cWidth = 0; + cHeight += FONT_H+2; + } + else if (*s == '\x0F') + { + if(!s[1] || !s[2] || !s[1]) break; + s+=3; + } + else if (*s == '\b') + { + if(!s[1]) break; + s++; + } + else + { + cWidth += font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + if(cWidth>lWidth) + lWidth = cWidth; + } + } + width = lWidth; + height = cHeight; +} + +void Graphics::draw_icon(int x, int y, Icon icon, unsigned char alpha, bool invert) +{ + y--; + switch(icon) + { + case IconOpen: + if(invert) + drawchar(x, y, 0x81, 0, 0, 0, alpha); + else + drawchar(x, y, 0x81, 255, 255, 255, alpha); + break; + case IconReload: + if(invert) + drawchar(x, y, 0x91, 0, 0, 0, alpha); + else + drawchar(x, y, 0x91, 255, 255, 255, alpha); + break; + case IconSave: + if(invert) + drawchar(x, y, 0x82, 0, 0, 0, alpha); + else + drawchar(x, y, 0x82, 255, 255, 255, alpha); + break; + case IconVoteUp: + if(invert) + drawchar(x, y, 0xCB, 0, 100, 0, alpha); + else + drawchar(x, y, 0xCB, 0, 187, 18, alpha); + break; + case IconVoteDown: + if(invert) + drawchar(x, y, 0xCA, 100, 10, 0, alpha); + else + drawchar(x, y, 0xCA, 187, 40, 0, alpha); + break; + case IconTag: + if(invert) + drawchar(x, y, 0x83, 0, 0, 0, alpha); + else + drawchar(x, y, 0x83, 255, 255, 255, alpha); + break; + case IconNew: + if(invert) + drawchar(x, y, 0x92, 0, 0, 0, alpha); + else + drawchar(x, y, 0x92, 255, 255, 255, alpha); + break; + case IconLogin: + if(invert) + drawchar(x, y+1, 0x84, 0, 0, 0, alpha); + else + drawchar(x, y+1, 0x84, 255, 255, 255, alpha); + break; + case IconSimulationSettings: + if(invert) + drawchar(x, y+1, 0xCF, 0, 0, 0, alpha); + else + drawchar(x, y+1, 0xCF, 255, 255, 255, alpha); + break; + case IconRenderSettings: + if(invert) + { + drawchar(x, y+1, 0xD8, 255, 0, 0, alpha); + drawchar(x, y+1, 0xD9, 0, 255, 0, alpha); + drawchar(x, y+1, 0xDA, 0, 0, 255, alpha); + } + else + { + addchar(x, y+1, 0xD8, 255, 0, 0, alpha); + addchar(x, y+1, 0xD9, 0, 255, 0, alpha); + addchar(x, y+1, 0xDA, 0, 0, 255, alpha); + } + break; + case IconPause: + if(invert) + drawchar(x, y, 0x90, 0, 0, 0, alpha); + else + drawchar(x, y, 0x90, 255, 255, 255, alpha); + break; + case IconFavourite: + if(invert) + drawchar(x, y, 0xCC, 100, 80, 32, alpha); + else + drawchar(x, y, 0xCC, 192, 160, 64, alpha); + break; + case IconReport: + if(invert) + drawchar(x, y, 0xE3, 140, 140, 0, alpha); + else + drawchar(x, y, 0xE3, 255, 255, 0, alpha); + break; + case IconUsername: + if(invert) + { + drawchar(x, y, 0x8B, 32, 64, 128, alpha); + drawchar(x, y, 0x8A, 0, 0, 0, alpha); + } + else + { + drawchar(x, y, 0x8B, 32, 64, 128, alpha); + drawchar(x, y, 0x8A, 255, 255, 255, alpha); + } + break; + case IconPassword: + if(invert) + { + drawchar(x, y, 0x8C, 160, 144, 32, alpha); + drawchar(x, y, 0x84, 0, 0, 0, alpha); + } + else + { + drawchar(x, y, 0x8C, 160, 144, 32, alpha); + drawchar(x, y, 0x84, 255, 255, 255, alpha); + } + break; + case IconClose: + if(invert) + drawchar(x, y, 0xAA, 20, 20, 20, alpha); + else + drawchar(x, y, 0xAA, 230, 230, 230, alpha); + break; + case IconVoteSort: + if (invert) + { + drawchar(x, y, 0xA9, 44, 48, 32, alpha); + drawchar(x, y, 0xA8, 32, 44, 32, alpha); + drawchar(x, y, 0xA7, 128, 128, 128, alpha); + } + else + { + drawchar(x, y, 0xA9, 144, 48, 32, alpha); + drawchar(x, y, 0xA8, 32, 144, 32, alpha); + drawchar(x, y, 0xA7, 255, 255, 255, alpha); + } + break; + case IconDateSort: + if (invert) + { + drawchar(x, y, 0xA6, 32, 32, 32, alpha); + } + else + { + drawchar(x, y, 0xA6, 255, 255, 255, alpha); + } + break; + case IconMyOwn: + if (invert) + { + drawchar(x, y, 0x94, 192, 160, 64, alpha); + drawchar(x, y, 0x93, 32, 32, 32, alpha); + } + else + { + drawchar(x, y, 0x94, 192, 160, 64, alpha); + drawchar(x, y, 0x93, 255, 255, 255, alpha); + } + break; + case IconSearch: + drawchar(x, y, 0x8E, 30, 30, 180, alpha); + drawchar(x, y, 0x8F, 255, 255, 255, alpha); + break; + case IconDelete: + if(invert) + { + drawchar(x, y, 0x86, 159, 47, 31, alpha); + drawchar(x, y, 0x85, 0, 0, 0, alpha); + } + else + { + drawchar(x, y, 0x86, 159, 47, 31, alpha); + drawchar(x, y, 0x85, 255, 255, 255, alpha); + } + break; + case IconAdd: + if(invert) + { + drawchar(x, y, 0x86, 32, 144, 32, alpha); + drawchar(x, y, 0x89, 0, 0, 0, alpha); + } + else + { + drawchar(x, y, 0x86, 32, 144, 32, alpha); + drawchar(x, y, 0x89, 255, 255, 255, alpha); + } + break; + case IconVelocity: + drawchar(x+1, y, 0x98, 128, 160, 255, alpha); + break; + case IconPressure: + if(invert) + drawchar(x+1, y+1, 0x99, 180, 160, 16, alpha); + else + drawchar(x+1, y+1, 0x99, 255, 212, 32, alpha); + break; + case IconPersistant: + if(invert) + drawchar(x+1, y+1, 0x9A, 20, 20, 20, alpha); + else + drawchar(x+1, y+1, 0x9A, 212, 212, 212, alpha); + break; + case IconFire: + drawchar(x+1, y+1, 0x9B, 255, 0, 0, alpha); + drawchar(x+1, y+1, 0x9C, 255, 255, 64, alpha); + break; + case IconBlob: + if(invert) + drawchar(x+1, y, 0xBF, 55, 180, 55, alpha); + else + drawchar(x+1, y, 0xBF, 55, 255, 55, alpha); + break; + case IconHeat: + drawchar(x+3, y, 0xBE, 255, 0, 0, alpha); + if(invert) + drawchar(x+3, y, 0xBD, 0, 0, 0, alpha); + else + drawchar(x+3, y, 0xBD, 255, 255, 255, alpha); + break; + case IconBlur: + if(invert) + drawchar(x+1, y, 0xC4, 50, 70, 180, alpha); + else + drawchar(x+1, y, 0xC4, 100, 150, 255, alpha); + break; + case IconGradient: + if(invert) + drawchar(x+1, y+1, 0xD3, 255, 50, 255, alpha); + else + drawchar(x+1, y+1, 0xD3, 205, 50, 205, alpha); + break; + case IconLife: + if(invert) + drawchar(x, y+1, 0xE0, 0, 0, 0, alpha); + else + drawchar(x, y+1, 0xE0, 255, 255, 255, alpha); + break; + case IconEffect: + drawchar(x+1, y, 0xE1, 255, 255, 160, alpha); + break; + case IconGlow: + drawchar(x+1, y, 0xDF, 200, 255, 255, alpha); + break; + case IconWarp: + drawchar(x+1, y, 0xDE, 255, 255, 255, alpha); + break; + case IconBasic: + if(invert) + drawchar(x+1, y+1, 0xDB, 50, 50, 0, alpha); + else + drawchar(x+1, y+1, 0xDB, 255, 255, 200, alpha); + break; + case IconAltAir: + if(invert) { + drawchar(x+1, y+1, 0xD4, 180, 55, 55, alpha); + drawchar(x+1, y+1, 0xD5, 55, 180, 55, alpha); + } else { + drawchar(x+1, y+1, 0xD4, 255, 55, 55, alpha); + drawchar(x+1, y+1, 0xD5, 55, 255, 55, alpha); + } + break; + default: + if(invert) + drawchar(x, y, 't', 0, 0, 0, alpha); + else + drawchar(x, y, 't', 255, 255, 255, alpha); + break; + } +} + +pixel *Graphics::render_packed_rgb(void *image, int width, int height, int cmp_size) +{ + unsigned char *tmp; + pixel *res; + int i; + + tmp = (unsigned char *)malloc(width*height*3); + if (!tmp) + return NULL; + res = (pixel *)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 Graphics::draw_image(const VideoBuffer & vidBuf, int x, int y, int a) +{ + draw_image(vidBuf.Buffer, x, y, vidBuf.Width, vidBuf.Height, a); +} + +void Graphics::draw_image(VideoBuffer * vidBuf, int x, int y, int a) +{ + draw_image(vidBuf->Buffer, x, y, vidBuf->Width, vidBuf->Height, a); +} + +VideoBuffer Graphics::DumpFrame() +{ +#ifdef OGLI +#else + VideoBuffer newBuffer(XRES+BARSIZE, YRES+MENUSIZE); + std::copy(vid, vid+((XRES+BARSIZE)*(YRES+MENUSIZE)), newBuffer.Buffer); + return newBuffer; +#endif +}
\ No newline at end of file diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h new file mode 100644 index 0000000..53d3ee7 --- /dev/null +++ b/src/graphics/Graphics.h @@ -0,0 +1,248 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +#include <string> +#include <cstdlib> +#include <cstring> +#include <vector> +#if defined(OGLI) +#include "OpenGLHeaders.h" +#endif +#include "Config.h" +//#include "powder.h" + +#ifdef PIX16 +#define PIXELSIZE 2 +#define PIXPACK(x) ((((x)>>8)&0xF800)|(((x)>>5)&0x07E0)|(((x)>>3)&0x001F)) +#define PIXRGB(r,g,b) ((((r)<<8)&0xF800)|(((g)<<3)&0x07E0)|(((b)>>3)&0x001F)) +#define PIXR(x) (((x)>>8)&0xF8) +#define PIXG(x) (((x)>>3)&0xFC) +#define PIXB(x) (((x)<<3)&0xF8) +#else +#define PIXELSIZE 4 +#ifdef PIX32BGR +#define PIXPACK(x) ((((x)>>16)&0x0000FF)|((x)&0x00FF00)|(((x)<<16)&0xFF0000)) +#define PIXRGB(r,g,b) (((b)<<16)|((g)<<8)|((r)))// (((b)<<16)|((g)<<8)|(r)) +#define PIXR(x) ((x)&0xFF) +#define PIXG(x) (((x)>>8)&0xFF) +#define PIXB(x) ((x)>>16) +#else +#ifdef PIX32BGRA +#define PIXPACK(x) ((((x)>>8)&0x0000FF00)|(((x)<<8)&0x00FF0000)|(((x)<<24)&0xFF000000)) +#define PIXRGB(r,g,b) (((b)<<24)|((g)<<16)|((r)<<8)) +#define PIXR(x) (((x)>>8)&0xFF) +#define PIXG(x) (((x)>>16)&0xFF) +#define PIXB(x) (((x)>>24)) +#elif defined(PIX32OGL) +#define PIXPACK(x) (0xFF000000|((x)&0xFFFFFF)) +#define PIXRGB(r,g,b) (0xFF000000|((r)<<16)|((g)<<8)|((b)))// (((b)<<16)|((g)<<8)|(r)) +#define PIXRGBA(r,g,b,a) (((a)<<24)|((r)<<16)|((g)<<8)|((b)))// (((b)<<16)|((g)<<8)|(r)) +#define PIXA(x) (((x)>>24)&0xFF) +#define PIXR(x) (((x)>>16)&0xFF) +#define PIXG(x) (((x)>>8)&0xFF) +#define PIXB(x) ((x)&0xFF) +#else +#define PIXPACK(x) (x) +#define PIXRGB(r,g,b) (((r)<<16)|((g)<<8)|(b)) +#define PIXR(x) ((x)>>16) +#define PIXG(x) (((x)>>8)&0xFF) +#define PIXB(x) ((x)&0xFF) +#endif +#endif +#endif + +#ifdef PIX16 +typedef unsigned short pixel; +#else +typedef unsigned int pixel; +#endif + +//Icon names, see Graphics::draw_icon +enum Icon +{ + NoIcon = 0, + IconOpen, + IconReload, + IconSave, + IconVoteUp, + IconVoteDown, + IconTag, + IconNew, + IconLogin, + IconRenderSettings, + IconSimulationSettings, + IconPause, + IconVoteSort, + IconDateSort, + IconMyOwn, + IconFavourite, + IconSearch, + IconDelete, + IconAdd, + IconReport, + IconUsername, + IconPassword, + IconClose, + IconEffect, + IconFire, + IconGlow, + IconBlur, + IconBlob, + IconBasic, + IconAltAir, + IconPressure, + IconVelocity, + IconWarp, + IconPersistant, + IconHeat, + IconLife, + IconGradient +}; + +//"Graphics lite" - slightly lower performance due to variable size, +class VideoBuffer +{ +public: + pixel * Buffer; + int Width, Height; + + VideoBuffer(const VideoBuffer & old); + VideoBuffer(VideoBuffer * old); + VideoBuffer(int width, int height); + void Resize(float factor, bool resample = false); + TPT_INLINE void BlendPixel(int x, int y, int r, int g, int b, int a) + { + #ifdef PIX32OGL + pixel t; + if (x<0 || y<0 || x>=Width || y>=Height) + return; + if (a!=255) + { + t = Buffer[y*(Width)+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; + a = a > PIXA(t) ? a : PIXA(t); + } + Buffer[y*(Width)+x] = PIXRGBA(r,g,b,a); + #else + pixel t; + if (x<0 || y<0 || x>=Width || y>=Height) + return; + if (a!=255) + { + t = Buffer[y*(Width)+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; + } + Buffer[y*(Width)+x] = PIXRGB(r,g,b); + #endif + } + + TPT_INLINE void SetPixel(int x, int y, int r, int g, int b, int a) + { + if (x<0 || y<0 || x>=Width || y>=Height) + return; + #ifdef PIX32OGL + Buffer[y*(Width)+x] = PIXRGBA(r,g,b,a); + #else + Buffer[y*(Width)+x] = PIXRGB((r*a)>>8, (g*a)>>8, (b*a)>>8); + #endif + } + + TPT_INLINE void AddPixel(int x, int y, int r, int g, int b, int a) + { + pixel t; + if (x<0 || y<0 || x>=Width || y>=Height) + return; + t = Buffer[y*(Width)+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; + Buffer[y*(Width)+x] = PIXRGB(r,g,b); + } + int SetCharacter(int x, int y, int c, int r, int g, int b, int a); + int BlendCharacter(int x, int y, int c, int r, int g, int b, int a); + int AddCharacter(int x, int y, int c, int r, int g, int b, int a); + ~VideoBuffer(); +}; + +class Graphics +{ +public: + pixel *vid; + int sdl_scale; +#ifdef OGLI + //OpenGL specific instance variables + GLuint vidBuf, textTexture; + void Reset(); + #endif + + //Common graphics methods in Graphics.cpp + static char * GenerateGradient(pixel * colours, float * points, int pointcount, int size); + + //PTIF methods + static void *ptif_pack(pixel *src, int w, int h, int *result_size); + static pixel *ptif_unpack(void *datain, int size, int *w, int *h); + static pixel *resample_img_nn(pixel *src, int sw, int sh, int rw, int rh); + static pixel *resample_img(pixel *src, int sw, int sh, int rw, int rh); + static pixel *rescale_img(pixel *src, int sw, int sh, int *qw, int *qh, int f); + static pixel *render_packed_rgb(void *image, int width, int height, int cmp_size); + + //Font/text metrics + static int CharIndexAtPosition(char *s, int positionX, int positionY); + static int PositionAtCharIndex(char *s, int charIndex, int & positionX, int & positionY); + static int CharWidth(char c); + static int textnwidth(char *s, int n); + static void textnpos(char *s, int n, int w, int *cx, int *cy); + static int textwidthx(char *s, int w); + static int textposxy(char *s, int width, int w, int h); + static int textwrapheight(char *s, int width); + static int textwidth(const char *s); + static void textsize(const char * s, int & width, int & height); + + VideoBuffer DumpFrame(); + + void Acquire(); + void Release(); + + void blendpixel(int x, int y, int r, int g, int b, int a); + void addpixel(int x, int y, int r, int g, int b, int a); + + void draw_icon(int x, int y, Icon icon, unsigned char alpha = 255, bool invert = false); + + void Clear(); + void Finalise(); + // + int drawtext(int x, int y, const char *s, int r, int g, int b, int a); + int drawtext(int x, int y, std::string s, int r, int g, int b, int a); + int drawchar(int x, int y, int c, int r, int g, int b, int a); + int addchar(int x, int y, int c, int r, int g, int b, int a); + + void xor_pixel(int x, int y); + void xor_line(int x, int y, int x2, int y2); + void xor_rect(int x, int y, int width, int height); + void xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h); + + void draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a); + void drawrect(int x, int y, int width, int height, int r, int g, int b, int a); + void fillrect(int x, int y, int width, int height, int r, int g, int b, int a); + void clearrect(int x, int y, int width, int height); + void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); + + void draw_image(pixel *img, int x, int y, int w, int h, int a); + void draw_image(const VideoBuffer & vidBuf, int w, int h, int a); + void draw_image(VideoBuffer * vidBuf, int w, int h, int a); + + Graphics(); + ~Graphics(); +}; + +#endif diff --git a/src/graphics/OpenGLDrawMethods.inl b/src/graphics/OpenGLDrawMethods.inl new file mode 100644 index 0000000..1ecd6b1 --- /dev/null +++ b/src/graphics/OpenGLDrawMethods.inl @@ -0,0 +1,350 @@ +#include "../data/font.h" +int PIXELMETHODS_CLASS::drawtext(int x, int y, const char *s, int r, int g, int b, int a) +{ + bool invert = false; + if(!strlen(s)) + return 0; + int oR = r, oG = g, oB = b; + int width, height; + Graphics::textsize(s, width, height); + VideoBuffer texture(width, height); + int characterX = 0, characterY = 0; + int startX = characterX; + for (; *s; s++) + { + if (*s == '\n') + { + characterX = startX; + characterY += FONT_H+2; + } + else if (*s == '\x0F') + { + if(!s[1] || !s[2] || !s[3]) break; + oR = r; + oG = g; + oB = b; + r = (unsigned char)s[1]; + g = (unsigned char)s[2]; + b = (unsigned char)s[3]; + s += 3; + } + else if (*s == '\x0E') + { + r = oR; + g = oG; + b = oB; + } + else if (*s == '\x01') + { + invert = !invert; + r = 255-r; + g = 255-g; + b = 255-b; + } + else if (*s == '\b') + { + if(!s[1]) break; + 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 'l': + r = 255; + g = b = 75; + break; + case 'b': + r = g = 0; + b = 255; + break; + case 't': + b = 255; + g = 170; + r = 32; + break; + } + if(invert) + { + r = 255-r; + g = 255-g; + b = 255-b; + } + s++; + } + else + { + characterX = texture.SetCharacter(characterX, characterY, *(unsigned char *)s, r, g, b, a); + } + } + glEnable(GL_TEXTURE_2D); + + //Generate texture + glBindTexture(GL_TEXTURE_2D, textTexture); + + //Draw texture + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.Width, texture.Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture.Buffer); + + //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture.Width, texture.Height, GL_BGRA, GL_UNSIGNED_BYTE, texture.Buffer); + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(x, y); + glTexCoord2d(1, 0); + glVertex2f(x+texture.Width, y); + glTexCoord2d(1, 1); + glVertex2f(x+texture.Width, y+texture.Height); + glTexCoord2d(0, 1); + glVertex2f(x, y+texture.Height); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + return x; +} + +int PIXELMETHODS_CLASS::drawtext(int x, int y, std::string s, int r, int g, int b, int a) +{ + return drawtext(x, y, s.c_str(), r, g, b, a); +} + +TPT_INLINE int PIXELMETHODS_CLASS::drawchar(int x, int y, int c, int r, int g, int b, int a) +{ + int i, j, w, bn = 0, ba = 0; + char *rp = font_data + font_ptrs[c]; + w = *(rp++); + VideoBuffer texture(w, 12); + texture.SetCharacter(0, 0, c, r, g, b, a); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textTexture); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.Width, texture.Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture.Buffer); + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(x, y); + glTexCoord2d(1, 0); + glVertex2f(x+texture.Width, y); + glTexCoord2d(1, 1); + glVertex2f(x+texture.Width, y+texture.Height); + glTexCoord2d(0, 1); + glVertex2f(x, y+texture.Height); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + return x + w; +} + +TPT_NO_INLINE int PIXELMETHODS_CLASS::addchar(int x, int y, int c, int r, int g, int b, int a) +{ + int i, j, w, bn = 0, ba = 0; + char *rp = font_data + font_ptrs[c]; + w = *(rp++); + VideoBuffer texture(w, 12); + texture.AddCharacter(0, 0, c, r, g, b, a); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textTexture); + glBlendFunc(GL_ONE, GL_ONE); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.Width, texture.Height, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture.Buffer); + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(x, y); + glTexCoord2d(1, 0); + glVertex2f(x+texture.Width, y); + glTexCoord2d(1, 1); + glVertex2f(x+texture.Width, y+texture.Height); + glTexCoord2d(0, 1); + glVertex2f(x, y+texture.Height); + glEnd(); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + return x + w; +} + +TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y) +{ + //OpenGL doesn't support single pixel manipulation, there are ways around it, but with poor performance +} + +TPT_INLINE void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a) +{ + //OpenGL doesn't support single pixel manipulation, there are ways around it, but with poor performance +} + +TPT_INLINE void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a) +{ + //OpenGL doesn't support single pixel manipulation, there are ways around it, but with poor performance +} + +void PIXELMETHODS_CLASS::xor_line(int x, int y, int x2, int y2) +{ + glEnable(GL_COLOR_LOGIC_OP); + //glEnable(GL_LINE_SMOOTH); + glLogicOp(GL_XOR); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_LINES); + glVertex2i(x, y); + glVertex2i(x2, y2); + glEnd(); + glDisable(GL_COLOR_LOGIC_OP); +} + +void PIXELMETHODS_CLASS::xor_rect(int x, int y, int width, int height) +{ + glEnable(GL_COLOR_LOGIC_OP); + //glEnable(GL_LINE_SMOOTH); + glLogicOp(GL_XOR); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_LINE_STRIP); + glVertex2i(x, y); + glVertex2i(x+width, y); + glVertex2i(x+width, y+height); + glVertex2i(x, y+height); + glVertex2i(x, y); + glEnd(); + glDisable(GL_COLOR_LOGIC_OP); +} + +void PIXELMETHODS_CLASS::xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h) +{ + //glEnable(GL_COLOR_LOGIC_OP); + //glLogicOp(GL_XOR); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textTexture); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap); + + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(x, y); + glTexCoord2d(1, 0); + glVertex2f(x+w, y); + glTexCoord2d(1, 1); + glVertex2f(x+w, y+h); + glTexCoord2d(0, 1); + glVertex2f(x, y+h); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + //glDisable(GL_COLOR_LOGIC_OP); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); +} + +void PIXELMETHODS_CLASS::draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a) +{ + a = 255; + glColor4ub(r, g, b, a); + glBegin(GL_LINES); + glVertex2i(x, y); + glVertex2i(x2, y2); + glEnd(); +} + +void PIXELMETHODS_CLASS::drawrect(int x, int y, int width, int height, int r, int g, int b, int a) +{ + float fx = float(x)+0.5f; + float fy = float(y)+0.5f; + float fwidth = width-1.0f; + float fheight = height-1.0f; + //x++; + //y++; + //height-=2; + //width-=2; + glColor4ub(r, g, b, a); + glBegin(GL_LINE_STRIP); + glVertex2f(fx, fy); + glVertex2f(fx+fwidth, fy); + glVertex2f(fx+fwidth, fy+fheight); + glVertex2f(fx, fy+fheight); //+1 is a hack to prevent squares from missing their corners, will make smoothed lines look like SHIT + glVertex2f(fx, fy); + glEnd(); +} + +void PIXELMETHODS_CLASS::fillrect(int x, int y, int width, int height, int r, int g, int b, int a) +{ + /*x++; + y++; + width-=1; + height-=1;*/ + + glColor4ub(r, g, b, a); + glBegin(GL_QUADS); + glVertex2i(x, y); + glVertex2i(x+width, y); + glVertex2i(x+width, y+height); + glVertex2i(x, y+height); + glEnd(); +} + +void PIXELMETHODS_CLASS::gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2) +{ + glBegin(GL_QUADS); + glColor4ub(r, g, b, a); + glVertex2i(x, y); + glColor4ub(r2, g2, b2, a2); + glVertex2i(x+width, y); + glColor4ub(r2, g2, b2, a2); + glVertex2i(x+width, y+height); + glColor4ub(r, g, b, a); + glVertex2i(x, y+height); + glEnd(); +} + +void PIXELMETHODS_CLASS::clearrect(int x, int y, int width, int height) +{ + glColor4ub(0, 0, 0, 255); + glBegin(GL_QUADS); + glVertex2i(x, y); + glVertex2i(x+width, y); + glVertex2i(x+width, y+height); + glVertex2i(x, y+height); + glEnd(); +} + +void PIXELMETHODS_CLASS::draw_image(pixel *img, int x, int y, int w, int h, int a) +{ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, textTexture); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img); + glBegin(GL_QUADS); + glTexCoord2d(0, 0); + glVertex2f(x, y); + glTexCoord2d(1, 0); + glVertex2f(x+w, y); + glTexCoord2d(1, 1); + glVertex2f(x+w, y+h); + glTexCoord2d(0, 1); + glVertex2f(x, y+h); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +} diff --git a/src/graphics/OpenGLGraphics.cpp b/src/graphics/OpenGLGraphics.cpp new file mode 100644 index 0000000..4f1d5d4 --- /dev/null +++ b/src/graphics/OpenGLGraphics.cpp @@ -0,0 +1,95 @@ +#include "Graphics.h" +#include "font.h" +#include <pthread.h> +#ifdef GetUserName +#undef GetUserName //God dammit microsoft! +#endif +#ifdef OGLI + +static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER; +//static pthread_mutex_t TMPMUT = PTHREAD_MUTEX_INITIALIZER; +Graphics::Graphics(): + sdl_scale(1) +{ +// if(gMutex == TMPMUT) +// pthread_mutex_init (&gMutex, NULL); + Reset(); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //Texture for main UI + glEnable(GL_TEXTURE_2D); + + glGenTextures(1, &vidBuf); + glBindTexture(GL_TEXTURE_2D, vidBuf); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, XRES+BARSIZE, YRES+MENUSIZE, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &textTexture); + glBindTexture(GL_TEXTURE_2D, textTexture); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_TEXTURE_2D); +} + +void Graphics::Acquire() +{ + pthread_mutex_lock(&gMutex); +} + +void Graphics::Release() +{ + pthread_mutex_unlock(&gMutex); +} + +Graphics::~Graphics() +{ +} + +void Graphics::Reset() +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + //glOrtho(0, (XRES+BARSIZE)*sdl_scale, 0, (YRES+MENUSIZE)*sdl_scale, -1, 1); + glOrtho(0, (XRES+BARSIZE)*sdl_scale, (YRES+MENUSIZE)*sdl_scale, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + //glRasterPos2i(0, (YRES+MENUSIZE)); + glRasterPos2i(0, 0); + glPixelZoom(1, 1); +} + +void Graphics::Clear() +{ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); +} + +void Graphics::Finalise() +{ + glFlush(); +} + +#define VIDXRES XRES+BARSIZE +#define VIDYRES YRES+MENUSIZE +#define PIXELMETHODS_CLASS Graphics +#include "OpenGLDrawMethods.inl" +#undef VIDYRES +#undef VIDXRES +#undef PIXELMETHODS_CLASS + + +#endif diff --git a/src/graphics/OpenGLHeaders.h b/src/graphics/OpenGLHeaders.h new file mode 100644 index 0000000..de692e0 --- /dev/null +++ b/src/graphics/OpenGLHeaders.h @@ -0,0 +1,24 @@ +#ifdef MACOSX + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 +#include <OpenGL/gl3.h> +#include <OpenGL/glu.h> +#else +//#include <GL/glew.h> +#include <OpenGL/gl.h> +#include <OpenGL/glu.h> +#define GL_RGBA32F 0x8814 +#endif + +#elif defined(WIN) + +#include <GL/glew.h> +#include <GL/gl.h> +#include <GL/glu.h> + +#else + +#include <GL/glew.h> +#include <GL/gl.h> +#include <GL/glu.h> +#endif diff --git a/src/graphics/RasterDrawMethods.inl b/src/graphics/RasterDrawMethods.inl new file mode 100644 index 0000000..55a64c9 --- /dev/null +++ b/src/graphics/RasterDrawMethods.inl @@ -0,0 +1,366 @@ +#include "font.h" + +int PIXELMETHODS_CLASS::drawtext(int x, int y, const char *s, int r, int g, int b, int a) +{ + if(!strlen(s)) + return 0; + int width, height; + + int invert = 0; + int oR = r, oG = g, oB = b; + int characterX = x, characterY = y; + int startX = characterX; + for (; *s; s++) + { + if (*s == '\n') + { + characterX = startX; + characterY += FONT_H+2; + } + else if (*s == '\x0F') + { + if(!s[1] || !s[2] || !s[3]) break; + oR = r; + oG = g; + oB = b; + r = (unsigned char)s[1]; + g = (unsigned char)s[2]; + b = (unsigned char)s[3]; + s += 3; + } + else if (*s == '\x0E') + { + r = oR; + g = oG; + b = oB; + } + else if (*s == '\x01') + { + invert = !invert; + r = 255-r; + g = 255-g; + b = 255-b; + } + else if (*s == '\b') + { + if(!s[1]) break; + 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 'l': + r = 255; + g = b = 75; + break; + case 'b': + r = g = 0; + b = 255; + break; + case 't': + b = 255; + g = 170; + r = 32; + break; + } + if(invert) + { + r = 255-r; + g = 255-g; + b = 255-b; + } + s++; + } + else + { + characterX = drawchar(characterX, characterY, *(unsigned char *)s, r, g, b, a); + } + } + return x; +} + +int PIXELMETHODS_CLASS::drawtext(int x, int y, std::string s, int r, int g, int b, int a) +{ + return drawtext(x, y, s.c_str(), r, g, b, a); +} + +TPT_INLINE int PIXELMETHODS_CLASS::drawchar(int x, int y, int c, int r, int g, int b, int a) +{ + 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; + } + blendpixel(x+i, y+j, r, g, b, ((ba&3)*a)/3); + ba >>= 2; + bn -= 2; + } + return x + w; +} + +TPT_NO_INLINE int PIXELMETHODS_CLASS::addchar(int x, int y, int c, int r, int g, int b, int a) +{ + 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; + } + { + addpixel(x+i, y+j, r, g, b, ((ba&3)*a)/3); + } + ba >>= 2; + bn -= 2; + } + return x + w; +} + +TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y) +{ + int c; + if (x<0 || y<0 || x>=XRES || y>=YRES) + return; + c = vid[y*(VIDXRES)+x]; + c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c); + if (c<512) + vid[y*(VIDXRES)+x] = PIXPACK(0xC0C0C0); + else + vid[y*(VIDXRES)+x] = PIXPACK(0x404040); +} + +TPT_INLINE void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a) +{ + pixel t; + if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) + return; + if (a!=255) + { + t = vid[y*(VIDXRES)+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*(VIDXRES)+x] = PIXRGB(r,g,b); +} + +TPT_INLINE void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a) +{ + pixel t; + if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) + return; + t = vid[y*(VIDXRES)+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*(VIDXRES)+x] = PIXRGB(r,g,b); +} + +void PIXELMETHODS_CLASS::xor_line(int x1, int y1, int x2, int y2) +{ + 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); + else + xor_pixel(x, y); + e += de; + if (e >= 0.5f) + { + y += sy; + e -= 1.0f; + } + } +} + +void PIXELMETHODS_CLASS::xor_rect(int x, int y, int w, int h) +{ + int i; + for (i=0; i<w; i+=2) + { + xor_pixel(x+i, y); + xor_pixel(x+i, y+h-1); + } + for (i=2; i<h; i+=2) + { + xor_pixel(x, y+i); + xor_pixel(x+w-1, y+i); + } +} + +void PIXELMETHODS_CLASS::xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h) +{ + for(int x1 = 0; x1 < w; x1++) + { + for(int y1 = 0; y1 < h; y1++) + { + if(bitmap[y1*w+x1]) + xor_pixel(x+x1, y+y1); + } + } +} + +void PIXELMETHODS_CLASS::draw_line(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(y, x, r, g, b, a); + else + blendpixel(x, y, r, g, b, a); + e += de; + if (e >= 0.5f) + { + y += sy; + e -= 1.0f; + } + } +} + +void PIXELMETHODS_CLASS::drawrect(int x, int y, int w, int h, int r, int g, int b, int a) +{ + int i; + w--; + h--; + for (i=0; i<=w; i++) + { + blendpixel(x+i, y, r, g, b, a); + blendpixel(x+i, y+h, r, g, b, a); + } + for (i=1; i<h; i++) + { + blendpixel(x, y+i, r, g, b, a); + blendpixel(x+w, y+i, r, g, b, a); + } +} + +void PIXELMETHODS_CLASS::fillrect(int x, int y, int w, int h, int r, int g, int b, int a) +{ + int i,j; + for (j=0; j<h; j++) + for (i=0; i<w; i++) + blendpixel(x+i, y+j, r, g, b, a); +} + +void PIXELMETHODS_CLASS::gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2) +{ + +} + +void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h) +{ + int i; + for (i=1; i<h; i++) + memset(vid+(x+1+(VIDXRES)*(y+i)), 0, PIXELSIZE*(w-1)); +} + +void PIXELMETHODS_CLASS::draw_image(pixel *img, int x, int y, int w, int h, int a) +{ + int i, j, r, g, b; + if (!img) return; + if(y + h > VIDYRES) h = ((VIDYRES)-y)-1; //Adjust height to prevent drawing off the bottom + if(!h || y < 0) return; + if(a >= 255) + for (j=0; j<h; j++) + for (i=0; i<w; i++) + { + vid[(y+j)*(VIDXRES)+(x+i)] = *img; + img++; + } + else + for (j=0; j<h; j++) + for (i=0; i<w; i++) + { + r = PIXR(*img); + g = PIXG(*img); + b = PIXB(*img); + blendpixel(x+i, y+j, r, g, b, a); + img++; + } +}
\ No newline at end of file diff --git a/src/graphics/RasterGraphics.cpp b/src/graphics/RasterGraphics.cpp new file mode 100644 index 0000000..2a485e5 --- /dev/null +++ b/src/graphics/RasterGraphics.cpp @@ -0,0 +1,45 @@ +#include "Graphics.h" + +#ifndef OGLI + +Graphics::Graphics(): +sdl_scale(1) +{ + vid = (pixel *)malloc(PIXELSIZE * ((XRES+BARSIZE) * (YRES+MENUSIZE))); + +} + +void Graphics::Acquire() +{ + +} + +void Graphics::Release() +{ + +} + +Graphics::~Graphics() +{ + free(vid); +} + +void Graphics::Clear() +{ + memset(vid, 0, PIXELSIZE * ((XRES+BARSIZE) * (YRES+MENUSIZE))); +} + +void Graphics::Finalise() +{ + +} + +#define VIDXRES XRES+BARSIZE +#define VIDYRES YRES+MENUSIZE +#define PIXELMETHODS_CLASS Graphics +#include "RasterDrawMethods.inl" +#undef VIDYRES +#undef VIDXRES +#undef PIXELMETHODS_CLASS + +#endif diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp new file mode 100644 index 0000000..eaec74c --- /dev/null +++ b/src/graphics/Renderer.cpp @@ -0,0 +1,2719 @@ +/* + * Renderer.cpp + * + * Created on: Jan 7, 2012 + * Author: Simon + */ +#include <cmath> +#include <iostream> +#include <vector> +#include <stdio.h> +#include <stdlib.h> +#include "Config.h" +#include "Renderer.h" +#include "Graphics.h" +#include "simulation/Elements.h" +#include "simulation/ElementGraphics.h" +#include "simulation/Air.h" +extern "C" +{ +#include "hmap.h" +#ifdef OGLR +#include "Shaders.h" +#endif +} + +#ifndef OGLI +#define VIDXRES (XRES+BARSIZE) +#define VIDYRES (YRES+MENUSIZE) +#else +#define VIDXRES XRES +#define VIDYRES YRES +#endif + + +void Renderer::RenderBegin() +{ +#ifdef OGLI +#ifdef OGLR + draw_air(); + draw_grav(); + DrawWalls(); + render_parts(); + render_fire(); + draw_other(); + draw_grav_zones(); + DrawSigns(); + + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); +#else + if(display_mode & DISPLAY_PERS) + { + std::copy(persistentVid, persistentVid+(VIDXRES*YRES), vid); + } + pixel * oldVid; + if(display_mode & DISPLAY_WARP) + { + oldVid = vid; + vid = warpVid; + std::fill(warpVid, warpVid+(VIDXRES*VIDYRES), 0); + } + + draw_air(); + draw_grav(); + DrawWalls(); + render_parts(); + + if(display_mode & DISPLAY_PERS) + { + int i,r,g,b; + for (i = 0; i < VIDXRES*YRES; i++) + { + r = PIXR(vid[i]); + g = PIXG(vid[i]); + b = PIXB(vid[i]); + if (r>0) + r--; + if (g>0) + g--; + if (b>0) + b--; + persistentVid[i] = PIXRGB(r,g,b); + } + } + + render_fire(); + draw_other(); + draw_grav_zones(); + DrawSigns(); + if(display_mode & DISPLAY_WARP) + { + vid = oldVid; + } +#endif +#else + if(display_mode & DISPLAY_PERS) + { + std::copy(persistentVid, persistentVid+(VIDXRES*YRES), vid); + } + pixel * oldVid; + if(display_mode & DISPLAY_WARP) + { + oldVid = vid; + vid = warpVid; + std::fill(warpVid, warpVid+(VIDXRES*VIDYRES), 0); + } + + draw_air(); + draw_grav(); + DrawWalls(); + render_parts(); + if(display_mode & DISPLAY_PERS) + { + int i,r,g,b; + for (i = 0; i < VIDXRES*YRES; i++) + { + r = PIXR(vid[i]); + g = PIXG(vid[i]); + b = PIXB(vid[i]); + if (r>0) + r--; + if (g>0) + g--; + if (b>0) + b--; + persistentVid[i] = PIXRGB(r,g,b); + } + } + + render_fire(); + draw_other(); + draw_grav_zones(); + DrawSigns(); + + if(display_mode & DISPLAY_WARP) + { + vid = oldVid; + } + + FinaliseParts(); +#endif +} + +void Renderer::RenderEnd() +{ +#ifdef OGLI +#ifdef OGLR + glTranslated(0, -MENUSIZE, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + FinaliseParts(); + RenderZoom(); +#else + RenderZoom(); + FinaliseParts(); +#endif +#else + RenderZoom(); +#endif +} + +void Renderer::clearScreen(float alpha) +{ +#ifdef OGLR + GLint prevFbo; + if(alpha > 0.999f) + { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + } + else + { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2f(XRES, 0); + glVertex2f(XRES, YRES); + glVertex2f(0, YRES); + glEnd(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + glBlendEquation(GL_FUNC_ADD); + } + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); +#endif +#ifdef OGLI +#ifndef OGLR + std::fill(vid, vid+(VIDXRES*VIDYRES), 0); +#endif +#else + g->Clear(); +#endif +} +#ifdef OGLR +void Renderer::checkShader(GLuint shader, char * shname) +{ + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) + { + char errorBuf[ GL_INFO_LOG_LENGTH]; + int errLen; + glGetShaderInfoLog(shader, GL_INFO_LOG_LENGTH, &errLen, errorBuf); + fprintf(stderr, "Failed to compile %s shader:\n%s\n", shname, errorBuf); + exit(1); + } +} +void Renderer::checkProgram(GLuint program, char * progname) +{ + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) + { + char errorBuf[ GL_INFO_LOG_LENGTH]; + int errLen; + glGetShaderInfoLog(program, GL_INFO_LOG_LENGTH, &errLen, errorBuf); + fprintf(stderr, "Failed to link %s program:\n%s\n", progname, errorBuf); + exit(1); + } +} +void Renderer::loadShaders() +{ + GLuint vertexShader, fragmentShader; + + //Particle texture + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &fireVertex, NULL); + glShaderSource( fragmentShader, 1, &fireFragment, NULL); + + glCompileShader( vertexShader ); + checkShader(vertexShader, "FV"); + glCompileShader( fragmentShader ); + checkShader(fragmentShader, "FF"); + + fireProg = glCreateProgram(); + glAttachShader( fireProg, vertexShader ); + glAttachShader( fireProg, fragmentShader ); + glLinkProgram( fireProg ); + checkProgram(fireProg, "F"); + + //Lensing + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &lensVertex, NULL); + glShaderSource( fragmentShader, 1, &lensFragment, NULL); + + glCompileShader( vertexShader ); + checkShader(vertexShader, "LV"); + glCompileShader( fragmentShader ); + checkShader(fragmentShader, "LF"); + + lensProg = glCreateProgram(); + glAttachShader( lensProg, vertexShader ); + glAttachShader( lensProg, fragmentShader ); + glLinkProgram( lensProg ); + checkProgram(lensProg, "L"); + + //Air Velocity + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &airVVertex, NULL); + glShaderSource( fragmentShader, 1, &airVFragment, NULL); + + glCompileShader( vertexShader ); + checkShader(vertexShader, "AVX"); + glCompileShader( fragmentShader ); + checkShader(fragmentShader, "AVF"); + + airProg_Velocity = glCreateProgram(); + glAttachShader( airProg_Velocity, vertexShader ); + glAttachShader( airProg_Velocity, fragmentShader ); + glLinkProgram( airProg_Velocity ); + checkProgram(airProg_Velocity, "AV"); + + //Air Pressure + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &airPVertex, NULL); + glShaderSource( fragmentShader, 1, &airPFragment, NULL); + + glCompileShader( vertexShader ); + checkShader(vertexShader, "APV"); + glCompileShader( fragmentShader ); + checkShader(fragmentShader, "APF"); + + airProg_Pressure = glCreateProgram(); + glAttachShader( airProg_Pressure, vertexShader ); + glAttachShader( airProg_Pressure, fragmentShader ); + glLinkProgram( airProg_Pressure ); + checkProgram(airProg_Pressure, "AP"); + + //Air cracker + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource( vertexShader, 1, &airCVertex, NULL); + glShaderSource( fragmentShader, 1, &airCFragment, NULL); + + glCompileShader( vertexShader ); + checkShader(vertexShader, "ACV"); + glCompileShader( fragmentShader ); + checkShader(fragmentShader, "ACF"); + + airProg_Cracker = glCreateProgram(); + glAttachShader( airProg_Cracker, vertexShader ); + glAttachShader( airProg_Cracker, fragmentShader ); + glLinkProgram( airProg_Cracker ); + checkProgram(airProg_Cracker, "AC"); +} +#endif + +void Renderer::FinaliseParts() +{ +#ifdef OGLR + glEnable( GL_TEXTURE_2D ); + if(display_mode & DISPLAY_WARP) + { + float xres = XRES, yres = YRES; + glUseProgram(lensProg); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, partsFboTex); + glUniform1i(glGetUniformLocation(lensProg, "pTex"), 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, partsTFX); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES/CELL, YRES/CELL, GL_RED, GL_FLOAT, sim->gravx); + glUniform1i(glGetUniformLocation(lensProg, "tfX"), 1); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, partsTFY); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES/CELL, YRES/CELL, GL_GREEN, GL_FLOAT, sim->gravy); + glUniform1i(glGetUniformLocation(lensProg, "tfY"), 2); + glActiveTexture(GL_TEXTURE0); + glUniform1fv(glGetUniformLocation(lensProg, "xres"), 1, &xres); + glUniform1fv(glGetUniformLocation(lensProg, "yres"), 1, &yres); + } + else + { + glBindTexture(GL_TEXTURE_2D, partsFboTex); + glBlendFunc(GL_ONE, GL_ONE); + } + + int sdl_scale = 1; + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2d(1, 0); + //glVertex3f(XRES*sdl_scale, (YRES+MENUSIZE)*sdl_scale, 1.0); + glVertex3f(XRES*sdl_scale, YRES*sdl_scale, 1.0); + glTexCoord2d(0, 0); + //glVertex3f(0, (YRES+MENUSIZE)*sdl_scale, 1.0); + glVertex3f(0, YRES*sdl_scale, 1.0); + glTexCoord2d(0, 1); + //glVertex3f(0, MENUSIZE*sdl_scale, 1.0); + glVertex3f(0, 0, 1.0); + glTexCoord2d(1, 1); + //glVertex3f(XRES*sdl_scale, MENUSIZE*sdl_scale, 1.0); + glVertex3f(XRES*sdl_scale, 0, 1.0); + glEnd(); + + if(display_mode & DISPLAY_WARP) + { + glUseProgram(0); + + } + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable( GL_TEXTURE_2D ); +#endif + +#if defined(OGLI) && !defined(OGLR) + if(display_mode & DISPLAY_WARP) + { + render_gravlensing(warpVid); + } + g->draw_image(vid, 0, 0, VIDXRES, VIDYRES, 255); +#endif + +#if !defined(OGLR) && !defined(OGLI) + if(display_mode & DISPLAY_WARP) + { + render_gravlensing(warpVid); + } +#endif +} + +void Renderer::RenderZoom() +{ + if(!zoomEnabled) + return; + #if defined(OGLR) + int sdl_scale = 1; + int origBlendSrc, origBlendDst; + float zcx1, zcx0, zcy1, zcy0, yfactor, xfactor, i; //X-Factor is shit, btw + xfactor = 1.0f/(float)XRES; + yfactor = 1.0f/(float)YRES; + yfactor*=-1.0f; + + zcx1 = (zoomScopePosition.X)*xfactor; + zcx0 = (zoomScopePosition.X+zoomScopeSize)*xfactor; + zcy1 = (zoomScopePosition.Y-1)*yfactor; + zcy0 = ((zoomScopePosition.Y-1+zoomScopeSize))*yfactor; + + glGetIntegerv(GL_BLEND_SRC, &origBlendSrc); + glGetIntegerv(GL_BLEND_DST, &origBlendDst); + glBlendFunc(GL_ONE, GL_ZERO); + + glEnable( GL_TEXTURE_2D ); + //glReadBuffer(GL_AUX0); + glBindTexture(GL_TEXTURE_2D, partsFboTex); + + //Draw zoomed texture + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2d(zcx1, zcy1); + glVertex2i(zoomWindowPosition.X, zoomWindowPosition.Y); + glTexCoord2d(zcx0, zcy1); + glVertex2i(zoomWindowPosition.X+(zoomScopeSize*ZFACTOR), zoomWindowPosition.Y); + glTexCoord2d(zcx0, zcy0); + glVertex2i(zoomWindowPosition.X+(zoomScopeSize*ZFACTOR), zoomWindowPosition.Y+(zoomScopeSize*ZFACTOR)); + glTexCoord2d(zcx1, zcy0); + glVertex2i(zoomWindowPosition.X, zoomWindowPosition.Y+(zoomScopeSize*ZFACTOR)); + glEnd(); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable( GL_TEXTURE_2D ); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //Lines to make the pixels stand out + glLineWidth(sdl_scale); + //glEnable(GL_LINE_SMOOTH); + glBegin(GL_LINES); + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + for(i = 0; i < zoomScopeSize; i++) + { + //Across + glVertex2i(zoomWindowPosition.X, zoomWindowPosition.Y+(i*ZFACTOR)); + glVertex2i(zoomWindowPosition.X+(zoomScopeSize*ZFACTOR), zoomWindowPosition.Y+(i*ZFACTOR)); + + //Down + glVertex2i(zoomWindowPosition.X+(i*ZFACTOR), zoomWindowPosition.Y); + glVertex2i(zoomWindowPosition.X+(i*ZFACTOR), zoomWindowPosition.Y+(zoomScopeSize*ZFACTOR)); + } + glEnd(); + + //Draw zoom window border + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_LINE_LOOP); + glVertex2i(zoomWindowPosition.X, zoomWindowPosition.Y); + glVertex2i(zoomWindowPosition.X+(zoomScopeSize*ZFACTOR), zoomWindowPosition.Y); + glVertex2i(zoomWindowPosition.X+(zoomScopeSize*ZFACTOR), zoomWindowPosition.Y+(zoomScopeSize*ZFACTOR)); + glVertex2i(zoomWindowPosition.X, zoomWindowPosition.Y+(zoomScopeSize*ZFACTOR)); + glEnd(); + //glDisable(GL_LINE_SMOOTH); + + if(zoomEnabled) + { + glEnable(GL_COLOR_LOGIC_OP); + //glEnable(GL_LINE_SMOOTH); + glLogicOp(GL_XOR); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_LINE_LOOP); + glVertex2i(zoomScopePosition.X, zoomScopePosition.Y); + glVertex2i(zoomScopePosition.X+zoomScopeSize, zoomScopePosition.Y); + glVertex2i(zoomScopePosition.X+zoomScopeSize, zoomScopePosition.Y+zoomScopeSize); + glVertex2i(zoomScopePosition.X, zoomScopePosition.Y+zoomScopeSize); + /*glVertex3i((zoomScopePosition.X-1)*sdl_scale, (YRES+MENUSIZE-(zoomScopePosition.Y-1))*sdl_scale, 0); + glVertex3i((zoomScopePosition.X-1)*sdl_scale, (YRES+MENUSIZE-(zoomScopePosition.Y+zoomScopeSize))*sdl_scale, 0); + glVertex3i((zoomScopePosition.X+zoomScopeSize)*sdl_scale, (YRES+MENUSIZE-(zoomScopePosition.Y+zoomScopeSize))*sdl_scale, 0); + glVertex3i((zoomScopePosition.X+zoomScopeSize)*sdl_scale, (YRES+MENUSIZE-(zoomScopePosition.Y-1))*sdl_scale, 0); + glVertex3i((zoomScopePosition.X-1)*sdl_scale, (YRES+MENUSIZE-(zoomScopePosition.Y-1))*sdl_scale, 0);*/ + glEnd(); + glDisable(GL_COLOR_LOGIC_OP); + } + glLineWidth(1); + glBlendFunc(origBlendSrc, origBlendDst); + #else + int x, y, i, j; + pixel pix; + pixel * img = vid; + clearrect(zoomWindowPosition.X-1, zoomWindowPosition.Y-1, zoomScopeSize*ZFACTOR+2, zoomScopeSize*ZFACTOR+2); + drawrect(zoomWindowPosition.X-2, zoomWindowPosition.Y-2, zoomScopeSize*ZFACTOR+4, zoomScopeSize*ZFACTOR+4, 192, 192, 192, 255); + drawrect(zoomWindowPosition.X-1, zoomWindowPosition.Y-1, zoomScopeSize*ZFACTOR+2, zoomScopeSize*ZFACTOR+2, 0, 0, 0, 255); + for (j=0; j<zoomScopeSize; j++) + for (i=0; i<zoomScopeSize; i++) + { + pix = img[(j+zoomScopePosition.Y)*(VIDXRES)+(i+zoomScopePosition.X)]; + for (y=0; y<ZFACTOR-1; y++) + for (x=0; x<ZFACTOR-1; x++) + img[(j*ZFACTOR+y+zoomWindowPosition.Y)*(VIDXRES)+(i*ZFACTOR+x+zoomWindowPosition.X)] = pix; + } + if (zoomEnabled) + { + for (j=-1; j<=zoomScopeSize; j++) + { + xor_pixel(zoomScopePosition.X+j, zoomScopePosition.Y-1); + xor_pixel(zoomScopePosition.X+j, zoomScopePosition.Y+zoomScopeSize); + } + for (j=0; j<zoomScopeSize; j++) + { + xor_pixel(zoomScopePosition.X-1, zoomScopePosition.Y+j); + xor_pixel(zoomScopePosition.X+zoomScopeSize, zoomScopePosition.Y+j); + } + } + #endif +} + +int Renderer_wtypesCount; +wall_type * Renderer_wtypes = LoadWalls(Renderer_wtypesCount); + + +VideoBuffer * Renderer::WallIcon(int wallID, int width, int height) +{ + int i, j, cr, cg, cb; + int wt = wallID; + if (wt<0 || wt>=Renderer_wtypesCount) + return 0; + wall_type *wtypes = Renderer_wtypes; + pixel pc = wtypes[wt].colour; + pixel gc = wtypes[wt].eglow; + VideoBuffer * newTexture = new VideoBuffer(width, height); + if (wtypes[wt].drawstyle==1) + { + for (j=0; j<height; j+=2) + for (i=(j>>1)&1; i<width; i+=2) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + else if (wtypes[wt].drawstyle==2) + { + for (j=0; j<height; j+=2) + for (i=0; i<width; i+=2) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + else if (wtypes[wt].drawstyle==3) + { + for (j=0; j<height; j++) + for (i=0; i<width; i++) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + else if (wtypes[wt].drawstyle==4) + { + for (j=0; j<height; j++) + for (i=0; i<width; i++) + if(i%CELL == j%CELL) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + else if (i%CELL == (j%CELL)+1 || (i%CELL == 0 && j%CELL == CELL-1)) + newTexture->SetPixel(i, j, PIXR(gc), PIXG(gc), PIXB(gc), 255); + else + newTexture->SetPixel(i, j, 0x20, 0x20, 0x20, 255); + } + + // special rendering for some walls + if (wt==WL_EWALL) + { + for (j=0; j<height; j++) + { + for (i=0; i<(width/4)+j; i++) + { + if (!(i&j&1)) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + for (; i<width; i++) + { + if (i&j&1) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + } + } + else if (wt==WL_WALLELEC) + { + for (j=0; j<height; j++) + for (i=0; i<width; i++) + { + if (!(j%2) && !(i%2)) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + else + newTexture->SetPixel(i, j, 0x80, 0x80, 0x80, 255); + } + } + else if (wt==WL_EHOLE) + { + for (j=0; j<height; j++) + { + for (i=0; i<(width/4)+j; i++) + { + if (i&j&1) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + for (; i<width; i++) + { + if (!(i&j&1)) + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + } + } + else if (wt == WL_ERASE) + { + for (j=0; j<height; j+=2) + { + for (i=1+(1&(j>>1)); i<width/2; i+=2) + { + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + } + for (j=0; j<height; j++) + { + for (i=width/2; i<width; i++) + { + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + } + for (j=3; j<(width-4)/2; j++) + { + newTexture->SetPixel(j+6, j, 0xFF, 0, 0, 255); + newTexture->SetPixel(j+7, j, 0xFF, 0, 0, 255); + newTexture->SetPixel(-j+19, j, 0xFF, 0, 0, 255); + newTexture->SetPixel(-j+20, j, 0xFF, 0, 0, 255); + } + } + else if(wt == WL_STREAM) + { + for (j=0; j<height; j++) + { + for (i=0; i<width; i++) + { + pc = i==0||i==width-1||j==0||j==height-1 ? PIXPACK(0xA0A0A0) : PIXPACK(0x000000); + newTexture->SetPixel(i, j, PIXR(pc), PIXG(pc), PIXB(pc), 255); + } + } + newTexture->SetCharacter(4, 2, 0x8D, 255, 255, 255, 255); + for (i=width/3; i<width; i++) + { + newTexture->SetPixel(i, 7+(int)(3.9f*cos(i*0.3f)), 255, 255, 255, 255); + } + } + return newTexture; +} + +void Renderer::DrawWalls() +{ +#ifdef OGLR + GLint prevFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); + + int x, y, i, j, cr, cg, cb; + unsigned char wt; + pixel pc; + pixel gc; + unsigned char (*bmap)[XRES/CELL] = sim->bmap; + unsigned char (*emap)[XRES/CELL] = sim->emap; + wall_type *wtypes = sim->wtypes; + for (y=0; y<YRES/CELL; y++) + for (x=0; x<XRES/CELL; x++) + if (bmap[y][x]) + { + wt = bmap[y][x]; + if (wt<0 || wt>=UI_WALLCOUNT) + continue; + pc = wtypes[wt].colour; + gc = wtypes[wt].eglow; + + cr = PIXR(pc); + cg = PIXG(pc); + cb = PIXB(pc); + + fillrect(x*CELL, y*CELL, CELL, CELL, cr, cg, cb, 255); + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + glTranslated(0, -MENUSIZE, 0); +#else + int x, y, i, j, cr, cg, cb; + unsigned char wt; + pixel pc; + pixel gc; + unsigned char (*bmap)[XRES/CELL] = sim->bmap; + unsigned char (*emap)[XRES/CELL] = sim->emap; + wall_type *wtypes = sim->wtypes; + for (y=0; y<YRES/CELL; y++) + for (x=0; x<XRES/CELL; x++) + if (bmap[y][x]) + { + wt = bmap[y][x]; + 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)*(VIDXRES)+(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)*(VIDXRES)+(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)*(VIDXRES)+(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)*(VIDXRES)+(x*CELL+i)] = pc; + else if (i == j+1 || (i == 0 && j == CELL-1)) + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = gc; + else + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = PIXPACK(0x202020); + } + + // special rendering for some walls + if (wt==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)*(VIDXRES)+(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)*(VIDXRES)+(x*CELL+i)] = pc; + } + } + else if (wt==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)*(VIDXRES)+(x*CELL+i)] = pc; + else + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = PIXPACK(0x808080); + } + } + else if (wt==WL_EHOLE) + { + if (emap[y][x]) + { + for (j=0; j<CELL; j++) + for (i=0; i<CELL; i++) + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = PIXPACK(0x242424); + for (j=0; j<CELL; j+=2) + for (i=0; i<CELL; i+=2) + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = PIXPACK(0x000000); + } + else + { + for (j=0; j<CELL; j+=2) + for (i=0; i<CELL; i+=2) + vid[(y*CELL+j)*(VIDXRES)+(x*CELL+i)] = PIXPACK(0x242424); + } + } + else if (wt==WL_STREAM) + { + float lx, ly, nx, ny; + lx = x*CELL + CELL*0.5f; + ly = y*CELL + CELL*0.5f; + for (int t = 0; t < 1024; t++) + { + nx = (int)(lx+0.5f); + ny = (int)(ly+0.5f); + if (nx<0 || nx>=XRES || ny<0 || ny>=YRES) + break; + addpixel(nx, ny, 255, 255, 255, 64); + i = nx/CELL; + j = ny/CELL; + lx += sim->vx[j][i]*0.125f; + ly += sim->vy[j][i]*0.125f; + if (bmap[j][i]==WL_STREAM && i!=x && j!=y) + break; + } + drawtext(x*CELL, y*CELL-2, "\x8D", 255, 255, 255, 128); + } + 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; + + } + } +#endif +} + +void Renderer::DrawSigns() +{ + int i, j, x, y, w, h, dx, dy,mx,my,b=1,bq; + std::vector<sign> signs = sim->signs; +#ifdef OGLR + GLint prevFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); +#endif + for (i=0; i < signs.size(); i++) + if (signs[i].text.length()) + { + char buff[256]; //Buffer + sim->signs[i].pos(x, y, w, h); + clearrect(x, y, w, h); + drawrect(x, y, w, h, 192, 192, 192, 255); + + //Displaying special information + if (signs[i].text == "{p}") + { + float pressure = 0.0f; + if (signs[i].x>=0 && signs[i].x<XRES && signs[i].y>=0 && signs[i].y<YRES) + pressure = sim->pv[signs[i].y/CELL][signs[i].x/CELL]; + sprintf(buff, "Pressure: %3.2f", pressure); //...pressure + drawtext(x+3, y+3, buff, 255, 255, 255, 255); + } + else if (signs[i].text == "{t}") + { + if (signs[i].x>=0 && signs[i].x<XRES && signs[i].y>=0 && signs[i].y<YRES && sim->pmap[signs[i].y][signs[i].x]) + sprintf(buff, "Temp: %4.2f", sim->parts[sim->pmap[signs[i].y][signs[i].x]>>8].temp-273.15); //...temperature + else + sprintf(buff, "Temp: 0.00"); //...temperature + drawtext(x+3, y+3, buff, 255, 255, 255, 255); + } + else if (sregexp(signs[i].text.c_str(), "^{[c|t]:[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(x+3, y+3, buff, 0, 191, 255, 255); + } + else + { + drawtext(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; +#ifdef OGLR + glBegin(GL_LINES); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glVertex2i(x, y); + glVertex2i(x+(dx*4), y+(dy*4)); + glEnd(); +#else + for (j=0; j<4; j++) + { + blendpixel(x, y, 192, 192, 192, 255); + x+=dx; + y+=dy; + } +#endif + /*if (MSIGN==i) + { + bq = b; + b = SDL_GetMouseState(&mx, &my); + mx /= sdl_scale; + my /= sdl_scale; + signs[i].x = mx; + signs[i].y = my; + }*/ + } +#ifdef OGLR + glTranslated(0, -MENUSIZE, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); +#endif +} + +void Renderer::render_gravlensing(pixel * source) +{ +#ifndef OGLR + int nx, ny, rx, ry, gx, gy, bx, by, co; + int r, g, b; + pixel t; + pixel *src = source; + pixel *dst = vid; + for(nx = 0; nx < XRES; nx++) + { + for(ny = 0; ny < YRES; ny++) + { + co = (ny/CELL)*(XRES/CELL)+(nx/CELL); + rx = (int)(nx-sim->gravx[co]*0.75f+0.5f); + ry = (int)(ny-sim->gravy[co]*0.75f+0.5f); + gx = (int)(nx-sim->gravx[co]*0.875f+0.5f); + gy = (int)(ny-sim->gravy[co]*0.875f+0.5f); + bx = (int)(nx-sim->gravx[co]+0.5f); + by = (int)(ny-sim->gravy[co]+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*(VIDXRES)+nx]; + r = PIXR(src[ry*(VIDXRES)+rx]) + PIXR(t); + g = PIXG(src[gy*(VIDXRES)+gx]) + PIXG(t); + b = PIXB(src[by*(VIDXRES)+bx]) + PIXB(t); + if (r>255) + r = 255; + if (g>255) + g = 255; + if (b>255) + b = 255; + dst[ny*(VIDXRES)+nx] = PIXRGB(r,g,b); + } + } + } +#endif +} + +void Renderer::render_fire() +{ +#ifndef OGLR + if(!(render_mode & FIREMODE)) + return; + 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; y<2*CELL; y++) + for (x=-CELL; x<2*CELL; x++) + addpixel(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; + } +#endif +} + +float temp[CELL*3][CELL*3]; +float fire_alphaf[CELL*3][CELL*3]; +float glow_alphaf[11][11]; +float blur_alphaf[7][7]; +void Renderer::prepare_alpha(int size, float intensity) +{ + //TODO: implement size + int x,y,i,j,c; + float multiplier = 255.0f*intensity; + + 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)); + +#ifdef OGLR + memset(fire_alphaf, 0, sizeof(fire_alphaf)); + for (x=0; x<CELL*3; x++) + for (y=0; y<CELL*3; y++) + { + fire_alphaf[y][x] = intensity*temp[y][x]/((float)(CELL*CELL)); + } + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, fireAlpha); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, CELL*3, CELL*3, GL_ALPHA, GL_FLOAT, fire_alphaf); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + memset(glow_alphaf, 0, sizeof(glow_alphaf)); + + c = 5; + + glow_alphaf[c][c-1] = 0.4f; + glow_alphaf[c][c+1] = 0.4f; + glow_alphaf[c-1][c] = 0.4f; + glow_alphaf[c+1][c] = 0.4f; + for (x = 1; x < 6; x++) { + glow_alphaf[c][c-x] += 0.02f; + glow_alphaf[c][c+x] += 0.02f; + glow_alphaf[c-x][c] += 0.02f; + glow_alphaf[c+x][c] += 0.02f; + for (y = 1; y < 6; y++) { + if(x + y > 7) + continue; + glow_alphaf[c+x][c-y] += 0.02f; + glow_alphaf[c-x][c+y] += 0.02f; + glow_alphaf[c+x][c+y] += 0.02f; + glow_alphaf[c-x][c-y] += 0.02f; + } + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 11, 11, GL_ALPHA, GL_FLOAT, glow_alphaf); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + c = 3; + + for (x=-3; x<4; x++) + { + for (y=-3; y<4; y++) + { + if (abs(x)+abs(y) <2 && !(abs(x)==2||abs(y)==2)) + blur_alphaf[c+x][c-y] = 0.11f; + if (abs(x)+abs(y) <=3 && abs(x)+abs(y)) + blur_alphaf[c+x][c-y] = 0.08f; + if (abs(x)+abs(y) == 2) + blur_alphaf[c+x][c-y] = 0.04f; + } + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, blurAlpha); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 7, 7, GL_ALPHA, GL_FLOAT, blur_alphaf); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +#endif +} + +void Renderer::render_parts() +{ + int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y, caddress; + int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; + float gradv, flicker, fnx, fny; + Particle * parts; + part_transition *ptransitions; + Element *elements; + if(!sim) + return; + parts = sim->parts; + elements = sim->elements; +#ifdef OGLR + int cfireV = 0, cfireC = 0, cfire = 0; + int csmokeV = 0, csmokeC = 0, csmoke = 0; + int cblobV = 0, cblobC = 0, cblob = 0; + int cblurV = 0, cblurC = 0, cblur = 0; + int cglowV = 0, cglowC = 0, cglow = 0; + int cflatV = 0, cflatC = 0, cflat = 0; + int caddV = 0, caddC = 0, cadd = 0; + int clineV = 0, clineC = 0, cline = 0; + GLint origBlendSrc, origBlendDst, prevFbo; + + glGetIntegerv(GL_BLEND_SRC, &origBlendSrc); + glGetIntegerv(GL_BLEND_DST, &origBlendDst); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + //Render to the particle FBO + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); +#else + if (gridSize)//draws the grid + { + for (ny=0; ny<YRES; ny++) + for (nx=0; nx<XRES; nx++) + { + if (ny%(4*gridSize)==0) + blendpixel(nx, ny, 100, 100, 100, 80); + if (nx%(4*gridSize)==0) + blendpixel(nx, ny, 100, 100, 100, 80); + } + } +#endif + for(i = 0; i<=sim->parts_lastActiveIndex; i++) { + if (sim->parts[i].type && sim->parts[i].type >= 0 && sim->parts[i].type < PT_NUM) { + t = sim->parts[i].type; + + nx = (int)(sim->parts[i].x+0.5f); + ny = (int)(sim->parts[i].y+0.5f); + fnx = sim->parts[i].x; + fny = sim->parts[i].y; + + if((sim->photons[ny][nx]&0xFF) && !(sim->elements[t].Properties & TYPE_ENERGY) && t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH) + continue; + if(nx >= XRES || nx < 0 || ny >= YRES || ny < 0) + continue; + + //Defaults + pixel_mode = 0 | PMODE_FLAT; + cola = 255; + colr = PIXR(elements[t].Colour); + colg = PIXG(elements[t].Colour); + colb = PIXB(elements[t].Colour); + firer = fireg = fireb = firea = 0; + + deca = (sim->parts[i].dcolour>>24)&0xFF; + decr = (sim->parts[i].dcolour>>16)&0xFF; + decg = (sim->parts[i].dcolour>>8)&0xFF; + decb = (sim->parts[i].dcolour)&0xFF; + + if(decorations_enable && blackDecorations) + { + if(deca < 250 || decr > 5 || decg > 5 || decb > 5) + deca = 0; + else + { + deca = 255; + decr = decg = decb = 0; + } + } + + { + if (graphicscache[t].isready) + { + pixel_mode = graphicscache[t].pixel_mode; + cola = graphicscache[t].cola; + colr = graphicscache[t].colr; + colg = graphicscache[t].colg; + colb = graphicscache[t].colb; + firea = graphicscache[t].firea; + firer = graphicscache[t].firer; + fireg = graphicscache[t].fireg; + fireb = graphicscache[t].fireb; + } + else if(!(colour_mode & COLOUR_BASC)) + { + if (elements[t].Graphics) + { + if ((*(elements[t].Graphics))(this, &(sim->parts[i]), nx, ny, &pixel_mode, &cola, &colr, &colg, &colb, &firea, &firer, &fireg, &fireb)) //That's a lot of args, a struct might be better + { + graphicscache[t].isready = 1; + graphicscache[t].pixel_mode = pixel_mode; + graphicscache[t].cola = cola; + graphicscache[t].colr = colr; + graphicscache[t].colg = colg; + graphicscache[t].colb = colb; + graphicscache[t].firea = firea; + graphicscache[t].firer = firer; + graphicscache[t].fireg = fireg; + graphicscache[t].fireb = fireb; + } + } + else + { + graphicscache[t].isready = 1; + graphicscache[t].pixel_mode = pixel_mode; + graphicscache[t].cola = cola; + graphicscache[t].colr = colr; + graphicscache[t].colg = colg; + graphicscache[t].colb = colb; + graphicscache[t].firea = firea; + graphicscache[t].firer = firer; + graphicscache[t].fireg = fireg; + graphicscache[t].fireb = fireb; + } + } + if((elements[t].Properties & PROP_HOT_GLOW) && sim->parts[i].temp>(elements[t].HighTemperature-800.0f)) + { + gradv = 3.1415/(2*elements[t].HighTemperature-(elements[t].HighTemperature-800.0f)); + caddress = (sim->parts[i].temp>elements[t].HighTemperature)?elements[t].HighTemperature-(elements[t].HighTemperature-800.0f):sim->parts[i].temp-(elements[t].HighTemperature-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((pixel_mode & FIRE_ADD) && !(render_mode & FIRE_ADD)) + pixel_mode |= PMODE_GLOW; + if((pixel_mode & FIRE_BLEND) && !(render_mode & FIRE_BLEND)) + pixel_mode |= PMODE_BLUR; + if((pixel_mode & PMODE_BLUR) && !(render_mode & PMODE_BLUR)) + pixel_mode |= PMODE_FLAT; + if((pixel_mode & PMODE_GLOW) && !(render_mode & PMODE_GLOW)) + pixel_mode |= PMODE_BLEND; + if (render_mode & PMODE_BLOB) + pixel_mode |= PMODE_BLOB; + + pixel_mode &= render_mode; + + //Alter colour based on display mode + if(colour_mode & COLOUR_HEAT) + { + caddress = restrict_flt((int)( restrict_flt((float)(sim->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]; + cola = 255; + if(pixel_mode & (FIREMODE | PMODE_GLOW)) pixel_mode = (pixel_mode & ~(FIREMODE|PMODE_GLOW)) | PMODE_BLUR; + } + else if(colour_mode & COLOUR_LIFE) + { + gradv = 0.4f; + if (!(sim->parts[i].life<5)) + q = sqrt((float)sim->parts[i].life); + else + q = sim->parts[i].life; + colr = colg = colb = sin(gradv*q) * 100 + 128; + cola = 255; + if(pixel_mode & (FIREMODE | PMODE_GLOW)) pixel_mode = (pixel_mode & ~(FIREMODE|PMODE_GLOW)) | PMODE_BLUR; + } + else if(colour_mode & COLOUR_BASC) + { + colr = PIXR(elements[t].Colour); + colg = PIXG(elements[t].Colour); + colb = PIXB(elements[t].Colour); + pixel_mode = PMODE_FLAT; + } + + //Apply decoration colour + if(!(colour_mode & ~COLOUR_GRAD) && decorations_enable && deca) + { + if(!(pixel_mode & NO_DECO)) + { + colr = (deca*decr + (255-deca)*colr) >> 8; + colg = (deca*decg + (255-deca)*colg) >> 8; + colb = (deca*decb + (255-deca)*colb) >> 8; + } + + if(pixel_mode & DECO_FIRE) + { + firer = (deca*decr + (255-deca)*firer) >> 8; + fireg = (deca*decg + (255-deca)*fireg) >> 8; + fireb = (deca*decb + (255-deca)*fireb) >> 8; + } + } + + if (colour_mode & COLOUR_GRAD) + { + float frequency = 0.05; + int q = sim->parts[i].temp-40; + colr = sin(frequency*q) * 16 + colr; + colg = sin(frequency*q) * 16 + colg; + colb = sin(frequency*q) * 16 + colb; + if(pixel_mode & (FIREMODE | PMODE_GLOW)) pixel_mode = (pixel_mode & ~(FIREMODE|PMODE_GLOW)) | PMODE_BLUR; + } + + #ifndef OGLR + //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; + if(cola>255) cola = 255; + else if(cola<0) cola = 0; + + if(firer>255) firer = 255; + else if(firer<0) firer = 0; + if(fireg>255) fireg = 255; + else if(fireg<0) fireg = 0; + if(fireb>255) fireb = 255; + else if(fireb<0) fireb = 0; + if(firea>255) firea = 255; + else if(firea<0) firea = 0; + #endif + + //Pixel rendering + if (pixel_mode & EFFECT_LINES) + { + if (t==PT_SOAP) + { + if ((parts[i].ctype&7) == 7) + draw_line(nx, ny, (int)(parts[parts[i].tmp].x+0.5f), (int)(parts[parts[i].tmp].y+0.5f), colr, colg, colb, cola); + } + } + if(pixel_mode & PSPEC_STICKMAN) + { + char buff[4]; //Buffer for HP + int s; + int legr, legg, legb; + playerst *cplayer; + if(t==PT_STKM) + cplayer = &sim->player; + else if(t==PT_STKM2) + cplayer = &sim->player2; + else if(t==PT_FIGH) + cplayer = &sim->fighters[(unsigned char)sim->parts[i].tmp]; + else + continue; + + if (mousePosX>(nx-3) && mousePosX<(nx+3) && mousePosY<(ny+3) && mousePosY>(ny-3)) //If mouse is in the head + { + sprintf(buff, "%3d", sim->parts[i].life); //Show HP + drawtext(mousePosX-8-2*(sim->parts[i].life<100)-2*(sim->parts[i].life<10), mousePosY-12, buff, 255, 255, 255, 255); + } + + if (colour_mode!=COLOUR_HEAT) + { + if (cplayer->elem<PT_NUM && cplayer->elem > 0) + { + colr = PIXR(elements[cplayer->elem].Colour); + colg = PIXG(elements[cplayer->elem].Colour); + colb = PIXB(elements[cplayer->elem].Colour); + } + else + { + colr = 0x80; + colg = 0x80; + colb = 0xFF; + } + } +#ifdef OGLR + glColor4f(((float)colr)/255.0f, ((float)colg)/255.0f, ((float)colb)/255.0f, 1.0f); + glBegin(GL_LINE_STRIP); + if(t==PT_FIGH) + { + glVertex2f(fnx, fny+2); + glVertex2f(fnx+2, fny); + glVertex2f(fnx, fny-2); + glVertex2f(fnx-2, fny); + glVertex2f(fnx, fny+2); + } + else + { + glVertex2f(fnx-2, fny-2); + glVertex2f(fnx+2, fny-2); + glVertex2f(fnx+2, fny+2); + glVertex2f(fnx-2, fny+2); + glVertex2f(fnx-2, fny-2); + } + glEnd(); + glBegin(GL_LINES); + + if (colour_mode!=COLOUR_HEAT) + { + if (t==PT_STKM2) + glColor4f(100.0f/255.0f, 100.0f/255.0f, 1.0f, 1.0f); + else + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + + glVertex2f(nx, ny+3); + glVertex2f(cplayer->legs[0], cplayer->legs[1]); + + glVertex2f(cplayer->legs[0], cplayer->legs[1]); + glVertex2f(cplayer->legs[4], cplayer->legs[5]); + + glVertex2f(nx, ny+3); + glVertex2f(cplayer->legs[8], cplayer->legs[9]); + + glVertex2f(cplayer->legs[8], cplayer->legs[9]); + glVertex2f(cplayer->legs[12], cplayer->legs[13]); + glEnd(); +#else + if (t==PT_STKM2) + { + legr = 100; + legg = 100; + legb = 255; + } + else + { + legr = 255; + legg = 255; + legb = 255; + } + + if (colour_mode==COLOUR_HEAT) + { + legr = colr; + legg = colg; + legb = colb; + } + + //head + if(t==PT_FIGH) + { + draw_line(nx, ny+2, nx+2, ny, colr, colg, colb, 255); + draw_line(nx+2, ny, nx, ny-2, colr, colg, colb, 255); + draw_line(nx, ny-2, nx-2, ny, colr, colg, colb, 255); + draw_line(nx-2, ny, nx, ny+2, colr, colg, colb, 255); + } + else + { + draw_line(nx-2, ny+2, nx+2, ny+2, colr, colg, colb, 255); + draw_line(nx-2, ny-2, nx+2, ny-2, colr, colg, colb, 255); + draw_line(nx-2, ny-2, nx-2, ny+2, colr, colg, colb, 255); + draw_line(nx+2, ny-2, nx+2, ny+2, colr, colg, colb, 255); + } + //legs + draw_line(nx, ny+3, cplayer->legs[0], cplayer->legs[1], legr, legg, legb, 255); + draw_line(cplayer->legs[0], cplayer->legs[1], cplayer->legs[4], cplayer->legs[5], legr, legg, legb, 255); + draw_line(nx, ny+3, cplayer->legs[8], cplayer->legs[9], legr, legg, legb, 255); + draw_line(cplayer->legs[8], cplayer->legs[9], cplayer->legs[12], cplayer->legs[13], legr, legg, legb, 255); +#endif + } + if(pixel_mode & PMODE_FLAT) + { +#ifdef OGLR + flatV[cflatV++] = nx; + flatV[cflatV++] = ny; + flatC[cflatC++] = ((float)colr)/255.0f; + flatC[cflatC++] = ((float)colg)/255.0f; + flatC[cflatC++] = ((float)colb)/255.0f; + flatC[cflatC++] = 1.0f; + cflat++; +#else + vid[ny*(VIDXRES)+nx] = PIXRGB(colr,colg,colb); +#endif + } + if(pixel_mode & PMODE_BLEND) + { +#ifdef OGLR + flatV[cflatV++] = nx; + flatV[cflatV++] = ny; + flatC[cflatC++] = ((float)colr)/255.0f; + flatC[cflatC++] = ((float)colg)/255.0f; + flatC[cflatC++] = ((float)colb)/255.0f; + flatC[cflatC++] = ((float)cola)/255.0f; + cflat++; +#else + blendpixel(nx, ny, colr, colg, colb, cola); +#endif + } + if(pixel_mode & PMODE_ADD) + { +#ifdef OGLR + addV[caddV++] = nx; + addV[caddV++] = ny; + addC[caddC++] = ((float)colr)/255.0f; + addC[caddC++] = ((float)colg)/255.0f; + addC[caddC++] = ((float)colb)/255.0f; + addC[caddC++] = ((float)cola)/255.0f; + cadd++; +#else + addpixel(nx, ny, colr, colg, colb, cola); +#endif + } + if(pixel_mode & PMODE_BLOB) + { +#ifdef OGLR + blobV[cblobV++] = nx; + blobV[cblobV++] = ny; + blobC[cblobC++] = ((float)colr)/255.0f; + blobC[cblobC++] = ((float)colg)/255.0f; + blobC[cblobC++] = ((float)colb)/255.0f; + blobC[cblobC++] = 1.0f; + cblob++; +#else + vid[ny*(VIDXRES)+nx] = PIXRGB(colr,colg,colb); + + blendpixel(nx+1, ny, colr, colg, colb, 223); + blendpixel(nx-1, ny, colr, colg, colb, 223); + blendpixel(nx, ny+1, colr, colg, colb, 223); + blendpixel(nx, ny-1, colr, colg, colb, 223); + + blendpixel(nx+1, ny-1, colr, colg, colb, 112); + blendpixel(nx-1, ny-1, colr, colg, colb, 112); + blendpixel(nx+1, ny+1, colr, colg, colb, 112); + blendpixel(nx-1, ny+1, colr, colg, colb, 112); +#endif + } + if(pixel_mode & PMODE_GLOW) + { + int cola1 = (5*cola)/255; +#ifdef OGLR + glowV[cglowV++] = nx; + glowV[cglowV++] = ny; + glowC[cglowC++] = ((float)colr)/255.0f; + glowC[cglowC++] = ((float)colg)/255.0f; + glowC[cglowC++] = ((float)colb)/255.0f; + glowC[cglowC++] = 1.0f; + cglow++; +#else + addpixel(nx, ny, colr, colg, colb, (192*cola)/255); + addpixel(nx+1, ny, colr, colg, colb, (96*cola)/255); + addpixel(nx-1, ny, colr, colg, colb, (96*cola)/255); + addpixel(nx, ny+1, colr, colg, colb, (96*cola)/255); + addpixel(nx, ny-1, colr, colg, colb, (96*cola)/255); + + for (x = 1; x < 6; x++) { + addpixel(nx, ny-x, colr, colg, colb, cola1); + addpixel(nx, ny+x, colr, colg, colb, cola1); + addpixel(nx-x, ny, colr, colg, colb, cola1); + addpixel(nx+x, ny, colr, colg, colb, cola1); + for (y = 1; y < 6; y++) { + if(x + y > 7) + continue; + addpixel(nx+x, ny-y, colr, colg, colb, cola1); + addpixel(nx-x, ny+y, colr, colg, colb, cola1); + addpixel(nx+x, ny+y, colr, colg, colb, cola1); + addpixel(nx-x, ny-y, colr, colg, colb, cola1); + } + } +#endif + } + if(pixel_mode & PMODE_BLUR) + { +#ifdef OGLR + blurV[cblurV++] = nx; + blurV[cblurV++] = ny; + blurC[cblurC++] = ((float)colr)/255.0f; + blurC[cblurC++] = ((float)colg)/255.0f; + blurC[cblurC++] = ((float)colb)/255.0f; + blurC[cblurC++] = 1.0f; + cblur++; +#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)) + blendpixel(x+nx, y+ny, colr, colg, colb, 30); + if (abs(x)+abs(y) <=3 && abs(x)+abs(y)) + blendpixel(x+nx, y+ny, colr, colg, colb, 20); + if (abs(x)+abs(y) == 2) + blendpixel(x+nx, y+ny, colr, colg, colb, 10); + } + } +#endif + } + if(pixel_mode & PMODE_SPARK) + { + flicker = rand()%20; +#ifdef OGLR + //Oh god, this is awful + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx-5; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/30; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx+5; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny-5; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/30; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny+5; + cline++; +#else + gradv = 4*sim->parts[i].life + flicker; + for (x = 0; gradv>0.5; x++) { + addpixel(nx+x, ny, colr, colg, colb, gradv); + addpixel(nx-x, ny, colr, colg, colb, gradv); + + addpixel(nx, ny+x, colr, colg, colb, gradv); + addpixel(nx, ny-x, colr, colg, colb, gradv); + gradv = gradv/1.5f; + } +#endif + } + if(pixel_mode & PMODE_FLARE) + { + flicker = rand()%20; +#ifdef OGLR + //Oh god, this is awful + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx-10; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/40; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx+10; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny-10; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/30; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny+10; + cline++; +#else + gradv = flicker + fabs(parts[i].vx)*17 + fabs(sim->parts[i].vy)*17; + blendpixel(nx, ny, colr, colg, colb, (gradv*4)>255?255:(gradv*4) ); + blendpixel(nx+1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx-1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx, ny+1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx, ny-1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + if (gradv>255) gradv=255; + blendpixel(nx+1, ny-1, colr, colg, colb, gradv); + blendpixel(nx-1, ny-1, colr, colg, colb, gradv); + blendpixel(nx+1, ny+1, colr, colg, colb, gradv); + blendpixel(nx-1, ny+1, colr, colg, colb, gradv); + for (x = 1; gradv>0.5; x++) { + addpixel(nx+x, ny, colr, colg, colb, gradv); + addpixel(nx-x, ny, colr, colg, colb, gradv); + addpixel(nx, ny+x, colr, colg, colb, gradv); + addpixel(nx, ny-x, colr, colg, colb, gradv); + gradv = gradv/1.2f; + } +#endif + } + if(pixel_mode & PMODE_LFLARE) + { + flicker = rand()%20; +#ifdef OGLR + //Oh god, this is awful + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx-70; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/30; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx+70; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny-70; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 1.0f - ((float)flicker)/50; + lineV[clineV++] = fnx; + lineV[clineV++] = fny; + cline++; + + lineC[clineC++] = ((float)colr)/255.0f; + lineC[clineC++] = ((float)colg)/255.0f; + lineC[clineC++] = ((float)colb)/255.0f; + lineC[clineC++] = 0.0f; + lineV[clineV++] = fnx; + lineV[clineV++] = fny+70; + cline++; +#else + gradv = flicker + fabs(parts[i].vx)*17 + fabs(parts[i].vy)*17; + blendpixel(nx, ny, colr, colg, colb, (gradv*4)>255?255:(gradv*4) ); + blendpixel(nx+1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx-1, ny, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx, ny+1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + blendpixel(nx, ny-1, colr, colg, colb, (gradv*2)>255?255:(gradv*2) ); + if (gradv>255) gradv=255; + blendpixel(nx+1, ny-1, colr, colg, colb, gradv); + blendpixel(nx-1, ny-1, colr, colg, colb, gradv); + blendpixel(nx+1, ny+1, colr, colg, colb, gradv); + blendpixel(nx-1, ny+1, colr, colg, colb, gradv); + for (x = 1; gradv>0.5; x++) { + addpixel(nx+x, ny, colr, colg, colb, gradv); + addpixel(nx-x, ny, colr, colg, colb, gradv); + addpixel(nx, ny+x, colr, colg, colb, gradv); + addpixel(nx, ny-x, colr, colg, colb, gradv); + gradv = gradv/1.01f; + } +#endif + } + if (pixel_mode & EFFECT_GRAVIN) + { + int nxo = 0; + int nyo = 0; + int r; + int fire_rv = 0; + float drad = 0.0f; + float ddist = 0.0f; + sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + for (r = 0; r < 4; r++) { + ddist = ((float)orbd[r])/16.0f; + drad = (M_PI * ((float)orbl[r]) / 180.0f)*1.41f; + nxo = (int)(ddist*cos(drad)); + nyo = (int)(ddist*sin(drad)); + if (ny+nyo>0 && ny+nyo<YRES && nx+nxo>0 && nx+nxo<XRES && (sim->pmap[ny+nyo][nx+nxo]&0xFF) != PT_PRTI) + addpixel(nx+nxo, ny+nyo, colr, colg, colb, 255-orbd[r]); + } + } + if (pixel_mode & EFFECT_GRAVOUT) + { + int nxo = 0; + int nyo = 0; + int r; + int fire_bv = 0; + float drad = 0.0f; + float ddist = 0.0f; + sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl); + for (r = 0; r < 4; r++) { + ddist = ((float)orbd[r])/16.0f; + drad = (M_PI * ((float)orbl[r]) / 180.0f)*1.41f; + nxo = (int)(ddist*cos(drad)); + nyo = (int)(ddist*sin(drad)); + if (ny+nyo>0 && ny+nyo<YRES && nx+nxo>0 && nx+nxo<XRES && (sim->pmap[ny+nyo][nx+nxo]&0xFF) != PT_PRTO) + addpixel(nx+nxo, ny+nyo, colr, colg, colb, 255-orbd[r]); + } + } + if (pixel_mode & EFFECT_DBGLINES) + { + if (mousePosX == nx && mousePosY == ny && debugLines)//draw lines connecting wifi/portal channels + { + int z; + int type = parts[i].type; + if (type == PT_PRTI) + type = PT_PRTO; + else if (type == PT_PRTO) + type = PT_PRTI; + for (z = 0; z<NPART; z++) { + if (parts[z].type) + { + if (parts[z].type==type&&parts[z].tmp==parts[i].tmp) + xor_line(nx,ny,(int)(parts[z].x+0.5f),(int)(parts[z].y+0.5f)); + } + } + } + } + //Fire effects + if(firea && (pixel_mode & FIRE_BLEND)) + { +#ifdef OGLR + smokeV[csmokeV++] = nx; + smokeV[csmokeV++] = ny; + smokeC[csmokeC++] = ((float)firer)/255.0f; + smokeC[csmokeC++] = ((float)fireg)/255.0f; + smokeC[csmokeC++] = ((float)fireb)/255.0f; + smokeC[csmokeC++] = ((float)firea)/255.0f; + csmoke++; +#else + firea /= 2; + 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; +#endif + } + if(firea && (pixel_mode & FIRE_ADD)) + { +#ifdef OGLR + fireV[cfireV++] = nx; + fireV[cfireV++] = ny; + fireC[cfireC++] = ((float)firer)/255.0f; + fireC[cfireC++] = ((float)fireg)/255.0f; + fireC[cfireC++] = ((float)fireb)/255.0f; + fireC[cfireC++] = ((float)firea)/255.0f; + cfire++; +#else + firea /= 8; + 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; +#endif + } + } + } + } +#ifdef OGLR + + //Go into array mode + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(cflat) + { + // -- BEGIN FLAT -- // + //Set point size (size of fire texture) + glPointSize(1.0f); + + glColorPointer(4, GL_FLOAT, 0, &flatC[0]); + glVertexPointer(2, GL_INT, 0, &flatV[0]); + + glDrawArrays(GL_POINTS, 0, cflat); + + //Clear some stuff we set + // -- END FLAT -- // + } + + if(cblob) + { + // -- BEGIN BLOB -- // + glEnable( GL_POINT_SMOOTH ); //Blobs! + glPointSize(2.5f); + + glColorPointer(4, GL_FLOAT, 0, &blobC[0]); + glVertexPointer(2, GL_INT, 0, &blobV[0]); + + glDrawArrays(GL_POINTS, 0, cblob); + + //Clear some stuff we set + glDisable( GL_POINT_SMOOTH ); + // -- END BLOB -- // + } + + if(cglow || cblur) + { + // -- BEGIN GLOW -- // + //Start and prepare fire program + glEnable(GL_TEXTURE_2D); + glUseProgram(fireProg); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glUniform1i(glGetUniformLocation(fireProg, "fireAlpha"), 0); + + glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT); + + //Make sure we can use texture coords on points + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + + //Set point size (size of fire texture) + glPointSize(11.0f); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + if(cglow) + { + glColorPointer(4, GL_FLOAT, 0, &glowC[0]); + glVertexPointer(2, GL_INT, 0, &glowV[0]); + + glDrawArrays(GL_POINTS, 0, cglow); + } + + glPointSize(7.0f); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(cblur) + { + glBindTexture(GL_TEXTURE_2D, blurAlpha); + + glColorPointer(4, GL_FLOAT, 0, &blurC[0]); + glVertexPointer(2, GL_INT, 0, &blurV[0]); + + glDrawArrays(GL_POINTS, 0, cblur); + } + + //Clear some stuff we set + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // -- END GLOW -- // + } + + if(cadd) + { + // -- BEGIN ADD -- // + //Set point size (size of fire texture) + glPointSize(1.0f); + + glColorPointer(4, GL_FLOAT, 0, &addC[0]); + glVertexPointer(2, GL_INT, 0, &addV[0]); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glDrawArrays(GL_POINTS, 0, cadd); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //Clear some stuff we set + // -- END ADD -- // + } + + if(cline) + { + // -- BEGIN LINES -- // + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glEnable( GL_LINE_SMOOTH ); + glColorPointer(4, GL_FLOAT, 0, &lineC[0]); + glVertexPointer(2, GL_FLOAT, 0, &lineV[0]); + + glDrawArrays(GL_LINE_STRIP, 0, cline); + + //Clear some stuff we set + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_LINE_SMOOTH); + // -- END LINES -- // + } + + if(cfire || csmoke) + { + // -- BEGIN FIRE -- // + //Start and prepare fire program + glEnable(GL_TEXTURE_2D); + glUseProgram(fireProg); + //glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, fireAlpha); + glUniform1i(glGetUniformLocation(fireProg, "fireAlpha"), 0); + + //Make sure we can use texture coords on points + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + + //Set point size (size of fire texture) + glPointSize(CELL*3); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + if(cfire) + { + glColorPointer(4, GL_FLOAT, 0, &fireC[0]); + glVertexPointer(2, GL_INT, 0, &fireV[0]); + + glDrawArrays(GL_POINTS, 0, cfire); + } + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(csmoke) + { + glColorPointer(4, GL_FLOAT, 0, &smokeC[0]); + glVertexPointer(2, GL_INT, 0, &smokeV[0]); + + glDrawArrays(GL_POINTS, 0, csmoke); + } + + //Clear some stuff we set + glDisable(GL_POINT_SPRITE); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // -- END FIRE -- // + } + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + //Reset FBO + glTranslated(0, -MENUSIZE, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + + glBlendFunc(origBlendSrc, origBlendDst); +#endif +} + +void Renderer::draw_other() // EMP effect +{ + int i, j; + int emp_decor = sim->emp_decor; + if (emp_decor>40) emp_decor = 40; + if (emp_decor<0) emp_decor = 0; + if (!(render_mode & EFFECT)) // not in nothing mode + return; + if (emp_decor>0) + { +#ifdef OGLR + GLint prevFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); + float femp_decor = ((float)emp_decor)/255.0f; + /*int r=emp_decor*2.5, g=100+emp_decor*1.5, b=255; + int a=(1.0*emp_decor/110)*255; + if (r>255) r=255; + if (g>255) g=255; + if (b>255) g=255; + if (a>255) a=255;*/ + glBegin(GL_QUADS); + glColor4f(femp_decor*2.5f, 0.4f+femp_decor*1.5f, 1.0f+femp_decor*1.5f, femp_decor/0.44f); + glVertex2f(0, MENUSIZE); + glVertex2f(XRES, MENUSIZE); + glVertex2f(XRES, YRES+MENUSIZE); + glVertex2f(0, YRES+MENUSIZE); + glEnd(); + glTranslated(0, -MENUSIZE, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); +#else + int r=emp_decor*2.5, g=100+emp_decor*1.5, b=255; + int a=(1.0*emp_decor/110)*255; + if (r>255) r=255; + if (g>255) g=255; + if (b>255) g=255; + if (a>255) a=255; + for (j=0; j<YRES; j++) + for (i=0; i<XRES; i++) + { + blendpixel(i, j, r, g, b, a); + } +#endif + } +} + +void Renderer::draw_grav() +{ + int x, y, i, ca; + float nx, ny, dist; + + if(!gravityFieldEnabled) + return; + + for (y=0; y<YRES/CELL; y++) + { + for (x=0; x<XRES/CELL; x++) + { + ca = y*(XRES/CELL)+x; + if(fabsf(sim->gravx[ca]) <= 0.001f && fabsf(sim->gravy[ca]) <= 0.001f) + continue; + nx = x*CELL; + ny = y*CELL; + dist = fabsf(sim->gravy[ca])+fabsf(sim->gravx[ca]); + for(i = 0; i < 4; i++) + { + nx -= sim->gravx[ca]*0.5f; + ny -= sim->gravy[ca]*0.5f; + addpixel((int)(nx+0.5f), (int)(ny+0.5f), 255, 255, 255, (int)(dist*20.0f)); + } + } + } +} + +void Renderer::draw_air() +{ + if(!sim->aheat_enable && (display_mode & DISPLAY_AIRH)) + return; +#ifndef OGLR + if(!(display_mode & DISPLAY_AIR)) + return; + int x, y, i, j; + float (*pv)[XRES/CELL] = sim->air->pv; + float (*hv)[XRES/CELL] = sim->air->hv; + float (*vx)[XRES/CELL] = sim->air->vx; + float (*vy)[XRES/CELL] = sim->air->vy; + pixel c; + for (y=0; y<YRES/CELL; y++) + for (x=0; x<XRES/CELL; x++) + { + if (display_mode & DISPLAY_AIRP) + { + 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 (display_mode & DISPLAY_AIRV) + { + 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 (display_mode & DISPLAY_AIRH) + { + 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 (display_mode & DISPLAY_AIRC) + { + 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)*(VIDXRES)] = c; + } +#else + int sdl_scale = 1; + GLuint airProg; + GLint prevFbo; + if(display_mode & DISPLAY_AIRC) + { + airProg = airProg_Cracker; + } + else if(display_mode & DISPLAY_AIRV) + { + airProg = airProg_Velocity; + } + else if(display_mode & DISPLAY_AIRP) + { + airProg = airProg_Pressure; + } + else + { + return; + } + + glEnable( GL_TEXTURE_2D ); + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glTranslated(0, MENUSIZE, 0); + + glUseProgram(airProg); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, airVX); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES/CELL, YRES/CELL, GL_RED, GL_FLOAT, sim->air->vx); + glUniform1i(glGetUniformLocation(airProg, "airX"), 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, airVY); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES/CELL, YRES/CELL, GL_GREEN, GL_FLOAT, sim->air->vy); + glUniform1i(glGetUniformLocation(airProg, "airY"), 1); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, airPV); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XRES/CELL, YRES/CELL, GL_BLUE, GL_FLOAT, sim->air->pv); + glUniform1i(glGetUniformLocation(airProg, "airP"), 2); + glActiveTexture(GL_TEXTURE0); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2d(1, 1); + glVertex3f(XRES*sdl_scale, YRES*sdl_scale, 1.0); + glTexCoord2d(0, 1); + glVertex3f(0, YRES*sdl_scale, 1.0); + glTexCoord2d(0, 0); + glVertex3f(0, 0, 1.0); + glTexCoord2d(1, 0); + glVertex3f(XRES*sdl_scale, 0, 1.0); + glEnd(); + + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glTranslated(0, -MENUSIZE, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); + glDisable( GL_TEXTURE_2D ); +#endif +} + +void Renderer::draw_grav_zones() +{ + if(!gravityZonesEnabled) + return; + + int x, y, i, j; + for (y=0; y<YRES/CELL; y++) + { + for (x=0; x<XRES/CELL; x++) + { + if(sim->grav->gravmask[y*(XRES/CELL)+x]) + { + for (j=0; j<CELL; j++)//draws the colors + for (i=0; i<CELL; i++) + if(i == j) + blendpixel(x*CELL+i, y*CELL+j, 255, 200, 0, 120); + else + blendpixel(x*CELL+i, y*CELL+j, 32, 32, 32, 120); + } + } + } +} + +void Renderer::drawblob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb) +{ + blendpixel(x+1, y, cr, cg, cb, 112); + blendpixel(x-1, y, cr, cg, cb, 112); + blendpixel(x, y+1, cr, cg, cb, 112); + blendpixel(x, y-1, cr, cg, cb, 112); + + blendpixel(x+1, y-1, cr, cg, cb, 64); + blendpixel(x-1, y-1, cr, cg, cb, 64); + blendpixel(x+1, y+1, cr, cg, cb, 64); + blendpixel(x-1, y+1, cr, cg, cb, 64); +} + +pixel Renderer::GetPixel(int x, int y) +{ + if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) + return 0; +#ifdef OGLR + return 0; +#else + return vid[(y*VIDXRES)+x]; +#endif +} + +Renderer::Renderer(Graphics * g, Simulation * sim): + sim(NULL), + g(NULL), + zoomWindowPosition(0, 0), + zoomScopePosition(0, 0), + zoomScopeSize(32), + ZFACTOR(8), + zoomEnabled(false), + decorations_enable(1), + gravityFieldEnabled(false), + gravityZonesEnabled(false), + mousePosX(-1), + mousePosY(-1), + display_mode(0), + render_mode(0), + colour_mode(0), + gridSize(0), + blackDecorations(false), + debugLines(false) +{ + this->g = g; + this->sim = sim; +#if !defined(OGLR) +#if defined(OGLI) + vid = new pixel[VIDXRES*VIDYRES]; +#else + vid = g->vid; +#endif + persistentVid = new pixel[VIDXRES*YRES]; + warpVid = new pixel[VIDXRES*VIDYRES]; +#endif + + memset(fire_r, 0, sizeof(fire_r)); + memset(fire_g, 0, sizeof(fire_g)); + memset(fire_b, 0, sizeof(fire_b)); + + //Set defauly display modes + SetColourMode(COLOUR_DEFAULT); + AddRenderMode(RENDER_BASC); + AddRenderMode(RENDER_FIRE); + + //Render mode presets. Possibly load from config in future? + renderModePresets = new RenderPreset[11]; + + renderModePresets[0].Name = "Alternative Velocity Display"; + renderModePresets[0].RenderModes.push_back(RENDER_EFFE); + renderModePresets[0].RenderModes.push_back(RENDER_BASC); + renderModePresets[0].DisplayModes.push_back(DISPLAY_AIRC); + + renderModePresets[1].Name = "Velocity Display"; + renderModePresets[1].RenderModes.push_back(RENDER_EFFE); + renderModePresets[1].RenderModes.push_back(RENDER_BASC); + renderModePresets[1].DisplayModes.push_back(DISPLAY_AIRV); + + renderModePresets[2].Name = "Pressure Display"; + renderModePresets[2].RenderModes.push_back(RENDER_EFFE); + renderModePresets[2].RenderModes.push_back(RENDER_BASC); + renderModePresets[2].DisplayModes.push_back(DISPLAY_AIRP); + + renderModePresets[3].Name = "Persistent Display"; + renderModePresets[3].RenderModes.push_back(RENDER_EFFE); + renderModePresets[3].RenderModes.push_back(RENDER_BASC); + renderModePresets[3].DisplayModes.push_back(DISPLAY_PERS); + + renderModePresets[4].Name = "Fire Display"; + renderModePresets[4].RenderModes.push_back(RENDER_FIRE); + renderModePresets[4].RenderModes.push_back(RENDER_EFFE); + renderModePresets[4].RenderModes.push_back(RENDER_BASC); + + renderModePresets[5].Name = "Blob Display"; + renderModePresets[5].RenderModes.push_back(RENDER_FIRE); + renderModePresets[5].RenderModes.push_back(RENDER_EFFE); + renderModePresets[5].RenderModes.push_back(RENDER_BLOB); + + renderModePresets[6].Name = "Heat Display"; + renderModePresets[6].RenderModes.push_back(RENDER_BASC); + renderModePresets[6].DisplayModes.push_back(DISPLAY_AIRH); + renderModePresets[6].ColourMode = COLOUR_HEAT; + + renderModePresets[7].Name = "Fancy Display"; + renderModePresets[7].RenderModes.push_back(RENDER_FIRE); + renderModePresets[7].RenderModes.push_back(RENDER_GLOW); + renderModePresets[7].RenderModes.push_back(RENDER_BLUR); + renderModePresets[7].RenderModes.push_back(RENDER_EFFE); + renderModePresets[7].RenderModes.push_back(RENDER_BASC); + renderModePresets[7].DisplayModes.push_back(DISPLAY_WARP); + + renderModePresets[8].Name = "Nothing Display"; + renderModePresets[8].RenderModes.push_back(RENDER_BASC); + + renderModePresets[9].Name = "Heat Gradient Display"; + renderModePresets[9].RenderModes.push_back(RENDER_BASC); + renderModePresets[9].ColourMode = COLOUR_GRAD; + + renderModePresets[10].Name = "Life Gradient Display"; + renderModePresets[10].RenderModes.push_back(RENDER_BASC); + renderModePresets[10].ColourMode = COLOUR_LIFE; + + //Prepare the graphics cache + graphicscache = (gcache_item *)malloc(sizeof(gcache_item)*PT_NUM); + memset(graphicscache, 0, sizeof(gcache_item)*PT_NUM); + + int fireColoursCount = 4; + pixel fireColours[] = {PIXPACK(0xAF9F0F), PIXPACK(0xDFBF6F), PIXPACK(0x60300F), PIXPACK(0x000000)}; + float fireColoursPoints[] = {1.0f, 0.9f, 0.5f, 0.0f}; + + int plasmaColoursCount = 5; + pixel plasmaColours[] = {PIXPACK(0xAFFFFF), PIXPACK(0xAFFFFF), PIXPACK(0x301060), PIXPACK(0x301040), PIXPACK(0x000000)}; + float plasmaColoursPoints[] = {1.0f, 0.9f, 0.5f, 0.25, 0.0f}; + + flm_data = Graphics::GenerateGradient(fireColours, fireColoursPoints, fireColoursCount, 200); + plasma_data = Graphics::GenerateGradient(plasmaColours, plasmaColoursPoints, plasmaColoursCount, 200); + +#ifdef OGLR + //FBO Texture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &partsFboTex); + glBindTexture(GL_TEXTURE_2D, partsFboTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, XRES, YRES, 0, GL_RGBA, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + //FBO + glGenFramebuffers(1, &partsFbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); + glEnable(GL_BLEND); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, partsFboTex, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding + glDisable(GL_TEXTURE_2D); + + //Texture for air to be drawn + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &airBuf); + glBindTexture(GL_TEXTURE_2D, airBuf); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Zoom texture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &zoomTex); + glBindTexture(GL_TEXTURE_2D, zoomTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Texture for velocity maps for gravity + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &partsTFX); + glBindTexture(GL_TEXTURE_2D, partsTFX); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + glGenTextures(1, &partsTFY); + glBindTexture(GL_TEXTURE_2D, partsTFY); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Texture for velocity maps for air + //TODO: Combine all air maps into 3D array or structs + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &airVX); + glBindTexture(GL_TEXTURE_2D, airVX); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + glGenTextures(1, &airVY); + glBindTexture(GL_TEXTURE_2D, airVY); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + glGenTextures(1, &airPV); + glBindTexture(GL_TEXTURE_2D, airPV); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, XRES/CELL, YRES/CELL, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Fire alpha texture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &fireAlpha); + glBindTexture(GL_TEXTURE_2D, fireAlpha); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, CELL*3, CELL*3, 0, GL_ALPHA, GL_FLOAT, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Glow alpha texture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &glowAlpha); + glBindTexture(GL_TEXTURE_2D, glowAlpha); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 11, 11, 0, GL_ALPHA, GL_FLOAT, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + + //Blur Alpha texture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &blurAlpha); + glBindTexture(GL_TEXTURE_2D, blurAlpha); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 7, 7, 0, GL_ALPHA, GL_FLOAT, NULL); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + //Temptexture + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &textTexture); + glBindTexture(GL_TEXTURE_2D, textTexture); + + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + loadShaders(); +#endif + prepare_alpha(CELL, 1.0f); +} + +void Renderer::CompileRenderMode() +{ + int old_render_mode = render_mode; + render_mode = 0; + for(int i = 0; i < render_modes.size(); i++) + render_mode |= render_modes[i]; + + //If firemode is removed, clear the fire display + if(!(render_mode & FIREMODE) && (old_render_mode & FIREMODE)) + { + ClearAccumulation(); + } +} + +void Renderer::ClearAccumulation() +{ + std::fill(fire_r[0]+0, fire_r[(YRES/CELL)-1]+((XRES/CELL)-1), 0); + std::fill(fire_g[0]+0, fire_g[(YRES/CELL)-1]+((XRES/CELL)-1), 0); + std::fill(fire_b[0]+0, fire_b[(YRES/CELL)-1]+((XRES/CELL)-1), 0); +#ifndef OGLR + std::fill(persistentVid, persistentVid+(VIDXRES*YRES), 0); +#endif +} + +void Renderer::AddRenderMode(unsigned int mode) +{ + for(int i = 0; i < render_modes.size(); i++) + { + if(render_modes[i] == mode) + { + return; + } + } + render_modes.push_back(mode); + CompileRenderMode(); +} + +void Renderer::RemoveRenderMode(unsigned int mode) +{ + for(int i = 0; i < render_modes.size(); i++) + { + if(render_modes[i] == mode) + { + render_modes.erase(render_modes.begin() + i); + i = 0; + } + } + CompileRenderMode(); +} + +void Renderer::SetRenderMode(std::vector<unsigned int> render) +{ + render_modes = render; + CompileRenderMode(); +} + +std::vector<unsigned int> Renderer::GetRenderMode() +{ + return render_modes; +} + +void Renderer::CompileDisplayMode() +{ + display_mode = 0; + for(int i = 0; i < display_modes.size(); i++) + display_mode |= display_modes[i]; +} + +void Renderer::AddDisplayMode(unsigned int mode) +{ + for(int i = 0; i < display_modes.size(); i++) + { + if(display_modes[i] == mode) + { + return; + } + if(display_modes[i] & DISPLAY_AIR) + { + display_modes.erase(display_modes.begin()+i); + } + } + display_modes.push_back(mode); + CompileDisplayMode(); +} + +void Renderer::RemoveDisplayMode(unsigned int mode) +{ + for(int i = 0; i < display_modes.size(); i++) + { + if(display_modes[i] == mode) + { + display_modes.erase(display_modes.begin() + i); + i = 0; + } + } + CompileDisplayMode(); +} + +void Renderer::SetDisplayMode(std::vector<unsigned int> display) +{ + display_modes = display; + CompileDisplayMode(); +} + +std::vector<unsigned int> Renderer::GetDisplayMode() +{ + return display_modes; +} + +void Renderer::SetColourMode(unsigned int mode) +{ + colour_mode = mode; +} + +unsigned int Renderer::GetColourMode() +{ + return colour_mode; +} + +VideoBuffer Renderer::DumpFrame() +{ +#ifdef OGLR +#elif defined(OGLI) + VideoBuffer newBuffer(XRES, YRES); + std::copy(vid, vid+(XRES*YRES), newBuffer.Buffer); + return newBuffer; +#else + VideoBuffer newBuffer(XRES, YRES); + for(int y = 0; y < YRES; y++) + { + std::copy(vid+(y*(XRES+BARSIZE)), vid+(y*(XRES+BARSIZE))+XRES, newBuffer.Buffer+(y*XRES)); + } + return newBuffer; +#endif +} + +Renderer::~Renderer() +{ + delete[] renderModePresets; + +#if !defined(OGLR) +#if defined(OGLI) + delete[] vid; +#endif + delete[] persistentVid; + delete[] warpVid; +#endif + free(graphicscache); + free(flm_data); + free(plasma_data); +} + +#define PIXELMETHODS_CLASS Renderer + +#ifdef OGLR +#include "OpenGLDrawMethods.inl" +#else +#include "RasterDrawMethods.inl" +#endif + +#undef PIXELMETHODS_CLASS + diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h new file mode 100644 index 0000000..fa12a8c --- /dev/null +++ b/src/graphics/Renderer.h @@ -0,0 +1,184 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include <vector> +#ifdef OGLR +#include "OpenGLHeaders.h" +#endif + +#include "Config.h" +#include "client/Client.h" +#include "Graphics.h" +#include "interface/Point.h" +#include "game/RenderPreset.h" + +class Simulation; + +class Graphics; + +struct gcache_item +{ + int isready; + int pixel_mode; + int cola, colr, colg, colb; + int firea, firer, fireg, fireb; + gcache_item() : + isready(0), + pixel_mode(0), + cola(0), + colr(0), + colg(0), + colb(0), + firea(0), + firer(0), + fireg(0), + fireb(0) + { + } +}; +typedef struct gcache_item gcache_item; + +class Renderer +{ +public: + std::vector<unsigned int> render_modes; + unsigned int render_mode; + unsigned int colour_mode; + std::vector<unsigned int> display_modes; + unsigned int display_mode; + RenderPreset * renderModePresets; + // + 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]; + char * flm_data; + char * plasma_data; + // + bool gravityZonesEnabled; + bool gravityFieldEnabled; + int decorations_enable; + bool blackDecorations; + bool debugLines; + Simulation * sim; + Graphics * g; + gcache_item *graphicscache; + + //Mouse position for debug information + int mousePosX, mousePosY; + + //Zoom window + ui::Point zoomWindowPosition; + ui::Point zoomScopePosition; + int zoomScopeSize; + bool zoomEnabled; + int ZFACTOR; + + //Renderers + void RenderBegin(); + void RenderEnd(); + + void RenderZoom(); + void DrawWalls(); + void DrawSigns(); + void render_gravlensing(pixel * source); + void render_fire(); + void prepare_alpha(int size, float intensity); + void render_parts(); + void draw_grav_zones(); + void draw_air(); + void draw_grav(); + void draw_other(); + void FinaliseParts(); + + void ClearAccumulation(); + void clearScreen(float alpha); + + //class SolidsRenderer; + +#ifdef OGLR + void checkShader(GLuint shader, char * shname); + void checkProgram(GLuint program, char * progname); + void loadShaders(); + GLuint vidBuf,textTexture; + GLint prevFbo; +#endif + pixel * vid; + pixel * persistentVid; + pixel * warpVid; + void blendpixel(int x, int y, int r, int g, int b, int a); + void addpixel(int x, int y, int r, int g, int b, int a); + + void draw_icon(int x, int y, Icon icon); + + int drawtext(int x, int y, const char *s, int r, int g, int b, int a); + int drawtext(int x, int y, std::string s, int r, int g, int b, int a); + int drawchar(int x, int y, int c, int r, int g, int b, int a); + int addchar(int x, int y, int c, int r, int g, int b, int a); + + void xor_pixel(int x, int y); + void xor_line(int x, int y, int x2, int y2); + void xor_rect(int x, int y, int width, int height); + void xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h); + + void draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a); + void drawrect(int x, int y, int width, int height, int r, int g, int b, int a); + void fillrect(int x, int y, int width, int height, int r, int g, int b, int a); + void clearrect(int x, int y, int width, int height); + void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); + + void draw_image(pixel *img, int x, int y, int w, int h, int a); + + VideoBuffer DumpFrame(); + + void drawblob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb); + + pixel GetPixel(int x, int y); + //... + //Display mode modifiers + void CompileDisplayMode(); + void CompileRenderMode(); + void AddRenderMode(unsigned int mode); + void SetRenderMode(std::vector<unsigned int> render); + std::vector<unsigned int> GetRenderMode(); + void RemoveRenderMode(unsigned int mode); + void AddDisplayMode(unsigned int mode); + void RemoveDisplayMode(unsigned int mode); + void SetDisplayMode(std::vector<unsigned int> display); + std::vector<unsigned int> GetDisplayMode(); + void SetColourMode(unsigned int mode); + unsigned int GetColourMode(); + + int GetGridSize() { return gridSize; } + void SetGridSize(int value) { gridSize = value; } + + static VideoBuffer * WallIcon(int wallID, int width, int height); + + Renderer(Graphics * g, Simulation * sim); + ~Renderer(); + +private: + int gridSize; +#ifdef OGLR + GLuint zoomTex, airBuf, fireAlpha, glowAlpha, blurAlpha, partsFboTex, partsFbo, partsTFX, partsTFY, airPV, airVY, airVX; + GLuint fireProg, airProg_Pressure, airProg_Velocity, airProg_Cracker, lensProg; + GLuint fireV[(YRES*XRES)*2]; + GLfloat fireC[(YRES*XRES)*4]; + GLuint smokeV[(YRES*XRES)*2]; + GLfloat smokeC[(YRES*XRES)*4]; + GLuint blobV[(YRES*XRES)*2]; + GLfloat blobC[(YRES*XRES)*4]; + GLuint blurV[(YRES*XRES)*2]; + GLfloat blurC[(YRES*XRES)*4]; + GLuint glowV[(YRES*XRES)*2]; + GLfloat glowC[(YRES*XRES)*4]; + GLuint flatV[(YRES*XRES)*2]; + GLfloat flatC[(YRES*XRES)*4]; + GLuint addV[(YRES*XRES)*2]; + GLfloat addC[(YRES*XRES)*4]; + GLfloat lineV[(((YRES*XRES)*2)*6)]; + GLfloat lineC[(((YRES*XRES)*2)*6)]; +#endif +}; + +#endif |
