diff options
Diffstat (limited to 'src/graphics/Graphics.cpp')
| -rw-r--r-- | src/graphics/Graphics.cpp | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp new file mode 100644 index 0000000..5f84088 --- /dev/null +++ b/src/graphics/Graphics.cpp @@ -0,0 +1,789 @@ +#include <cmath> +#include <bzlib.h> +#include <string> +#include "Config.h" +#include "Misc.h" +#include "Graphics.h" +#define INCLUDE_FONTDATA +#include "font.h" + +TPT_INLINE void VideoBuffer::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 VideoBuffer::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,g,b); +#endif +} + +TPT_INLINE void VideoBuffer::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); +} + +TPT_INLINE 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; +} + +TPT_INLINE 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; +} + +TPT_INLINE 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; +} + +/** + * 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) +{ + 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(rw > sw && rh > sh){ + 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){ + rw *= 0.7; + rh *= 0.7; + if(rw <= rrw || rh <= rrh){ + rw = rrw; + rh = rrh; + } + 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 = 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::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) +{ + y--; + switch(icon) + { + case IconOpen: + drawchar(x, y, 0x81, 255, 255, 255, 255); + break; + case IconReload: + drawchar(x, y, 0x91, 255, 255, 255, 255); + break; + case IconSave: + drawchar(x, y, 0x82, 255, 255, 255, 255); + break; + case IconVoteUp: + drawchar(x, y, 0xCB, 0, 187, 18, 255); + break; + case IconVoteDown: + drawchar(x, y, 0xCA, 187, 40, 0, 255); + break; + case IconTag: + drawchar(x, y, 0x83, 255, 255, 255, 255); + break; + case IconNew: + drawchar(x, y, 0x92, 255, 255, 255, 255); + break; + case IconLogin: + drawchar(x, y, 0x84, 255, 255, 255, 255); + break; + case IconSimulationSettings: + drawchar(x, y, 0xCF, 255, 255, 255, 255); + break; + case IconRenderSettings: + addchar(x, y, 0xD8, 255, 0, 0, 255); + addchar(x, y, 0xD9, 0, 255, 0, 255); + addchar(x, y, 0xDA, 0, 0, 255, 255); + break; + case IconPause: + drawchar(x, y, 0x90, 255, 255, 255, 255); + break; + case IconFavourite: + drawchar(x, y, 0xCC, 192, 160, 64, 255); + break; + case IconReport: + drawchar(x, y, 0xE3, 255, 255, 0, 255); + break; + case IconUsername: + drawchar(x, y, 0x8B, 32, 64, 128, 255); + drawchar(x, y, 0x8A, 255, 255, 255, 255); + break; + case IconPassword: + drawchar(x, y, 0x8C, 160, 144, 32, 255); + drawchar(x, y, 0x84, 255, 255, 255, 255); + break; + case IconClose: + drawchar(x, y, 0xAA, 230, 230, 230, 255); + break; + case IconVoteSort: + case IconDateSort: + case IconFolder: + case IconSearch: + case IconDelete: + drawchar(x, y, 0x86, 255, 55, 55, 255); + drawchar(x, y, 0x85, 255, 255, 255, 255); + break; + default: + drawchar(x, y, 't', 255, 255, 255, 255); + 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; +} + + |
