- Don't use += when initializing MAKE_ENV. - Add note in pkg-message about CELLSHADING option. Obtained from: http://ioquake3.org/?page=patches
933 lines
24 KiB
Text
933 lines
24 KiB
Text
Index: code/renderer/tr_image.c
|
|
===================================================================
|
|
--- code/renderer/tr_image.c (revision 933)
|
|
+++ code/renderer/tr_image.c (working copy)
|
|
@@ -34,7 +34,24 @@
|
|
#define JPEG_INTERNALS
|
|
#include "../jpeg-6/jpeglib.h"
|
|
|
|
+/**
|
|
+ * Headers for cell shading
|
|
+ * @author Jordi Prats Catala
|
|
+ * @author Guillermo Miranda Alamo
|
|
+ */
|
|
+/*
|
|
+byte getImageR(byte *targa_rgba, int x, int y, int columns, int rows);
|
|
+byte getImageG(byte *targa_rgba, int x, int y, int columns, int rows);
|
|
+byte getImageB(byte *targa_rgba, int x, int y, int columns, int rows);
|
|
+byte getImageA(byte *targa_rgba, int x, int y, int columns, int rows);
|
|
+void setImageR(byte *targa_rgba, int x, int y, int columns, int rows, byte value);
|
|
+void setImageG(byte *targa_rgba, int x, int y, int columns, int rows, byte value);
|
|
+void setImageB(byte *targa_rgba, int x, int y, int columns, int rows, byte value);
|
|
+void setImageA(byte *targa_rgba, int x, int y, int columns, int rows, byte value);
|
|
+*/
|
|
+//void kuwahara(int columns, int rows, byte *targa_rgba);
|
|
|
|
+
|
|
static void LoadBMP( const char *name, byte **pic, int *width, int *height );
|
|
static void LoadTGA( const char *name, byte **pic, int *width, int *height );
|
|
static void LoadJPG( const char *name, byte **pic, int *width, int *height );
|
|
@@ -799,7 +816,643 @@
|
|
return image;
|
|
}
|
|
|
|
+/****************************
|
|
+RGB GET/SET
|
|
+****************************/
|
|
|
|
+//RED
|
|
+static byte getImageR(byte *targa_rgba, int x, int y, int columns, int rows)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+ if(rows<=y)
|
|
+ y=y%rows;
|
|
+ if(columns<=x)
|
|
+ x=x%columns;
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+
|
|
+ return *pixbuf;
|
|
+}
|
|
+
|
|
+static void setImageR(byte *targa_rgba, int x, int y, int columns, int rows, byte value)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+
|
|
+ *pixbuf=value;
|
|
+}
|
|
+//GREEN
|
|
+static byte getImageG(byte *targa_rgba, int x, int y, int columns, int rows)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+ if(rows<=y)
|
|
+ y=y%rows;
|
|
+ if(columns<=x)
|
|
+ x=x%columns;
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+
|
|
+ pixbuf++;
|
|
+ return *pixbuf;
|
|
+}
|
|
+
|
|
+static void setImageG(byte *targa_rgba, int x, int y, int columns, int rows, byte value)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+ pixbuf++;
|
|
+ *pixbuf=value;
|
|
+}
|
|
+//BLUE
|
|
+static byte getImageB(byte *targa_rgba, int x, int y, int columns, int rows)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+ if(rows<=y)
|
|
+ y=y%rows;
|
|
+ if(columns<=x)
|
|
+ x=x%columns;
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+ pixbuf+=2;
|
|
+ return *pixbuf;
|
|
+}
|
|
+
|
|
+static void setImageB(byte *targa_rgba, int x, int y, int columns, int rows, byte value)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+ pixbuf+=2;
|
|
+ *pixbuf=value;
|
|
+}
|
|
+//ALPHA
|
|
+static byte getImageA(byte *targa_rgba, int x, int y, int columns, int rows)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+ pixbuf+=3;
|
|
+ return *pixbuf;
|
|
+}
|
|
+
|
|
+static void setImageA(byte *targa_rgba, int x, int y, int columns, int rows, byte value)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4;
|
|
+
|
|
+ pixbuf+=(x*4);
|
|
+ pixbuf+=3;
|
|
+ *pixbuf=value;
|
|
+}
|
|
+
|
|
+//RGB
|
|
+static void getImageRGB(byte *targa_rgba, int x, int y, int columns, int rows, vec3_t rgb)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ x*=((x<0)?-1:1);
|
|
+ y*=((y<0)?-1:1);
|
|
+ //if(rows<=y)
|
|
+ y=y%rows;
|
|
+ //if(columns<=x)
|
|
+ x=x%columns;
|
|
+ //x*=((x<0)?-1:1);
|
|
+ //y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4 + x*4;
|
|
+
|
|
+ rgb[0]=*pixbuf;
|
|
+ rgb[1]=*(pixbuf+1);
|
|
+ rgb[2]=*(pixbuf+2);
|
|
+}
|
|
+
|
|
+static void setImageRGB(byte *targa_rgba, int x, int y, int columns, int rows, vec3_t rgb)
|
|
+{
|
|
+ byte *pixbuf;
|
|
+
|
|
+ //x*=((x<0)?-1:1);
|
|
+ //y*=((y<0)?-1:1);
|
|
+
|
|
+ pixbuf = targa_rgba + y*columns*4 + (x*4);
|
|
+
|
|
+ *pixbuf=(byte)(rgb[0]);
|
|
+ *(pixbuf+1)=(byte)(rgb[1]);
|
|
+ *(pixbuf+2)=(byte)(rgb[2]);
|
|
+}
|
|
+
|
|
+/****************************
|
|
+NO BRAINER'S BLUR
|
|
+****************************/
|
|
+static void blur(int columns, int rows, byte *targa_rgba)
|
|
+{
|
|
+ int row, column;
|
|
+ float sum;
|
|
+
|
|
+
|
|
+ for(row=0; row<rows; row++)
|
|
+ {
|
|
+ //pixbuf = targa_rgba + row*columns*4;
|
|
+ for(column=0; column<columns; column++)
|
|
+ {
|
|
+ sum=0;
|
|
+ sum+=getImageR(targa_rgba,column-1,row-1,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column,row-1,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column+1,row-1,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column-1,row,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column,row,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column+1,row,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column-1,row+1,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column,row+1,columns,rows);
|
|
+ sum+=getImageR(targa_rgba,column+1,row+1,columns,rows);
|
|
+
|
|
+ sum/=9.0f;
|
|
+
|
|
+ setImageR(targa_rgba, column, row, columns, rows, (byte)sum);
|
|
+ ////////////////////
|
|
+ sum=0;
|
|
+ sum+=getImageG(targa_rgba,column-1,row-1,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column,row-1,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column+1,row-1,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column-1,row,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column,row,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column+1,row,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column-1,row+1,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column,row+1,columns,rows);
|
|
+ sum+=getImageG(targa_rgba,column+1,row+1,columns,rows);
|
|
+
|
|
+ sum/=9.0f;
|
|
+
|
|
+ setImageG(targa_rgba, column, row, columns, rows, (byte)sum);
|
|
+ ////////////////////////
|
|
+ sum=0;
|
|
+ sum+=getImageB(targa_rgba,column-1,row-1,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column,row-1,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column+1,row-1,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column-1,row,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column,row,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column+1,row,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column-1,row+1,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column,row+1,columns,rows);
|
|
+ sum+=getImageB(targa_rgba,column+1,row+1,columns,rows);
|
|
+
|
|
+ sum/=9.0f;
|
|
+
|
|
+ setImageB(targa_rgba, column, row, columns, rows, (byte)sum);
|
|
+
|
|
+ // "halftoning"
|
|
+ /*if((row%5==0)&&(column%5==1))
|
|
+ {
|
|
+ gris=0;
|
|
+ gris+=red;
|
|
+ gris+=green;
|
|
+ gris+=blue;
|
|
+ gris/=3;
|
|
+
|
|
+ gris=255-gris;
|
|
+ if(gris<0)
|
|
+ gris=0;
|
|
+
|
|
+ setImageR(targa_rgba, column, row, columns, rows, (byte)gris);
|
|
+ setImageG(targa_rgba, column, row, columns, rows, (byte)gris);
|
|
+ setImageB(targa_rgba, column, row, columns, rows, (byte)gris);
|
|
+
|
|
+ }*/
|
|
+
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+/****************************
|
|
+COLORED LIGHTMAP
|
|
+****************************/
|
|
+void whiteTextureOne(int columns, int rows, byte *targa_rgba){
|
|
+ //byte *pixbyf;
|
|
+ int row, column;
|
|
+ long rMean=0, gMean=0, bMean=0;
|
|
+ int pixels=0;
|
|
+
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ // Don't count fully transparent pixels
|
|
+ if(getImageA(targa_rgba,column,row,columns,rows)==0)
|
|
+ continue;
|
|
+ // Sum pixels values
|
|
+ rMean+=getImageR(targa_rgba,column,row,columns,rows);
|
|
+ gMean+=getImageG(targa_rgba,column,row,columns,rows);
|
|
+ bMean+=getImageB(targa_rgba,column,row,columns,rows);
|
|
+ pixels++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Calculate average
|
|
+ if(pixels>0){
|
|
+ rMean=((float)rMean/(float)pixels);
|
|
+ gMean=((float)gMean/(float)pixels);
|
|
+ bMean=((float)bMean/(float)pixels);
|
|
+ }
|
|
+ else{
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ if(getImageA(targa_rgba,column,row,columns,rows)<32)
|
|
+ continue;
|
|
+ setImageR(targa_rgba,column,row,columns,rows,rMean);
|
|
+ setImageG(targa_rgba,column,row,columns,rows,gMean);
|
|
+ setImageB(targa_rgba,column,row,columns,rows,bMean);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int diffSquare(int mean, int val){
|
|
+ float variance = (val-mean)/255.0f;
|
|
+ float radius = mean<128?mean:255-mean;
|
|
+ return mean+(radius*variance);
|
|
+}
|
|
+
|
|
+/****************************
|
|
+DECONTRAST
|
|
+****************************/
|
|
+void whiteTextureTwo(int columns, int rows, byte *targa_rgba){
|
|
+ int row, column;
|
|
+ long rMean=0, gMean=0, bMean=0;
|
|
+ int r=0, g=0, b=0;
|
|
+ int pixels=0;
|
|
+
|
|
+
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ // Don't count fully transparent pixels
|
|
+ if(getImageA(targa_rgba,column,row,columns,rows)<32)
|
|
+ continue;
|
|
+ // Sum pixels values
|
|
+ rMean+=getImageR(targa_rgba,column,row,columns,rows);
|
|
+ gMean+=getImageG(targa_rgba,column,row,columns,rows);
|
|
+ bMean+=getImageB(targa_rgba,column,row,columns,rows);
|
|
+ pixels++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Calculate average
|
|
+ if(pixels>0){
|
|
+ rMean=rMean/pixels;
|
|
+ gMean=gMean/pixels;
|
|
+ bMean=bMean/pixels;
|
|
+ }
|
|
+ else{
|
|
+ return;
|
|
+ }
|
|
+
|
|
+
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ if(getImageA(targa_rgba,column,row,columns,rows)<32)
|
|
+ continue;
|
|
+ r=getImageR(targa_rgba,column,row,columns,rows);
|
|
+ g=getImageG(targa_rgba,column,row,columns,rows);
|
|
+ b=getImageB(targa_rgba,column,row,columns,rows);
|
|
+
|
|
+ setImageR(targa_rgba,column,row,columns,rows,diffSquare(rMean,r));
|
|
+ setImageG(targa_rgba,column,row,columns,rows,diffSquare(gMean,g));
|
|
+ setImageB(targa_rgba,column,row,columns,rows,diffSquare(bMean,b));
|
|
+
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/****************************
|
|
+KUWAHARA ,FAILS SOMEWHERE
|
|
+****************************/
|
|
+#define KWH_RADIUS 2
|
|
+static void mean_variance(int x0, int y0, int x1, int y1, int columns, int rows, byte *targa_rgba, vec4_t mv )
|
|
+{
|
|
+ short min=255*3, max=0;
|
|
+ unsigned short count= 0;
|
|
+ short row, column;
|
|
+ unsigned short value;
|
|
+ vec3_t rgb;
|
|
+
|
|
+ mv[0]=mv[1]=mv[2]=mv[3]=0;
|
|
+
|
|
+ for(row=y0;row<=y1;row++)
|
|
+ {
|
|
+ for(column=x0;column<=x1;column++)
|
|
+ {
|
|
+ getImageRGB(targa_rgba,column,row,columns,rows,rgb);
|
|
+
|
|
+ VectorAdd(mv,rgb,mv);
|
|
+
|
|
+ count++;
|
|
+ value=rgb[0]+rgb[1]+rgb[2];
|
|
+ if(value<min) min=value;
|
|
+ if(value>max) max=value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mv[0]/=count;
|
|
+ mv[1]/=count;
|
|
+ mv[2]/=count;
|
|
+ mv[3]= (max-min)/3.0f;
|
|
+}
|
|
+
|
|
+
|
|
+static void rgb_kuwahara(int x, int y, int columns, int rows, byte *targa_rgba, vec4_t bmv)
|
|
+{
|
|
+ vec4_t mv;
|
|
+ bmv[0]=bmv[1]=bmv[2]=bmv[3]=255;
|
|
+
|
|
+ mean_variance(x-KWH_RADIUS, y-KWH_RADIUS, x, y, columns, rows, targa_rgba, mv);
|
|
+ if( mv[3] < bmv[3] )
|
|
+ {
|
|
+ Vector4Copy(mv,bmv);
|
|
+ }
|
|
+
|
|
+ mean_variance(x, y-KWH_RADIUS, x+KWH_RADIUS, y, columns, rows, targa_rgba, mv);
|
|
+ if( mv[3] < bmv[3] )
|
|
+ {
|
|
+ Vector4Copy(mv,bmv);
|
|
+ }
|
|
+
|
|
+ mean_variance(x, y, x+KWH_RADIUS, y+KWH_RADIUS, columns, rows, targa_rgba, mv);
|
|
+ if( mv[3] < bmv[3] )
|
|
+ {
|
|
+ Vector4Copy(mv,bmv);
|
|
+ }
|
|
+
|
|
+ mean_variance(x-KWH_RADIUS, y, x, y+KWH_RADIUS, columns, rows, targa_rgba, mv);
|
|
+ if( mv[3] < bmv[3] )
|
|
+ {
|
|
+ Vector4Copy(mv,bmv);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void kuwahara(int columns, int rows, byte *targa_rgba){
|
|
+ int row, column;
|
|
+ vec4_t rgbv;
|
|
+
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ rgb_kuwahara(column, row, columns, rows, targa_rgba, rgbv);
|
|
+ setImageRGB(targa_rgba,column,row,columns,rows,rgbv);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+#define FLT_MAX 3.40282346638528860000e+38
|
|
+static void kuwahara3(int columns, int rows, byte *targa_rgba)
|
|
+{
|
|
+ byte channel;
|
|
+ int size = 10;
|
|
+ int index1,index2;
|
|
+ int width = columns-4;
|
|
+ int height = rows-4;
|
|
+ int size2 = (size+1)/2;
|
|
+ int offset = (size-1)/2;
|
|
+ const int width2 = columns + offset;
|
|
+ const int height2 = rows + offset;
|
|
+ int x1start = 4;
|
|
+ int y1start = 4;
|
|
+ int x2, y2;
|
|
+ int sum, sum2, n, v=0, xbase, ybase;
|
|
+ int y1,x1;
|
|
+ int xbase2=0, ybase2=0;
|
|
+ float var, min;
|
|
+ float** mean, **variance;
|
|
+
|
|
+ //blur(columns, rows, targa_rgba);
|
|
+
|
|
+ // I hate malloc I hate malloc I hate malloc I hate malloc I hate malloc I hate malloc
|
|
+ mean = (float**)malloc(sizeof(float*)*width2);
|
|
+ for(index1=0;index1<width2;index1++)
|
|
+ mean[index1] = (float*)malloc(sizeof(float)*height2);
|
|
+
|
|
+ variance = (float**)malloc(sizeof(float*)*width2);
|
|
+ for(index2=0;index2<width2;index2++)
|
|
+ variance[index2] = (float*)malloc(sizeof(float)*height2);
|
|
+
|
|
+ // For each channel (R,G,B)
|
|
+ // for(channel=0;channel<2;channel++)
|
|
+ // FTL
|
|
+ for(channel=0;channel<3;channel++){
|
|
+ for (y1=y1start-offset; y1<y1start+height; y1++) {
|
|
+
|
|
+ for (x1=x1start-offset; x1<x1start+width; x1++) {
|
|
+ sum=0; sum2=0; n=0;
|
|
+ for (x2=x1; x2<x1+size2; x2++) {
|
|
+ for (y2=y1; y2<y1+size2; y2++) {
|
|
+ //v = i(x2, y2);
|
|
+ switch(channel){
|
|
+ case 0:
|
|
+ v = getImageR(targa_rgba,x2,y2,columns,rows);
|
|
+ break;
|
|
+ case 1:
|
|
+ v = getImageG(targa_rgba,x2,y2,columns,rows);
|
|
+ break;
|
|
+ case 2:
|
|
+ v = getImageB(targa_rgba,x2,y2,columns,rows);
|
|
+ break;
|
|
+ }
|
|
+ //v = *targa_rgba + y2*columns*4+x2*4;
|
|
+ v/=10;
|
|
+ v*=10;
|
|
+ sum += v;
|
|
+ sum2 += v*v;
|
|
+ n++;
|
|
+ }
|
|
+ }
|
|
+ //cerr << "Accedo" << endl;
|
|
+ mean[x1+offset][y1+offset] = (float)(sum/n);
|
|
+ variance[x1+offset][y1+offset] = (float)((n*sum2-sum*sum)/n);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (y1=y1start; y1<y1start+height; y1++) {
|
|
+ /*if ((y1%20)==0)
|
|
+ cout << (0.7+0.3*(y1-y1start)/height);*/
|
|
+ for (x1=x1start; x1<x1start+width; x1++) {
|
|
+ min = FLT_MAX;
|
|
+ xbase = x1; ybase=y1;
|
|
+ var = variance[xbase][ybase];
|
|
+ if (var<min){
|
|
+ min= var;
|
|
+ xbase2=xbase;
|
|
+ ybase2=ybase;
|
|
+ }
|
|
+ xbase = x1+offset;
|
|
+ var = variance[xbase][ybase];
|
|
+ if (var<min){
|
|
+ min= var;
|
|
+ xbase2=xbase;
|
|
+ ybase2=ybase;
|
|
+ }
|
|
+ ybase = y1+offset;
|
|
+ var = variance[xbase][ybase];
|
|
+ if (var<min){
|
|
+ min= var;
|
|
+ xbase2=xbase;
|
|
+ ybase2=ybase;
|
|
+ }
|
|
+ xbase = x1;
|
|
+ var = variance[xbase][ybase];
|
|
+ if (var<min){
|
|
+ min= var;
|
|
+ xbase2=xbase;
|
|
+ ybase2=ybase;
|
|
+ }
|
|
+ //i(x1, y1)=(int)(mean[xbase2][ybase2]+0.5);
|
|
+ switch(channel){
|
|
+ case 0:
|
|
+ setImageR(targa_rgba,x1,y1,columns,rows,(byte)(mean[xbase2][ybase2]+0.5));
|
|
+ break;
|
|
+ case 1:
|
|
+ setImageG(targa_rgba,x1,y1,columns,rows,(byte)(mean[xbase2][ybase2]+0.5));
|
|
+ break;
|
|
+ case 2:
|
|
+ setImageB(targa_rgba,x1,y1,columns,rows,(byte)(mean[xbase2][ybase2]+0.5));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Fuck mean & variance, this is hell (!+) Bad Religion
|
|
+ for(index1=0;index1<width2;index1++)
|
|
+ free(mean[index1]);
|
|
+ free(mean);
|
|
+
|
|
+ for(index2=0;index2<width2;index2++)
|
|
+ free(variance[index2]);
|
|
+ free(variance);
|
|
+
|
|
+ //blur(columns, rows, targa_rgba);
|
|
+}
|
|
+
|
|
+/****************************
|
|
+Symmetric Nearest Neighbour
|
|
+****************************/
|
|
+
|
|
+#define SNN_RADIUS 3
|
|
+
|
|
+static int deltaE(int l1,int a1,int b1,int l2,int a2,int b2)
|
|
+{
|
|
+ return (l1-l2)*(l1-l2) + (a1-a2)*(a1-a2) + (b1-b2)*(b1-b2);
|
|
+}
|
|
+
|
|
+static void snn(int columns, int rows, byte *targa_rgba)
|
|
+{
|
|
+
|
|
+ int row, column;
|
|
+ unsigned short sumR, sumG, sumB;
|
|
+ unsigned short count;
|
|
+ short u, v;
|
|
+ byte r, g, b;
|
|
+ byte r1, g1, b1;
|
|
+ byte r2, g2, b2;
|
|
+ for(row=0;row<rows;row++){
|
|
+ for(column=0;column<columns;column++){
|
|
+ sumR=0;
|
|
+ sumG=0;
|
|
+ sumB=0;
|
|
+ count=0;
|
|
+
|
|
+ r=getImageR(targa_rgba,column,row,columns,rows);
|
|
+ g=getImageG(targa_rgba,column,row,columns,rows);
|
|
+ b=getImageB(targa_rgba,column,row,columns,rows);
|
|
+
|
|
+ for(v=-SNN_RADIUS;v<=0;v++)
|
|
+ {
|
|
+ for(u=-SNN_RADIUS;u<=SNN_RADIUS;u++)
|
|
+ {
|
|
+ if(v==0&&u>=0) break;
|
|
+ // Sum pixels values
|
|
+ r1=getImageR(targa_rgba,column+u,row+v,columns,rows);
|
|
+ g1=getImageG(targa_rgba,column+u,row+v,columns,rows);
|
|
+ b1=getImageB(targa_rgba,column+u,row+v,columns,rows);
|
|
+
|
|
+ r2=getImageR(targa_rgba,column-u,row-v,columns,rows);
|
|
+ g2=getImageG(targa_rgba,column-u,row-v,columns,rows);
|
|
+ b2=getImageB(targa_rgba,column-u,row-v,columns,rows);
|
|
+
|
|
+ if ( deltaE(r,g,b,r1,g1,b1) < deltaE(r,g,b,r2,g2,b2))
|
|
+ {
|
|
+ sumR += r1;
|
|
+ sumG += g1;
|
|
+ sumB += b1;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ sumR += r2;
|
|
+ sumG += g2;
|
|
+ sumB += b2;
|
|
+ }
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ r=(byte)((int)(2*sumR+r)/(int)(2*count+1));
|
|
+ g=(byte)((int)(2*sumG+g)/(int)(2*count+1));
|
|
+ b=(byte)((int)(2*sumB+b)/(int)(2*count+1));
|
|
+
|
|
+ setImageR(targa_rgba,column,row,columns,rows,r);
|
|
+ setImageG(targa_rgba,column,row,columns,rows,g);
|
|
+ setImageB(targa_rgba,column,row,columns,rows,b);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
/*
|
|
=========================================================
|
|
|
|
@@ -1968,6 +2621,50 @@
|
|
} else if ( !Q_stricmp( name+len-4, ".jpg" ) ) {
|
|
LoadJPG( name, pic, width, height );
|
|
}
|
|
+
|
|
+ switch(r_celshadalgo->integer)
|
|
+ {
|
|
+ case 1:
|
|
+ whiteTextureOne(*width,*height,*pic);
|
|
+ break;
|
|
+ case 2:
|
|
+ whiteTextureTwo(*width,*height,*pic);
|
|
+ break;
|
|
+ case 10:
|
|
+ kuwahara(*width,*height,*pic);
|
|
+ break;
|
|
+ case 11:
|
|
+ blur(*width,*height,*pic);
|
|
+ kuwahara(*width,*height,*pic);
|
|
+ break;
|
|
+ case 12:
|
|
+ kuwahara(*width,*height,*pic);
|
|
+ blur(*width,*height,*pic);
|
|
+ break;
|
|
+ case 13:
|
|
+ blur(*width,*height,*pic);
|
|
+ kuwahara(*width,*height,*pic);
|
|
+ blur(*width,*height,*pic);
|
|
+ break;
|
|
+ case 20:
|
|
+ snn(*width,*height,*pic);
|
|
+ break;
|
|
+ case 21:
|
|
+ blur(*width,*height,*pic);
|
|
+ snn(*width,*height,*pic);
|
|
+ break;
|
|
+ case 22:
|
|
+ snn(*width,*height,*pic);
|
|
+ blur(*width,*height,*pic);
|
|
+ break;
|
|
+ case 23:
|
|
+ blur(*width,*height,*pic);
|
|
+ snn(*width,*height,*pic);
|
|
+ blur(*width,*height,*pic);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
|
|
Index: code/renderer/tr_init.c
|
|
===================================================================
|
|
--- code/renderer/tr_init.c (revision 933)
|
|
+++ code/renderer/tr_init.c (working copy)
|
|
@@ -111,6 +111,10 @@
|
|
cvar_t *r_roundImagesDown;
|
|
cvar_t *r_colorMipLevels;
|
|
cvar_t *r_picmip;
|
|
+// Next one added for cell shading algorithm selection
|
|
+cvar_t *r_celshadalgo;
|
|
+//. next one for enable/disable cel bordering all together.
|
|
+cvar_t *r_celoutline;
|
|
cvar_t *r_showtris;
|
|
cvar_t *r_showsky;
|
|
cvar_t *r_shownormals;
|
|
@@ -1110,6 +1114,10 @@
|
|
r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_CHEAT);
|
|
r_nobind = ri.Cvar_Get ("r_nobind", "0", CVAR_CHEAT);
|
|
r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_CHEAT);
|
|
+ // for cell shading algorithm selection
|
|
+ r_celshadalgo = ri.Cvar_Get ("r_celshadalgo", "1", CVAR_LATCH);
|
|
+ // cel outline option
|
|
+ r_celoutline = ri.Cvar_Get("r_celoutline","1", CVAR_ARCHIVE);
|
|
r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_CHEAT);
|
|
r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_CHEAT);
|
|
r_clear = ri.Cvar_Get ("r_clear", "0", CVAR_CHEAT);
|
|
Index: code/renderer/tr_local.h
|
|
===================================================================
|
|
--- code/renderer/tr_local.h (revision 933)
|
|
+++ code/renderer/tr_local.h (working copy)
|
|
@@ -1063,6 +1063,8 @@
|
|
extern cvar_t *r_uiFullScreen; // ui is running fullscreen
|
|
|
|
extern cvar_t *r_logFile; // number of frames to emit GL logs
|
|
+extern cvar_t *r_celshadalgo; // Cell shading, chooses method: 0 = disabled, 1 = kuwahara, 2 = whiteTexture
|
|
+extern cvar_t *r_celoutline; //. cel outline. 1 on, 0 off. (maybe other options later)
|
|
extern cvar_t *r_showtris; // enables wireframe rendering of the world
|
|
extern cvar_t *r_showsky; // forces sky in front of all surfaces
|
|
extern cvar_t *r_shownormals; // draws wireframe normals
|
|
Index: code/renderer/tr_shade.c
|
|
===================================================================
|
|
--- code/renderer/tr_shade.c (revision 933)
|
|
+++ code/renderer/tr_shade.c (working copy)
|
|
@@ -201,6 +201,86 @@
|
|
}
|
|
|
|
|
|
+//R_DRAWCEL
|
|
+static void R_DrawCel( int numIndexes, const glIndex_t *indexes ) {
|
|
+ int primitives;
|
|
+
|
|
+ if(
|
|
+ //. ignore the 2d projection. do i smell the HUD?
|
|
+ (backEnd.projection2D == qtrue) ||
|
|
+ //. ignore general entitites that are sprites. SEE NOTE #3.
|
|
+ (backEnd.currentEntity->e.reType == RT_SPRITE) ||
|
|
+ //. ignore these liquids. why? ever see liquid with tris on the surface? exactly. SEE NOTE #4.
|
|
+ (tess.shader->contentFlags & (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FOG)) ||
|
|
+ //. ignore things that are two sided, meaning mostly things that have transparency. SEE NOTE #1.
|
|
+ (tess.shader->cullType == CT_TWO_SIDED)
|
|
+
|
|
+ ) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ primitives = r_primitives->integer;
|
|
+
|
|
+ // default is to use triangles if compiled vertex arrays are present
|
|
+ if ( primitives == 0 ) {
|
|
+ if ( qglLockArraysEXT ) {
|
|
+ primitives = 2;
|
|
+ } else {
|
|
+ primitives = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //. correction for mirrors. SEE NOTE #2.
|
|
+ if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_FRONT); }
|
|
+ else { qglCullFace (GL_BACK); }
|
|
+
|
|
+ qglEnable (GL_BLEND);
|
|
+ qglBlendFunc (GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA);
|
|
+ qglColor3f (0.0f,0.0f,0.0f);
|
|
+ qglLineWidth( (float) r_celoutline->integer );
|
|
+
|
|
+ if(primitives == 2) {
|
|
+ qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes );
|
|
+ } else if(primitives == 1) {
|
|
+ R_DrawStripElements( numIndexes, indexes, qglArrayElement );
|
|
+ } else if(primitives == 3) {
|
|
+ R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete );
|
|
+ }
|
|
+
|
|
+ //. correction for mirrors. SEE NOTE #2.
|
|
+ if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_BACK); }
|
|
+ else { qglCullFace (GL_FRONT); }
|
|
+
|
|
+ qglDisable (GL_BLEND);
|
|
+
|
|
+ return;
|
|
+
|
|
+/* Notes
|
|
+
|
|
+1. this is going to be a pain in the arse. it fixes things like light `beams` from being cel'd but it
|
|
+also will ignore any other shader set with no culling. this usually is everything that is translucent.
|
|
+but this is a good hack to clean up the screen untill something more selective comes along. or who knows
|
|
+group desision might actually be that this is liked. if so i take back calling it a `hack`, lol.
|
|
+ = bob.
|
|
+
|
|
+2. mirrors display correctly because the normals of the displayed are inverted of normal space. so to
|
|
+continue to have them display correctly, we must invert them inversely from a normal inversion.
|
|
+ = bob.
|
|
+
|
|
+3. this turns off a lot of space hogging sprite cel outlines. picture if you will five people in a small
|
|
+room all shooting rockets. each smoke puff gets a big black square around it, each explosion gets a big
|
|
+black square around it, and now nobody can see eachother because everyones screen is solid black.
|
|
+ = bob.
|
|
+
|
|
+4. ignoring liquids means you will not get black tris lines all over the top of your liquid. i put this in
|
|
+after seeing the lava on q3dm7 and water on q3ctf2 that had black lines all over the top, making the
|
|
+liquids look solid instead of... liquid.
|
|
+ = bob.
|
|
+
|
|
+*/
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
=============================================================
|
|
|
|
@@ -245,6 +325,33 @@
|
|
GL_Bind( bundle->image[ index ] );
|
|
}
|
|
|
|
+//DRAWCEL
|
|
+static void DrawCel (shaderCommands_t *input) {
|
|
+
|
|
+ GL_Bind( tr.whiteImage );
|
|
+ qglColor3f (1,1,1);
|
|
+
|
|
+ GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
|
|
+
|
|
+ qglDisableClientState (GL_COLOR_ARRAY);
|
|
+ qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
+
|
|
+ qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
|
|
+
|
|
+ if (qglLockArraysEXT) {
|
|
+ qglLockArraysEXT(0, input->numVertexes);
|
|
+ GLimp_LogComment( "glLockArraysEXT\n" );
|
|
+ }
|
|
+
|
|
+ R_DrawCel( input->numIndexes, input->indexes );
|
|
+
|
|
+ if (qglUnlockArraysEXT) {
|
|
+ qglUnlockArraysEXT();
|
|
+ GLimp_LogComment( "glUnlockArraysEXT\n" );
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
/*
|
|
================
|
|
DrawTris
|
|
@@ -1140,6 +1247,12 @@
|
|
qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
|
|
}
|
|
|
|
+ //. show me cel outlines.
|
|
+ //. there has to be a better place to put this.
|
|
+ if(r_celoutline->integer > 0) {
|
|
+ DrawCel(&tess);
|
|
+ }
|
|
+
|
|
//
|
|
// if there is only a single pass then we can enable color
|
|
// and texture arrays before we compile, otherwise we need
|
|
Index: code/renderer/tr_shader.c
|
|
===================================================================
|
|
--- code/renderer/tr_shader.c (revision 933)
|
|
+++ code/renderer/tr_shader.c (working copy)
|
|
@@ -2744,7 +2744,17 @@
|
|
*/
|
|
qhandle_t RE_RegisterShaderNoMip( const char *name ) {
|
|
shader_t *sh;
|
|
+ // Remember previous value
|
|
+ int old_r_celshadalgo;
|
|
|
|
+ /*
|
|
+ * This will prevent sprites, like buttons, go through
|
|
+ * cel shading filters, like kuwahara.
|
|
+ * @author gmiranda
|
|
+ */
|
|
+ old_r_celshadalgo = r_celshadalgo->integer;
|
|
+ r_celshadalgo->integer=0;
|
|
+
|
|
if ( strlen( name ) >= MAX_QPATH ) {
|
|
Com_Printf( "Shader name exceeds MAX_QPATH\n" );
|
|
return 0;
|
|
@@ -2752,6 +2762,9 @@
|
|
|
|
sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
|
|
|
|
+ // Restore value
|
|
+ r_celshadalgo->integer=old_r_celshadalgo;
|
|
+
|
|
// we want to return 0 if the shader failed to
|
|
// load for some reason, but R_FindShader should
|
|
// still keep a name allocated for it, so if
|