diff options
-rw-r--r-- | games/ioquake3/Makefile | 14 | ||||
-rw-r--r-- | games/ioquake3/files/extra-patch-cellshading | 933 | ||||
-rw-r--r-- | games/ioquake3/files/extra-patch-mp3 | 753 | ||||
-rw-r--r-- | games/ioquake3/files/patch-Makefile | 85 | ||||
-rw-r--r-- | games/ioquake3/pkg-message | 2 | ||||
-rw-r--r-- | games/iourbanterror/Makefile | 14 | ||||
-rw-r--r-- | games/iourbanterror/files/extra-patch-cellshading | 933 | ||||
-rw-r--r-- | games/iourbanterror/files/extra-patch-mp3 | 753 | ||||
-rw-r--r-- | games/iourbanterror/files/patch-Makefile | 85 | ||||
-rw-r--r-- | games/iourbanterror/pkg-message | 2 |
10 files changed, 3538 insertions, 36 deletions
diff --git a/games/ioquake3/Makefile b/games/ioquake3/Makefile index c2f42bfbbec3..cb37008aa1c1 100644 --- a/games/ioquake3/Makefile +++ b/games/ioquake3/Makefile @@ -19,8 +19,10 @@ USE_BZIP2= yes USE_GMAKE= yes OPTIONS= CLIENT "Build client" on \ + CELLSHADING "Enable Cell Shading effect" off \ GAMELIBS "Build game libraries (when not mandatory)" off \ DEDICATED "Build dedicated server" on \ + MP3 "Enable MP3 support" off \ OPENAL "Enable OpenAL (3D sound) support" off \ OPENAL_DLOPEN "Enable dynamic loading of OpenAL" off \ OPTIMIZED_CFLAGS "Enable compilation optimizations" on \ @@ -29,7 +31,7 @@ OPTIONS= CLIENT "Build client" on \ SMP "Build SMP (threaded) client" on \ VORBIS "Enable Ogg Vorbis codec support" off -MAKE_ENV+= DEFAULT_BASEDIR="${Q3DIR}" LIBDIR="${LIBDIR}" \ +MAKE_ENV= DEFAULT_BASEDIR="${Q3DIR}" LIBDIR="${LIBDIR}" \ PTHREAD_LIBS="${PTHREAD_LIBS}" PLIST_SUB= LIBDIR="${LIBDIR:S/${PREFIX}\///}" @@ -53,6 +55,10 @@ HAVE_VM_COMPILED= yes MAKE_ENV+= HAVE_VM_COMPILED=true .endif +.if defined(WITH_CELLSHADING) +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-cellshading +.endif + .if !defined(WITHOUT_CLIENT) || !defined(WITHOUT_SMP) # OpenAL . if defined(WITH_OPENAL) @@ -104,6 +110,12 @@ PLIST_SUB+= GAMELIBS="" PLIST_SUB+= GAMELIBS="@comment " .endif +.if defined(WITH_MP3) +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-mp3 +LIB_DEPENDS+= mad.2:${PORTSDIR}/audio/libmad +MAKE_ENV+= USE_CODEC_MP3=1 +.endif + .if !defined(WITHOUT_OPTIMIZED_CFLAGS) MAKE_ENV+= USE_OPTIMIZED_CFLAGS=1 .endif diff --git a/games/ioquake3/files/extra-patch-cellshading b/games/ioquake3/files/extra-patch-cellshading new file mode 100644 index 000000000000..ce459a17bd45 --- /dev/null +++ b/games/ioquake3/files/extra-patch-cellshading @@ -0,0 +1,933 @@ +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 diff --git a/games/ioquake3/files/extra-patch-mp3 b/games/ioquake3/files/extra-patch-mp3 new file mode 100644 index 000000000000..b33f2a660571 --- /dev/null +++ b/games/ioquake3/files/extra-patch-mp3 @@ -0,0 +1,753 @@ +Index: code/client/snd_codec.c +=================================================================== +--- code/client/snd_codec.c (revision 917) ++++ code/client/snd_codec.c (working copy) +@@ -105,6 +105,9 @@ + #if USE_CODEC_VORBIS + S_CodecRegister(&ogg_codec); + #endif ++#if USE_CODEC_MP3 ++ S_CodecRegister(&mp3_codec); ++#endif + } + + /* +Index: code/client/snd_codec.h +=================================================================== +--- code/client/snd_codec.h (revision 917) ++++ code/client/snd_codec.h (working copy) +@@ -95,4 +95,13 @@ + int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); + #endif // USE_CODEC_VORBIS + ++// MP3 codec ++#ifdef USE_CODEC_MP3 ++extern snd_codec_t mp3_codec; ++void *S_MP3_CodecLoad(const char *filename, snd_info_t *info); ++snd_stream_t *S_MP3_CodecOpenStream(const char *filename); ++void S_MP3_CodecCloseStream(snd_stream_t *stream); ++int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); ++#endif // USE_CODEC_MP3 ++ + #endif // !_SND_CODEC_H_ +Index: code/client/snd_codec_mp3.c +=================================================================== +--- code/client/snd_codec_mp3.c (revision 0) ++++ code/client/snd_codec_mp3.c (revision 0) +@@ -0,0 +1,716 @@ ++/* ++=========================================================================== ++Copyright (C) 1999-2005 Id Software, Inc. ++Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) ++Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de> ++Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de> ++ ++This file is part of Quake III Arena source code. ++ ++Quake III Arena source code is free software; you can redistribute it ++and/or modify it under the terms of the GNU General Public License as ++published by the Free Software Foundation; either version 2 of the License, ++or (at your option) any later version. ++ ++Quake III Arena source code is distributed in the hope that it will be ++useful, but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with Quake III Arena source code; if not, write to the Free Software ++Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++=========================================================================== ++*/ ++ ++// MP3 support is enabled by this define ++#if USE_CODEC_MP3 ++ ++// includes for the Q3 sound system ++#include "client.h" ++#include "snd_codec.h" ++ ++// includes for the MP3 codec ++#include <mad.h> ++ ++#define MP3_SAMPLE_WIDTH 2 ++#define MP3_PCMSAMPLES_PERSLICE 32 ++ ++// buffer size used when reading through the mp3 ++#define MP3_DATA_BUFSIZ 128*1024 ++ ++// undefine this if you don't want any dithering. ++#define MP3_DITHERING ++ ++// Q3 MP3 codec ++snd_codec_t mp3_codec = ++{ ++ ".mp3", ++ S_MP3_CodecLoad, ++ S_MP3_CodecOpenStream, ++ S_MP3_CodecReadStream, ++ S_MP3_CodecCloseStream, ++ NULL ++}; ++ ++// structure used for info purposes ++struct snd_codec_mp3_info ++{ ++ byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed ++ // by the decoder. ++ struct mad_stream madstream; // uses encbuf as buffer. ++ struct mad_frame madframe; // control structures for libmad. ++ struct mad_synth madsynth; ++ ++ byte *pcmbuf; // buffer for not-used samples. ++ int buflen; // length of buffer data. ++ int pcmbufsize; // amount of allocated memory for ++ // pcmbuf. This should have at least ++ // the size of a decoded mp3 frame. ++ ++ byte *dest; // copy decoded data here. ++ int destlen; // amount of already copied data. ++ int destsize; // amount of bytes we must decode. ++}; ++ ++/*************** MP3 utility functions ***************/ ++ ++/* ++================= ++S_MP3_ReadData ++================= ++*/ ++ ++// feed libmad with data ++int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize) ++{ ++ int retval; ++ int leftover; ++ ++ if(!stream) ++ return -1; ++ ++ leftover = madstream->bufend - madstream->next_frame; ++ if(leftover > 0) ++ memmove(encbuf, madstream->this_frame, leftover); ++ ++ ++ // Fill the buffer right to the end ++ ++ retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file); ++ ++ if(retval <= 0) ++ { ++ // EOF reached, that's ok. ++ return 0; ++ } ++ ++ mad_stream_buffer(madstream, encbuf, retval + leftover); ++ ++ return retval; ++} ++ ++ ++/* ++================= ++S_MP3_Scanfile ++ ++to determine the samplecount, we apparently must get *all* headers :( ++I basically used the xmms-mad plugin source to see how this stuff works. ++ ++returns a value < 0 on error. ++================= ++*/ ++ ++int S_MP3_Scanfile(snd_stream_t *stream) ++{ ++ struct mad_stream madstream; ++ struct mad_header madheader; ++ int retval; ++ int samplecount; ++ byte encbuf[MP3_DATA_BUFSIZ]; ++ ++ // error out on invalid input. ++ if(!stream) ++ return -1; ++ ++ mad_stream_init(&madstream); ++ mad_header_init(&madheader); ++ ++ while(1) ++ { ++ retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf)); ++ if(retval < 0) ++ return -1; ++ else if(retval == 0) ++ break; ++ ++ // Start decoding the headers. ++ while(1) ++ { ++ if((retval = mad_header_decode(&madheader, &madstream)) < 0) ++ { ++ if(madstream.error == MAD_ERROR_BUFLEN) ++ { ++ // We need to read more data ++ break; ++ } ++ ++ if(!MAD_RECOVERABLE (madstream.error)) ++ { ++ // unrecoverable error... we must bail out. ++ return retval; ++ } ++ ++ mad_stream_skip(&madstream, madstream.skiplen); ++ continue; ++ } ++ ++ // we got a valid header. ++ ++ if(madheader.layer != MAD_LAYER_III) ++ { ++ // we don't support non-mp3s ++ return -1; ++ } ++ ++ if(!stream->info.samples) ++ { ++ // This here is the very first frame. Set initial values now, ++ // that we expect to stay constant throughout the whole mp3. ++ ++ stream->info.rate = madheader.samplerate; ++ stream->info.width = MP3_SAMPLE_WIDTH; ++ stream->info.channels = MAD_NCHANNELS(&madheader); ++ stream->info.samples = 0; ++ stream->info.size = 0; // same here. ++ stream->info.dataofs = 0; ++ } ++ else ++ { ++ // Check whether something changed that shouldn't. ++ ++ if(stream->info.rate != madheader.samplerate || ++ stream->info.channels != MAD_NCHANNELS(&madheader)) ++ return -1; ++ } ++ ++ // Update the counters ++ samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE; ++ stream->info.samples += samplecount; ++ stream->info.size += samplecount * stream->info.channels * stream->info.width; ++ } ++ } ++ ++ // Reset the file pointer so we can do the real decoding. ++ FS_Seek(stream->file, 0, FS_SEEK_SET); ++ ++ return 0; ++} ++ ++/************************ dithering functions ***************************/ ++ ++#ifdef MP3_DITHERING ++ ++// All dithering done here is taken from the GPL'ed xmms-mad plugin. ++ ++/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ ++/* Any feedback is very welcome. For any question, comments, */ ++/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ ++/* matumoto@math.keio.ac.jp */ ++ ++/* Period parameters */ ++#define MP3_DITH_N 624 ++#define MP3_DITH_M 397 ++#define MATRIX_A 0x9908b0df /* constant vector a */ ++#define UPPER_MASK 0x80000000 /* most significant w-r bits */ ++#define LOWER_MASK 0x7fffffff /* least significant r bits */ ++ ++/* Tempering parameters */ ++#define TEMPERING_MASK_B 0x9d2c5680 ++#define TEMPERING_MASK_C 0xefc60000 ++#define TEMPERING_SHIFT_U(y) (y >> 11) ++#define TEMPERING_SHIFT_S(y) (y << 7) ++#define TEMPERING_SHIFT_T(y) (y << 15) ++#define TEMPERING_SHIFT_L(y) (y >> 18) ++ ++static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */ ++static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */ ++ ++/* initializing the array with a NONZERO seed */ ++void sgenrand(unsigned long seed) ++{ ++ /* setting initial seeds to mt[MP3_DITH_N] using */ ++ /* the generator Line 25 of Table 1 in */ ++ /* [KNUTH 1981, The Art of Computer Programming */ ++ /* Vol. 2 (2nd Ed.), pp102] */ ++ mt[0]= seed & 0xffffffff; ++ for (mti=1; mti<MP3_DITH_N; mti++) ++ mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; ++} ++ ++unsigned long genrand(void) ++{ ++ unsigned long y; ++ static unsigned long mag01[2]={0x0, MATRIX_A}; ++ /* mag01[x] = x * MATRIX_A for x=0,1 */ ++ ++ if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */ ++ int kk; ++ ++ if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */ ++ sgenrand(4357); /* a default initial seed is used */ ++ ++ for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) { ++ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); ++ mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1]; ++ } ++ for (;kk<MP3_DITH_N-1;kk++) { ++ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); ++ mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1]; ++ } ++ y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); ++ mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1]; ++ ++ mti = 0; ++ } ++ ++ y = mt[mti++]; ++ y ^= TEMPERING_SHIFT_U(y); ++ y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; ++ y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; ++ y ^= TEMPERING_SHIFT_L(y); ++ ++ return y; ++} ++ ++long triangular_dither_noise(int nbits) { ++ // parameter nbits : the peak-to-peak amplitude desired (in bits) ++ // use with nbits set to 2 + nber of bits to be trimmed. ++ // (because triangular is made from two uniformly distributed processes, ++ // it starts at 2 bits peak-to-peak amplitude) ++ // see The Theory of Dithered Quantization by Robert Alexander Wannamaker ++ // for complete proof of why that's optimal ++ ++ long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[ ++ //int signe = (v>0) ? 1 : -1; ++ long P = 1 << (32 - nbits); // the power of 2 ++ v /= P; ++ // now v in ]-2^(nbits-1), 2^(nbits-1) [ ++ ++ return v; ++} ++ ++#endif // MP3_DITHERING ++ ++/************************ decoder functions ***************************/ ++ ++/* ++================= ++S_MP3_Scale ++ ++Converts the signal to 16 bit LE-PCM data and does dithering. ++ ++- borrowed from xmms-mad plugin source. ++================= ++*/ ++ ++/* ++ * xmms-mad - mp3 plugin for xmms ++ * Copyright (C) 2001-2002 Sam Clegg ++ */ ++ ++signed int S_MP3_Scale(mad_fixed_t sample) ++{ ++ int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16; ++#ifdef MP3_DITHERING ++ int dither; ++#endif ++ ++ // round ++ sample += (1L << (n_bits_to_loose - 1)); ++ ++#ifdef MP3_DITHERING ++ dither = triangular_dither_noise(n_bits_to_loose + 1); ++ sample += dither; ++#endif ++ ++ /* clip */ ++ if (sample >= MAD_F_ONE) ++ sample = MAD_F_ONE - 1; ++ else if (sample < -MAD_F_ONE) ++ sample = -MAD_F_ONE; ++ ++ /* quantize */ ++ return sample >> n_bits_to_loose; ++} ++ ++ ++ ++/* ++================= ++S_MP3_PCMCopy ++ ++Copy and convert pcm data until bytecount bytes have been written. ++return the position in pcm->samples. ++indicate the amount of actually written bytes in wrotecnt. ++================= ++*/ ++ ++int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs, ++ int sampleofs, int bytecount, int *wrotecnt) ++{ ++ int written = 0; ++ signed int sample; ++ int framesize = pcm->channels * MP3_SAMPLE_WIDTH; ++ ++ // add new pcm data. ++ while(written < bytecount && sampleofs < pcm->length) ++ { ++ sample = S_MP3_Scale(pcm->samples[0][sampleofs]); ++ ++#ifdef Q3_BIG_ENDIAN ++ // output to 16 bit big endian PCM ++ buf[bufofs++] = (sample >> 8) & 0xff; ++ buf[bufofs++] = sample & 0xff; ++#else ++ // output to 16 bit little endian PCM ++ buf[bufofs++] = sample & 0xff; ++ buf[bufofs++] = (sample >> 8) & 0xff; ++#endif ++ ++ if(pcm->channels == 2) ++ { ++ sample = S_MP3_Scale(pcm->samples[1][sampleofs]); ++ ++#ifdef Q3_BIG_ENDIAN ++ buf[bufofs++] = (sample >> 8) & 0xff; ++ buf[bufofs++] = sample & 0xff; ++#else ++ buf[bufofs++] = sample & 0xff; ++ buf[bufofs++] = (sample >> 8) & 0xff; ++#endif ++ } ++ ++ sampleofs++; ++ written += framesize; ++ } ++ ++ if(wrotecnt) ++ *wrotecnt = written; ++ ++ return sampleofs; ++} ++ ++ ++/* ++================= ++S_MP3_Decode ++================= ++*/ ++ ++// gets executed for every decoded frame. ++int S_MP3_Decode(snd_stream_t *stream) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ struct mad_stream *madstream; ++ struct mad_frame *madframe; ++ struct mad_synth *madsynth; ++ struct mad_pcm *pcm; ++ int cursize; ++ int samplecount; ++ int needcount; ++ int wrote; ++ int retval; ++ ++ if(!stream) ++ return -1; ++ ++ mp3info = stream->ptr; ++ madstream = &mp3info->madstream; ++ madframe = &mp3info->madframe; ++ ++ if(mad_frame_decode(madframe, madstream)) ++ { ++ if(madstream->error == MAD_ERROR_BUFLEN) ++ { ++ // we need more data. Read another chunk. ++ retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf)); ++ ++ // call myself again now that buffer is full. ++ if(retval > 0) ++ retval = S_MP3_Decode(stream); ++ } ++ else if(MAD_RECOVERABLE(madstream->error)) ++ { ++ mad_stream_skip(madstream, madstream->skiplen); ++ return S_MP3_Decode(stream); ++ } ++ else ++ retval = -1; ++ ++ return retval; ++ } ++ ++ // check whether this really is an mp3 ++ if(madframe->header.layer != MAD_LAYER_III) ++ return -1; ++ ++ // generate pcm data ++ madsynth = &mp3info->madsynth; ++ mad_synth_frame(madsynth, madframe); ++ ++ pcm = &madsynth->pcm; ++ ++ // perform a few checks to see whether something changed that shouldn't. ++ ++ if(stream->info.rate != pcm->samplerate || ++ stream->info.channels != pcm->channels) ++ { ++ return -1; ++ } ++ // see whether we have got enough data now. ++ cursize = pcm->length * pcm->channels * stream->info.width; ++ needcount = mp3info->destsize - mp3info->destlen; ++ ++ // Copy exactly as many samples as required. ++ samplecount = S_MP3_PCMCopy(mp3info->dest, pcm, ++ mp3info->destlen, 0, needcount, &wrote); ++ mp3info->destlen += wrote; ++ ++ if(samplecount < pcm->length) ++ { ++ // Not all samples got copied. Copy the rest into the pcm buffer. ++ samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, ++ mp3info->buflen, ++ samplecount, ++ mp3info->pcmbufsize - mp3info->buflen, ++ &wrote); ++ mp3info->buflen += wrote; ++ ++ ++ if(samplecount < pcm->length) ++ { ++ // The pcm buffer was not large enough. Make it bigger. ++ byte *newbuf = Z_Malloc(cursize); ++ ++ if(mp3info->pcmbuf) ++ { ++ memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen); ++ Z_Free(mp3info->pcmbuf); ++ } ++ ++ mp3info->pcmbuf = newbuf; ++ mp3info->pcmbufsize = cursize; ++ ++ samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, ++ mp3info->buflen, ++ samplecount, ++ mp3info->pcmbufsize - mp3info->buflen, ++ &wrote); ++ mp3info->buflen += wrote; ++ } ++ ++ // we're definitely done. ++ retval = 0; ++ } ++ else if(mp3info->destlen >= mp3info->destsize) ++ retval = 0; ++ else ++ retval = 1; ++ ++ return retval; ++} ++ ++/*************** Callback functions for quake3 ***************/ ++ ++/* ++================= ++S_MP3_CodecOpenStream ++================= ++*/ ++ ++snd_stream_t *S_MP3_CodecOpenStream(const char *filename) ++{ ++ snd_stream_t *stream; ++ struct snd_codec_mp3_info *mp3info; ++ ++ // Open the stream ++ stream = S_CodecUtilOpen(filename, &mp3_codec); ++ if(!stream || stream->length <= 0) ++ return NULL; ++ ++ // We have to scan through the MP3 to determine the important mp3 info. ++ if(S_MP3_Scanfile(stream) < 0) ++ { ++ // scanning didn't work out... ++ S_CodecUtilClose(stream); ++ return NULL; ++ } ++ ++ // Initialize the mp3 info structure we need for streaming ++ mp3info = Z_Malloc(sizeof(*mp3info)); ++ if(!mp3info) ++ { ++ S_CodecUtilClose(stream); ++ return NULL; ++ } ++ ++ stream->ptr = mp3info; ++ ++ // initialize the libmad control structures. ++ mad_stream_init(&mp3info->madstream); ++ mad_frame_init(&mp3info->madframe); ++ mad_synth_init(&mp3info->madsynth); ++ ++ if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0) ++ { ++ // we didnt read anything, that's bad. ++ S_MP3_CodecCloseStream(stream); ++ return NULL; ++ } ++ ++ return stream; ++} ++ ++/* ++================= ++S_MP3_CodecCloseStream ++================= ++*/ ++ ++// free all memory we allocated. ++void S_MP3_CodecCloseStream(snd_stream_t *stream) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ ++ if(!stream) ++ return; ++ ++ // free all data in our mp3info tree ++ ++ if(stream->ptr) ++ { ++ mp3info = stream->ptr; ++ ++ if(mp3info->pcmbuf) ++ Z_Free(mp3info->pcmbuf); ++ ++ mad_synth_finish(&mp3info->madsynth); ++ mad_frame_finish(&mp3info->madframe); ++ mad_stream_finish(&mp3info->madstream); ++ ++ Z_Free(stream->ptr); ++ } ++ ++ S_CodecUtilClose(stream); ++} ++ ++/* ++================= ++S_MP3_CodecReadStream ++================= ++*/ ++int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ int retval; ++ ++ if(!stream) ++ return -1; ++ ++ mp3info = stream->ptr; ++ ++ // Make sure we get complete frames all the way through. ++ bytes -= bytes % (stream->info.channels * stream->info.width); ++ ++ if(mp3info->buflen) ++ { ++ if(bytes < mp3info->buflen) ++ { ++ // we still have enough bytes in our decoded pcm buffer ++ memcpy(buffer, mp3info->pcmbuf, bytes); ++ ++ // remove the portion from our buffer. ++ mp3info->buflen -= bytes; ++ memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen); ++ return bytes; ++ } ++ else ++ { ++ // copy over the samples we already have. ++ memcpy(buffer, mp3info->pcmbuf, mp3info->buflen); ++ mp3info->destlen = mp3info->buflen; ++ mp3info->buflen = 0; ++ } ++ } ++ else ++ mp3info->destlen = 0; ++ ++ mp3info->dest = buffer; ++ mp3info->destsize = bytes; ++ ++ do ++ { ++ retval = S_MP3_Decode(stream); ++ } while(retval > 0); ++ ++ // if there was an error return nothing. ++ if(retval < 0) ++ return 0; ++ ++ return mp3info->destlen; ++} ++ ++/* ++===================================================================== ++S_MP3_CodecLoad ++ ++We handle S_MP3_CodecLoad as a special case of the streaming functions ++where we read the whole stream at once. ++====================================================================== ++*/ ++void *S_MP3_CodecLoad(const char *filename, snd_info_t *info) ++{ ++ snd_stream_t *stream; ++ byte *pcmbuffer; ++ ++ // check if input is valid ++ if(!filename) ++ return NULL; ++ ++ stream = S_MP3_CodecOpenStream(filename); ++ ++ if(!stream) ++ return NULL; ++ ++ // copy over the info ++ info->rate = stream->info.rate; ++ info->width = stream->info.width; ++ info->channels = stream->info.channels; ++ info->samples = stream->info.samples; ++ info->dataofs = stream->info.dataofs; ++ ++ // allocate enough buffer for all pcm data ++ pcmbuffer = Z_Malloc(stream->info.size); ++ if(!pcmbuffer) ++ { ++ S_MP3_CodecCloseStream(stream); ++ return NULL; ++ } ++ ++ info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer); ++ ++ if(info->size <= 0) ++ { ++ // we didn't read anything at all. darn. ++ Z_Free(pcmbuffer); ++ pcmbuffer = NULL; ++ } ++ ++ S_MP3_CodecCloseStream(stream); ++ ++ return pcmbuffer; ++} ++ ++#endif // USE_CODEC_MP3 diff --git a/games/ioquake3/files/patch-Makefile b/games/ioquake3/files/patch-Makefile index c2732bfca0d6..70d1aa3fe694 100644 --- a/games/ioquake3/files/patch-Makefile +++ b/games/ioquake3/files/patch-Makefile @@ -1,6 +1,6 @@ --- Makefile.orig Tue Nov 28 19:05:39 2006 -+++ Makefile Tue Dec 26 00:19:11 2006 -@@ -26,11 +26,19 @@ ++++ Makefile Fri Sep 14 14:44:03 2007 +@@ -26,11 +26,20 @@ endif endif @@ -15,6 +15,7 @@ +BUILD_GAME_SO?=0 +BUILD_SERVER?=0 +HAVE_VM_COMPILED?=false ++USE_CODEC_MP3?=0 +USE_CODEC_VORBIS?=0 +USE_LOCAL_HEADERS?=0 +USE_OPENAL?=0 @@ -25,7 +26,7 @@ ############################################################################# # -@@ -88,30 +96,10 @@ +@@ -88,30 +97,10 @@ endif export USE_CCACHE @@ -57,7 +58,41 @@ CDIR=$(MOUNT_DIR)/client SDIR=$(MOUNT_DIR)/server RDIR=$(MOUNT_DIR)/renderer -@@ -444,18 +432,12 @@ +@@ -185,6 +174,10 @@ + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ BASE_CFLAGS += -DUSE_CODEC_MP3=1 ++ endif ++ + ifeq ($(USE_SDL),1) + BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 $(shell sdl-config --cflags) + GL_CFLAGS = +@@ -243,6 +236,10 @@ + endif + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ CLIENT_LDFLAGS += -lmad ++ endif ++ + ifeq ($(USE_CODEC_VORBIS),1) + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg + endif +@@ -342,6 +339,11 @@ + endif + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ BASE_CFLAGS += -DUSE_CODEC_MP3=1 ++ CLIENT_LDFLAGS += -lmad ++ endif ++ + ifeq ($(USE_CODEC_VORBIS),1) + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg +@@ -444,18 +446,12 @@ ifeq ($(PLATFORM),freebsd) @@ -79,7 +114,7 @@ ifeq ($(USE_OPENAL),1) BASE_CFLAGS += -DUSE_OPENAL=1 -@@ -468,47 +450,61 @@ +@@ -468,47 +464,61 @@ BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 endif @@ -164,7 +199,7 @@ endif endif -@@ -516,7 +512,6 @@ +@@ -516,7 +526,6 @@ CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif @@ -172,7 +207,7 @@ else # ifeq freebsd ############################################################################# -@@ -670,24 +665,25 @@ +@@ -670,24 +679,25 @@ TARGETS = ifneq ($(BUILD_SERVER),0) @@ -209,7 +244,7 @@ endif ifneq ($(BUILD_GAME_QVM),0) -@@ -749,11 +745,11 @@ +@@ -749,11 +759,11 @@ $(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEBUG_CFLAGS) $(DEPEND_CFLAGS)" build_release: B=$(BR) @@ -223,7 +258,15 @@ targets: $(TARGETS) -@@ -964,13 +960,10 @@ +@@ -836,6 +846,7 @@ + $(B)/client/snd_codec.o \ + $(B)/client/snd_codec_wav.o \ + $(B)/client/snd_codec_ogg.o \ ++ $(B)/client/snd_codec_mp3.o \ + \ + $(B)/client/qal.o \ + $(B)/client/snd_openal.o \ +@@ -964,13 +975,10 @@ ifeq ($(ARCH),i386) Q3OBJ += $(B)/client/vm_x86.o endif @@ -239,7 +282,7 @@ Q3OBJ += $(B)/client/$(VM_PPC).o endif endif -@@ -1017,10 +1010,10 @@ +@@ -1017,10 +1025,10 @@ $(B)/client/sdl_glimp_smp.o endif @@ -252,7 +295,15 @@ $(CC) -o $@ $(Q3OBJ) $(Q3POBJ_SMP) $(CLIENT_LDFLAGS) \ $(THREAD_LDFLAGS) $(LDFLAGS) $(LIBSDLMAIN) -@@ -1317,18 +1310,15 @@ +@@ -1056,6 +1064,7 @@ + $(B)/client/snd_codec.o : $(CDIR)/snd_codec.c; $(DO_CC) + $(B)/client/snd_codec_wav.o : $(CDIR)/snd_codec_wav.c; $(DO_CC) + $(B)/client/snd_codec_ogg.o : $(CDIR)/snd_codec_ogg.c; $(DO_CC) ++$(B)/client/snd_codec_mp3.o : $(CDIR)/snd_codec_mp3.c; $(DO_CC) + + $(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) + $(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) +@@ -1317,18 +1326,15 @@ ifeq ($(ARCH),i386) Q3DOBJ += $(B)/ded/vm_x86.o endif @@ -274,7 +325,7 @@ $(CC) -o $@ $(Q3DOBJ) $(LDFLAGS) $(B)/ded/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_DED_CC) -@@ -1445,7 +1435,7 @@ +@@ -1445,7 +1451,7 @@ Q3CGOBJ = $(Q3CGOBJ_) $(B)/baseq3/cgame/cg_syscalls.o Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -283,7 +334,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ) $(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm -@@ -1486,7 +1476,7 @@ +@@ -1486,7 +1492,7 @@ MPCGOBJ = $(MPCGOBJ_) $(B)/missionpack/cgame/cg_syscalls.o MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm) $(B)/missionpack/game/bg_lib.asm @@ -292,7 +343,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ) $(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm -@@ -1536,7 +1526,7 @@ +@@ -1536,7 +1542,7 @@ Q3GOBJ = $(Q3GOBJ_) $(B)/baseq3/game/g_syscalls.o Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -301,7 +352,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) $(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm -@@ -1584,7 +1574,7 @@ +@@ -1584,7 +1590,7 @@ MPGOBJ = $(MPGOBJ_) $(B)/missionpack/game/g_syscalls.o MPGVMOBJ = $(MPGOBJ_:%.o=%.asm) $(B)/missionpack/game/bg_lib.asm @@ -310,7 +361,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ) $(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm -@@ -1644,7 +1634,7 @@ +@@ -1644,7 +1650,7 @@ Q3UIOBJ = $(Q3UIOBJ_) $(B)/missionpack/ui/ui_syscalls.o Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -319,7 +370,7 @@ $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ) $(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm -@@ -1669,7 +1659,7 @@ +@@ -1669,7 +1675,7 @@ MPUIOBJ = $(MPUIOBJ_) $(B)/missionpack/ui/ui_syscalls.o MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm diff --git a/games/ioquake3/pkg-message b/games/ioquake3/pkg-message index a812c9d679ba..1f128f1231e9 100644 --- a/games/ioquake3/pkg-message +++ b/games/ioquake3/pkg-message @@ -12,4 +12,6 @@ they have additional variables which would be removed if other engines overwrite them. But you can safely copy the original directory to the new one for the first time. +If you enabled CELLSHADING, check files/extra-patch-cellshading for variables. + ============================================================================== diff --git a/games/iourbanterror/Makefile b/games/iourbanterror/Makefile index c2f42bfbbec3..cb37008aa1c1 100644 --- a/games/iourbanterror/Makefile +++ b/games/iourbanterror/Makefile @@ -19,8 +19,10 @@ USE_BZIP2= yes USE_GMAKE= yes OPTIONS= CLIENT "Build client" on \ + CELLSHADING "Enable Cell Shading effect" off \ GAMELIBS "Build game libraries (when not mandatory)" off \ DEDICATED "Build dedicated server" on \ + MP3 "Enable MP3 support" off \ OPENAL "Enable OpenAL (3D sound) support" off \ OPENAL_DLOPEN "Enable dynamic loading of OpenAL" off \ OPTIMIZED_CFLAGS "Enable compilation optimizations" on \ @@ -29,7 +31,7 @@ OPTIONS= CLIENT "Build client" on \ SMP "Build SMP (threaded) client" on \ VORBIS "Enable Ogg Vorbis codec support" off -MAKE_ENV+= DEFAULT_BASEDIR="${Q3DIR}" LIBDIR="${LIBDIR}" \ +MAKE_ENV= DEFAULT_BASEDIR="${Q3DIR}" LIBDIR="${LIBDIR}" \ PTHREAD_LIBS="${PTHREAD_LIBS}" PLIST_SUB= LIBDIR="${LIBDIR:S/${PREFIX}\///}" @@ -53,6 +55,10 @@ HAVE_VM_COMPILED= yes MAKE_ENV+= HAVE_VM_COMPILED=true .endif +.if defined(WITH_CELLSHADING) +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-cellshading +.endif + .if !defined(WITHOUT_CLIENT) || !defined(WITHOUT_SMP) # OpenAL . if defined(WITH_OPENAL) @@ -104,6 +110,12 @@ PLIST_SUB+= GAMELIBS="" PLIST_SUB+= GAMELIBS="@comment " .endif +.if defined(WITH_MP3) +EXTRA_PATCHES+= ${FILESDIR}/extra-patch-mp3 +LIB_DEPENDS+= mad.2:${PORTSDIR}/audio/libmad +MAKE_ENV+= USE_CODEC_MP3=1 +.endif + .if !defined(WITHOUT_OPTIMIZED_CFLAGS) MAKE_ENV+= USE_OPTIMIZED_CFLAGS=1 .endif diff --git a/games/iourbanterror/files/extra-patch-cellshading b/games/iourbanterror/files/extra-patch-cellshading new file mode 100644 index 000000000000..ce459a17bd45 --- /dev/null +++ b/games/iourbanterror/files/extra-patch-cellshading @@ -0,0 +1,933 @@ +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 diff --git a/games/iourbanterror/files/extra-patch-mp3 b/games/iourbanterror/files/extra-patch-mp3 new file mode 100644 index 000000000000..b33f2a660571 --- /dev/null +++ b/games/iourbanterror/files/extra-patch-mp3 @@ -0,0 +1,753 @@ +Index: code/client/snd_codec.c +=================================================================== +--- code/client/snd_codec.c (revision 917) ++++ code/client/snd_codec.c (working copy) +@@ -105,6 +105,9 @@ + #if USE_CODEC_VORBIS + S_CodecRegister(&ogg_codec); + #endif ++#if USE_CODEC_MP3 ++ S_CodecRegister(&mp3_codec); ++#endif + } + + /* +Index: code/client/snd_codec.h +=================================================================== +--- code/client/snd_codec.h (revision 917) ++++ code/client/snd_codec.h (working copy) +@@ -95,4 +95,13 @@ + int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); + #endif // USE_CODEC_VORBIS + ++// MP3 codec ++#ifdef USE_CODEC_MP3 ++extern snd_codec_t mp3_codec; ++void *S_MP3_CodecLoad(const char *filename, snd_info_t *info); ++snd_stream_t *S_MP3_CodecOpenStream(const char *filename); ++void S_MP3_CodecCloseStream(snd_stream_t *stream); ++int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); ++#endif // USE_CODEC_MP3 ++ + #endif // !_SND_CODEC_H_ +Index: code/client/snd_codec_mp3.c +=================================================================== +--- code/client/snd_codec_mp3.c (revision 0) ++++ code/client/snd_codec_mp3.c (revision 0) +@@ -0,0 +1,716 @@ ++/* ++=========================================================================== ++Copyright (C) 1999-2005 Id Software, Inc. ++Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) ++Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de> ++Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de> ++ ++This file is part of Quake III Arena source code. ++ ++Quake III Arena source code is free software; you can redistribute it ++and/or modify it under the terms of the GNU General Public License as ++published by the Free Software Foundation; either version 2 of the License, ++or (at your option) any later version. ++ ++Quake III Arena source code is distributed in the hope that it will be ++useful, but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with Quake III Arena source code; if not, write to the Free Software ++Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++=========================================================================== ++*/ ++ ++// MP3 support is enabled by this define ++#if USE_CODEC_MP3 ++ ++// includes for the Q3 sound system ++#include "client.h" ++#include "snd_codec.h" ++ ++// includes for the MP3 codec ++#include <mad.h> ++ ++#define MP3_SAMPLE_WIDTH 2 ++#define MP3_PCMSAMPLES_PERSLICE 32 ++ ++// buffer size used when reading through the mp3 ++#define MP3_DATA_BUFSIZ 128*1024 ++ ++// undefine this if you don't want any dithering. ++#define MP3_DITHERING ++ ++// Q3 MP3 codec ++snd_codec_t mp3_codec = ++{ ++ ".mp3", ++ S_MP3_CodecLoad, ++ S_MP3_CodecOpenStream, ++ S_MP3_CodecReadStream, ++ S_MP3_CodecCloseStream, ++ NULL ++}; ++ ++// structure used for info purposes ++struct snd_codec_mp3_info ++{ ++ byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed ++ // by the decoder. ++ struct mad_stream madstream; // uses encbuf as buffer. ++ struct mad_frame madframe; // control structures for libmad. ++ struct mad_synth madsynth; ++ ++ byte *pcmbuf; // buffer for not-used samples. ++ int buflen; // length of buffer data. ++ int pcmbufsize; // amount of allocated memory for ++ // pcmbuf. This should have at least ++ // the size of a decoded mp3 frame. ++ ++ byte *dest; // copy decoded data here. ++ int destlen; // amount of already copied data. ++ int destsize; // amount of bytes we must decode. ++}; ++ ++/*************** MP3 utility functions ***************/ ++ ++/* ++================= ++S_MP3_ReadData ++================= ++*/ ++ ++// feed libmad with data ++int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize) ++{ ++ int retval; ++ int leftover; ++ ++ if(!stream) ++ return -1; ++ ++ leftover = madstream->bufend - madstream->next_frame; ++ if(leftover > 0) ++ memmove(encbuf, madstream->this_frame, leftover); ++ ++ ++ // Fill the buffer right to the end ++ ++ retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file); ++ ++ if(retval <= 0) ++ { ++ // EOF reached, that's ok. ++ return 0; ++ } ++ ++ mad_stream_buffer(madstream, encbuf, retval + leftover); ++ ++ return retval; ++} ++ ++ ++/* ++================= ++S_MP3_Scanfile ++ ++to determine the samplecount, we apparently must get *all* headers :( ++I basically used the xmms-mad plugin source to see how this stuff works. ++ ++returns a value < 0 on error. ++================= ++*/ ++ ++int S_MP3_Scanfile(snd_stream_t *stream) ++{ ++ struct mad_stream madstream; ++ struct mad_header madheader; ++ int retval; ++ int samplecount; ++ byte encbuf[MP3_DATA_BUFSIZ]; ++ ++ // error out on invalid input. ++ if(!stream) ++ return -1; ++ ++ mad_stream_init(&madstream); ++ mad_header_init(&madheader); ++ ++ while(1) ++ { ++ retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf)); ++ if(retval < 0) ++ return -1; ++ else if(retval == 0) ++ break; ++ ++ // Start decoding the headers. ++ while(1) ++ { ++ if((retval = mad_header_decode(&madheader, &madstream)) < 0) ++ { ++ if(madstream.error == MAD_ERROR_BUFLEN) ++ { ++ // We need to read more data ++ break; ++ } ++ ++ if(!MAD_RECOVERABLE (madstream.error)) ++ { ++ // unrecoverable error... we must bail out. ++ return retval; ++ } ++ ++ mad_stream_skip(&madstream, madstream.skiplen); ++ continue; ++ } ++ ++ // we got a valid header. ++ ++ if(madheader.layer != MAD_LAYER_III) ++ { ++ // we don't support non-mp3s ++ return -1; ++ } ++ ++ if(!stream->info.samples) ++ { ++ // This here is the very first frame. Set initial values now, ++ // that we expect to stay constant throughout the whole mp3. ++ ++ stream->info.rate = madheader.samplerate; ++ stream->info.width = MP3_SAMPLE_WIDTH; ++ stream->info.channels = MAD_NCHANNELS(&madheader); ++ stream->info.samples = 0; ++ stream->info.size = 0; // same here. ++ stream->info.dataofs = 0; ++ } ++ else ++ { ++ // Check whether something changed that shouldn't. ++ ++ if(stream->info.rate != madheader.samplerate || ++ stream->info.channels != MAD_NCHANNELS(&madheader)) ++ return -1; ++ } ++ ++ // Update the counters ++ samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE; ++ stream->info.samples += samplecount; ++ stream->info.size += samplecount * stream->info.channels * stream->info.width; ++ } ++ } ++ ++ // Reset the file pointer so we can do the real decoding. ++ FS_Seek(stream->file, 0, FS_SEEK_SET); ++ ++ return 0; ++} ++ ++/************************ dithering functions ***************************/ ++ ++#ifdef MP3_DITHERING ++ ++// All dithering done here is taken from the GPL'ed xmms-mad plugin. ++ ++/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */ ++/* Any feedback is very welcome. For any question, comments, */ ++/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */ ++/* matumoto@math.keio.ac.jp */ ++ ++/* Period parameters */ ++#define MP3_DITH_N 624 ++#define MP3_DITH_M 397 ++#define MATRIX_A 0x9908b0df /* constant vector a */ ++#define UPPER_MASK 0x80000000 /* most significant w-r bits */ ++#define LOWER_MASK 0x7fffffff /* least significant r bits */ ++ ++/* Tempering parameters */ ++#define TEMPERING_MASK_B 0x9d2c5680 ++#define TEMPERING_MASK_C 0xefc60000 ++#define TEMPERING_SHIFT_U(y) (y >> 11) ++#define TEMPERING_SHIFT_S(y) (y << 7) ++#define TEMPERING_SHIFT_T(y) (y << 15) ++#define TEMPERING_SHIFT_L(y) (y >> 18) ++ ++static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */ ++static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */ ++ ++/* initializing the array with a NONZERO seed */ ++void sgenrand(unsigned long seed) ++{ ++ /* setting initial seeds to mt[MP3_DITH_N] using */ ++ /* the generator Line 25 of Table 1 in */ ++ /* [KNUTH 1981, The Art of Computer Programming */ ++ /* Vol. 2 (2nd Ed.), pp102] */ ++ mt[0]= seed & 0xffffffff; ++ for (mti=1; mti<MP3_DITH_N; mti++) ++ mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; ++} ++ ++unsigned long genrand(void) ++{ ++ unsigned long y; ++ static unsigned long mag01[2]={0x0, MATRIX_A}; ++ /* mag01[x] = x * MATRIX_A for x=0,1 */ ++ ++ if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */ ++ int kk; ++ ++ if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */ ++ sgenrand(4357); /* a default initial seed is used */ ++ ++ for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) { ++ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); ++ mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1]; ++ } ++ for (;kk<MP3_DITH_N-1;kk++) { ++ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); ++ mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1]; ++ } ++ y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); ++ mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1]; ++ ++ mti = 0; ++ } ++ ++ y = mt[mti++]; ++ y ^= TEMPERING_SHIFT_U(y); ++ y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; ++ y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; ++ y ^= TEMPERING_SHIFT_L(y); ++ ++ return y; ++} ++ ++long triangular_dither_noise(int nbits) { ++ // parameter nbits : the peak-to-peak amplitude desired (in bits) ++ // use with nbits set to 2 + nber of bits to be trimmed. ++ // (because triangular is made from two uniformly distributed processes, ++ // it starts at 2 bits peak-to-peak amplitude) ++ // see The Theory of Dithered Quantization by Robert Alexander Wannamaker ++ // for complete proof of why that's optimal ++ ++ long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[ ++ //int signe = (v>0) ? 1 : -1; ++ long P = 1 << (32 - nbits); // the power of 2 ++ v /= P; ++ // now v in ]-2^(nbits-1), 2^(nbits-1) [ ++ ++ return v; ++} ++ ++#endif // MP3_DITHERING ++ ++/************************ decoder functions ***************************/ ++ ++/* ++================= ++S_MP3_Scale ++ ++Converts the signal to 16 bit LE-PCM data and does dithering. ++ ++- borrowed from xmms-mad plugin source. ++================= ++*/ ++ ++/* ++ * xmms-mad - mp3 plugin for xmms ++ * Copyright (C) 2001-2002 Sam Clegg ++ */ ++ ++signed int S_MP3_Scale(mad_fixed_t sample) ++{ ++ int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16; ++#ifdef MP3_DITHERING ++ int dither; ++#endif ++ ++ // round ++ sample += (1L << (n_bits_to_loose - 1)); ++ ++#ifdef MP3_DITHERING ++ dither = triangular_dither_noise(n_bits_to_loose + 1); ++ sample += dither; ++#endif ++ ++ /* clip */ ++ if (sample >= MAD_F_ONE) ++ sample = MAD_F_ONE - 1; ++ else if (sample < -MAD_F_ONE) ++ sample = -MAD_F_ONE; ++ ++ /* quantize */ ++ return sample >> n_bits_to_loose; ++} ++ ++ ++ ++/* ++================= ++S_MP3_PCMCopy ++ ++Copy and convert pcm data until bytecount bytes have been written. ++return the position in pcm->samples. ++indicate the amount of actually written bytes in wrotecnt. ++================= ++*/ ++ ++int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs, ++ int sampleofs, int bytecount, int *wrotecnt) ++{ ++ int written = 0; ++ signed int sample; ++ int framesize = pcm->channels * MP3_SAMPLE_WIDTH; ++ ++ // add new pcm data. ++ while(written < bytecount && sampleofs < pcm->length) ++ { ++ sample = S_MP3_Scale(pcm->samples[0][sampleofs]); ++ ++#ifdef Q3_BIG_ENDIAN ++ // output to 16 bit big endian PCM ++ buf[bufofs++] = (sample >> 8) & 0xff; ++ buf[bufofs++] = sample & 0xff; ++#else ++ // output to 16 bit little endian PCM ++ buf[bufofs++] = sample & 0xff; ++ buf[bufofs++] = (sample >> 8) & 0xff; ++#endif ++ ++ if(pcm->channels == 2) ++ { ++ sample = S_MP3_Scale(pcm->samples[1][sampleofs]); ++ ++#ifdef Q3_BIG_ENDIAN ++ buf[bufofs++] = (sample >> 8) & 0xff; ++ buf[bufofs++] = sample & 0xff; ++#else ++ buf[bufofs++] = sample & 0xff; ++ buf[bufofs++] = (sample >> 8) & 0xff; ++#endif ++ } ++ ++ sampleofs++; ++ written += framesize; ++ } ++ ++ if(wrotecnt) ++ *wrotecnt = written; ++ ++ return sampleofs; ++} ++ ++ ++/* ++================= ++S_MP3_Decode ++================= ++*/ ++ ++// gets executed for every decoded frame. ++int S_MP3_Decode(snd_stream_t *stream) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ struct mad_stream *madstream; ++ struct mad_frame *madframe; ++ struct mad_synth *madsynth; ++ struct mad_pcm *pcm; ++ int cursize; ++ int samplecount; ++ int needcount; ++ int wrote; ++ int retval; ++ ++ if(!stream) ++ return -1; ++ ++ mp3info = stream->ptr; ++ madstream = &mp3info->madstream; ++ madframe = &mp3info->madframe; ++ ++ if(mad_frame_decode(madframe, madstream)) ++ { ++ if(madstream->error == MAD_ERROR_BUFLEN) ++ { ++ // we need more data. Read another chunk. ++ retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf)); ++ ++ // call myself again now that buffer is full. ++ if(retval > 0) ++ retval = S_MP3_Decode(stream); ++ } ++ else if(MAD_RECOVERABLE(madstream->error)) ++ { ++ mad_stream_skip(madstream, madstream->skiplen); ++ return S_MP3_Decode(stream); ++ } ++ else ++ retval = -1; ++ ++ return retval; ++ } ++ ++ // check whether this really is an mp3 ++ if(madframe->header.layer != MAD_LAYER_III) ++ return -1; ++ ++ // generate pcm data ++ madsynth = &mp3info->madsynth; ++ mad_synth_frame(madsynth, madframe); ++ ++ pcm = &madsynth->pcm; ++ ++ // perform a few checks to see whether something changed that shouldn't. ++ ++ if(stream->info.rate != pcm->samplerate || ++ stream->info.channels != pcm->channels) ++ { ++ return -1; ++ } ++ // see whether we have got enough data now. ++ cursize = pcm->length * pcm->channels * stream->info.width; ++ needcount = mp3info->destsize - mp3info->destlen; ++ ++ // Copy exactly as many samples as required. ++ samplecount = S_MP3_PCMCopy(mp3info->dest, pcm, ++ mp3info->destlen, 0, needcount, &wrote); ++ mp3info->destlen += wrote; ++ ++ if(samplecount < pcm->length) ++ { ++ // Not all samples got copied. Copy the rest into the pcm buffer. ++ samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, ++ mp3info->buflen, ++ samplecount, ++ mp3info->pcmbufsize - mp3info->buflen, ++ &wrote); ++ mp3info->buflen += wrote; ++ ++ ++ if(samplecount < pcm->length) ++ { ++ // The pcm buffer was not large enough. Make it bigger. ++ byte *newbuf = Z_Malloc(cursize); ++ ++ if(mp3info->pcmbuf) ++ { ++ memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen); ++ Z_Free(mp3info->pcmbuf); ++ } ++ ++ mp3info->pcmbuf = newbuf; ++ mp3info->pcmbufsize = cursize; ++ ++ samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm, ++ mp3info->buflen, ++ samplecount, ++ mp3info->pcmbufsize - mp3info->buflen, ++ &wrote); ++ mp3info->buflen += wrote; ++ } ++ ++ // we're definitely done. ++ retval = 0; ++ } ++ else if(mp3info->destlen >= mp3info->destsize) ++ retval = 0; ++ else ++ retval = 1; ++ ++ return retval; ++} ++ ++/*************** Callback functions for quake3 ***************/ ++ ++/* ++================= ++S_MP3_CodecOpenStream ++================= ++*/ ++ ++snd_stream_t *S_MP3_CodecOpenStream(const char *filename) ++{ ++ snd_stream_t *stream; ++ struct snd_codec_mp3_info *mp3info; ++ ++ // Open the stream ++ stream = S_CodecUtilOpen(filename, &mp3_codec); ++ if(!stream || stream->length <= 0) ++ return NULL; ++ ++ // We have to scan through the MP3 to determine the important mp3 info. ++ if(S_MP3_Scanfile(stream) < 0) ++ { ++ // scanning didn't work out... ++ S_CodecUtilClose(stream); ++ return NULL; ++ } ++ ++ // Initialize the mp3 info structure we need for streaming ++ mp3info = Z_Malloc(sizeof(*mp3info)); ++ if(!mp3info) ++ { ++ S_CodecUtilClose(stream); ++ return NULL; ++ } ++ ++ stream->ptr = mp3info; ++ ++ // initialize the libmad control structures. ++ mad_stream_init(&mp3info->madstream); ++ mad_frame_init(&mp3info->madframe); ++ mad_synth_init(&mp3info->madsynth); ++ ++ if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0) ++ { ++ // we didnt read anything, that's bad. ++ S_MP3_CodecCloseStream(stream); ++ return NULL; ++ } ++ ++ return stream; ++} ++ ++/* ++================= ++S_MP3_CodecCloseStream ++================= ++*/ ++ ++// free all memory we allocated. ++void S_MP3_CodecCloseStream(snd_stream_t *stream) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ ++ if(!stream) ++ return; ++ ++ // free all data in our mp3info tree ++ ++ if(stream->ptr) ++ { ++ mp3info = stream->ptr; ++ ++ if(mp3info->pcmbuf) ++ Z_Free(mp3info->pcmbuf); ++ ++ mad_synth_finish(&mp3info->madsynth); ++ mad_frame_finish(&mp3info->madframe); ++ mad_stream_finish(&mp3info->madstream); ++ ++ Z_Free(stream->ptr); ++ } ++ ++ S_CodecUtilClose(stream); ++} ++ ++/* ++================= ++S_MP3_CodecReadStream ++================= ++*/ ++int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) ++{ ++ struct snd_codec_mp3_info *mp3info; ++ int retval; ++ ++ if(!stream) ++ return -1; ++ ++ mp3info = stream->ptr; ++ ++ // Make sure we get complete frames all the way through. ++ bytes -= bytes % (stream->info.channels * stream->info.width); ++ ++ if(mp3info->buflen) ++ { ++ if(bytes < mp3info->buflen) ++ { ++ // we still have enough bytes in our decoded pcm buffer ++ memcpy(buffer, mp3info->pcmbuf, bytes); ++ ++ // remove the portion from our buffer. ++ mp3info->buflen -= bytes; ++ memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen); ++ return bytes; ++ } ++ else ++ { ++ // copy over the samples we already have. ++ memcpy(buffer, mp3info->pcmbuf, mp3info->buflen); ++ mp3info->destlen = mp3info->buflen; ++ mp3info->buflen = 0; ++ } ++ } ++ else ++ mp3info->destlen = 0; ++ ++ mp3info->dest = buffer; ++ mp3info->destsize = bytes; ++ ++ do ++ { ++ retval = S_MP3_Decode(stream); ++ } while(retval > 0); ++ ++ // if there was an error return nothing. ++ if(retval < 0) ++ return 0; ++ ++ return mp3info->destlen; ++} ++ ++/* ++===================================================================== ++S_MP3_CodecLoad ++ ++We handle S_MP3_CodecLoad as a special case of the streaming functions ++where we read the whole stream at once. ++====================================================================== ++*/ ++void *S_MP3_CodecLoad(const char *filename, snd_info_t *info) ++{ ++ snd_stream_t *stream; ++ byte *pcmbuffer; ++ ++ // check if input is valid ++ if(!filename) ++ return NULL; ++ ++ stream = S_MP3_CodecOpenStream(filename); ++ ++ if(!stream) ++ return NULL; ++ ++ // copy over the info ++ info->rate = stream->info.rate; ++ info->width = stream->info.width; ++ info->channels = stream->info.channels; ++ info->samples = stream->info.samples; ++ info->dataofs = stream->info.dataofs; ++ ++ // allocate enough buffer for all pcm data ++ pcmbuffer = Z_Malloc(stream->info.size); ++ if(!pcmbuffer) ++ { ++ S_MP3_CodecCloseStream(stream); ++ return NULL; ++ } ++ ++ info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer); ++ ++ if(info->size <= 0) ++ { ++ // we didn't read anything at all. darn. ++ Z_Free(pcmbuffer); ++ pcmbuffer = NULL; ++ } ++ ++ S_MP3_CodecCloseStream(stream); ++ ++ return pcmbuffer; ++} ++ ++#endif // USE_CODEC_MP3 diff --git a/games/iourbanterror/files/patch-Makefile b/games/iourbanterror/files/patch-Makefile index c2732bfca0d6..70d1aa3fe694 100644 --- a/games/iourbanterror/files/patch-Makefile +++ b/games/iourbanterror/files/patch-Makefile @@ -1,6 +1,6 @@ --- Makefile.orig Tue Nov 28 19:05:39 2006 -+++ Makefile Tue Dec 26 00:19:11 2006 -@@ -26,11 +26,19 @@ ++++ Makefile Fri Sep 14 14:44:03 2007 +@@ -26,11 +26,20 @@ endif endif @@ -15,6 +15,7 @@ +BUILD_GAME_SO?=0 +BUILD_SERVER?=0 +HAVE_VM_COMPILED?=false ++USE_CODEC_MP3?=0 +USE_CODEC_VORBIS?=0 +USE_LOCAL_HEADERS?=0 +USE_OPENAL?=0 @@ -25,7 +26,7 @@ ############################################################################# # -@@ -88,30 +96,10 @@ +@@ -88,30 +97,10 @@ endif export USE_CCACHE @@ -57,7 +58,41 @@ CDIR=$(MOUNT_DIR)/client SDIR=$(MOUNT_DIR)/server RDIR=$(MOUNT_DIR)/renderer -@@ -444,18 +432,12 @@ +@@ -185,6 +174,10 @@ + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ BASE_CFLAGS += -DUSE_CODEC_MP3=1 ++ endif ++ + ifeq ($(USE_SDL),1) + BASE_CFLAGS += -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 $(shell sdl-config --cflags) + GL_CFLAGS = +@@ -243,6 +236,10 @@ + endif + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ CLIENT_LDFLAGS += -lmad ++ endif ++ + ifeq ($(USE_CODEC_VORBIS),1) + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg + endif +@@ -342,6 +339,11 @@ + endif + endif + ++ ifeq ($(USE_CODEC_MP3),1) ++ BASE_CFLAGS += -DUSE_CODEC_MP3=1 ++ CLIENT_LDFLAGS += -lmad ++ endif ++ + ifeq ($(USE_CODEC_VORBIS),1) + BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 + CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg +@@ -444,18 +446,12 @@ ifeq ($(PLATFORM),freebsd) @@ -79,7 +114,7 @@ ifeq ($(USE_OPENAL),1) BASE_CFLAGS += -DUSE_OPENAL=1 -@@ -468,47 +450,61 @@ +@@ -468,47 +464,61 @@ BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 endif @@ -164,7 +199,7 @@ endif endif -@@ -516,7 +512,6 @@ +@@ -516,7 +526,6 @@ CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif @@ -172,7 +207,7 @@ else # ifeq freebsd ############################################################################# -@@ -670,24 +665,25 @@ +@@ -670,24 +679,25 @@ TARGETS = ifneq ($(BUILD_SERVER),0) @@ -209,7 +244,7 @@ endif ifneq ($(BUILD_GAME_QVM),0) -@@ -749,11 +745,11 @@ +@@ -749,11 +759,11 @@ $(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEBUG_CFLAGS) $(DEPEND_CFLAGS)" build_release: B=$(BR) @@ -223,7 +258,15 @@ targets: $(TARGETS) -@@ -964,13 +960,10 @@ +@@ -836,6 +846,7 @@ + $(B)/client/snd_codec.o \ + $(B)/client/snd_codec_wav.o \ + $(B)/client/snd_codec_ogg.o \ ++ $(B)/client/snd_codec_mp3.o \ + \ + $(B)/client/qal.o \ + $(B)/client/snd_openal.o \ +@@ -964,13 +975,10 @@ ifeq ($(ARCH),i386) Q3OBJ += $(B)/client/vm_x86.o endif @@ -239,7 +282,7 @@ Q3OBJ += $(B)/client/$(VM_PPC).o endif endif -@@ -1017,10 +1010,10 @@ +@@ -1017,10 +1025,10 @@ $(B)/client/sdl_glimp_smp.o endif @@ -252,7 +295,15 @@ $(CC) -o $@ $(Q3OBJ) $(Q3POBJ_SMP) $(CLIENT_LDFLAGS) \ $(THREAD_LDFLAGS) $(LDFLAGS) $(LIBSDLMAIN) -@@ -1317,18 +1310,15 @@ +@@ -1056,6 +1064,7 @@ + $(B)/client/snd_codec.o : $(CDIR)/snd_codec.c; $(DO_CC) + $(B)/client/snd_codec_wav.o : $(CDIR)/snd_codec_wav.c; $(DO_CC) + $(B)/client/snd_codec_ogg.o : $(CDIR)/snd_codec_ogg.c; $(DO_CC) ++$(B)/client/snd_codec_mp3.o : $(CDIR)/snd_codec_mp3.c; $(DO_CC) + + $(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) + $(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) +@@ -1317,18 +1326,15 @@ ifeq ($(ARCH),i386) Q3DOBJ += $(B)/ded/vm_x86.o endif @@ -274,7 +325,7 @@ $(CC) -o $@ $(Q3DOBJ) $(LDFLAGS) $(B)/ded/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_DED_CC) -@@ -1445,7 +1435,7 @@ +@@ -1445,7 +1451,7 @@ Q3CGOBJ = $(Q3CGOBJ_) $(B)/baseq3/cgame/cg_syscalls.o Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -283,7 +334,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ) $(B)/baseq3/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm -@@ -1486,7 +1476,7 @@ +@@ -1486,7 +1492,7 @@ MPCGOBJ = $(MPCGOBJ_) $(B)/missionpack/cgame/cg_syscalls.o MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm) $(B)/missionpack/game/bg_lib.asm @@ -292,7 +343,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ) $(B)/missionpack/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm -@@ -1536,7 +1526,7 @@ +@@ -1536,7 +1542,7 @@ Q3GOBJ = $(Q3GOBJ_) $(B)/baseq3/game/g_syscalls.o Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -301,7 +352,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) $(B)/baseq3/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm -@@ -1584,7 +1574,7 @@ +@@ -1584,7 +1590,7 @@ MPGOBJ = $(MPGOBJ_) $(B)/missionpack/game/g_syscalls.o MPGVMOBJ = $(MPGOBJ_:%.o=%.asm) $(B)/missionpack/game/bg_lib.asm @@ -310,7 +361,7 @@ $(CC) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ) $(B)/missionpack/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm -@@ -1644,7 +1634,7 @@ +@@ -1644,7 +1650,7 @@ Q3UIOBJ = $(Q3UIOBJ_) $(B)/missionpack/ui/ui_syscalls.o Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm @@ -319,7 +370,7 @@ $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ) $(B)/baseq3/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm -@@ -1669,7 +1659,7 @@ +@@ -1669,7 +1675,7 @@ MPUIOBJ = $(MPUIOBJ_) $(B)/missionpack/ui/ui_syscalls.o MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm) $(B)/baseq3/game/bg_lib.asm diff --git a/games/iourbanterror/pkg-message b/games/iourbanterror/pkg-message index a812c9d679ba..1f128f1231e9 100644 --- a/games/iourbanterror/pkg-message +++ b/games/iourbanterror/pkg-message @@ -12,4 +12,6 @@ they have additional variables which would be removed if other engines overwrite them. But you can safely copy the original directory to the new one for the first time. +If you enabled CELLSHADING, check files/extra-patch-cellshading for variables. + ============================================================================== |