From 04870d3a20169b49cea5a36141d3683c8ad7c99a Mon Sep 17 00:00:00 2001 From: leilei- Date: Fri, 3 Apr 2015 05:53:02 -0400 Subject: [PATCH] - r_roundImagesDown 2 - nonpowerof2 (NPOT) support. No extension checking added yet; use at your own risk! (intended for buffer effects) - r_parseStageSimple - working towards pcx2 support by loading shader stages with the texture last, to approximate blending functions by processing them into having alpha channels (or not, for opaque surfaces). Because I can. - leifx filter change - indicate number of passes to the shader, so the pixel blurring order can be tweaked to further perfection (ridding the left pixel check as that happens) --- code/qcommon/q_shared.h | 2 +- code/renderer_oa/tr_backend.c | 39 +- code/renderer_oa/tr_bloom.c | 10 +- code/renderer_oa/tr_cmds.c | 3 + code/renderer_oa/tr_image.c | 211 +++++-- code/renderer_oa/tr_init.c | 4 +- code/renderer_oa/tr_local.h | 7 +- code/renderer_oa/tr_shade.c | 35 ++ code/renderer_oa/tr_shader.c | 1002 ++++++++++++++++++++++++++++++++- 9 files changed, 1211 insertions(+), 102 deletions(-) diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 03e78ef9..ebc341ee 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -1419,6 +1419,6 @@ int vresHeight; #define LERP( a, b, w ) ( ( a ) * ( 1.0f - ( w ) ) + ( b ) * ( w ) ) -#define LUMA( red, green, blue ) ( 0.2126f * ( red ) + 0.7152f * ( green ) + 0.0722f * ( blue ) ) +#define LUMA( red, green, blue ) ( 0.296875f * ( red ) + 0.5859375f * ( green ) + 0.109375f * ( blue ) ) #endif // __Q_SHARED_H diff --git a/code/renderer_oa/tr_backend.c b/code/renderer_oa/tr_backend.c index ec54299c..dac9768a 100644 --- a/code/renderer_oa/tr_backend.c +++ b/code/renderer_oa/tr_backend.c @@ -475,47 +475,18 @@ static void GL_StatePCX( unsigned long stateBits ) unsigned long diff = stateBits ^ glState.glStateBits; - if ( !diff ) - { - return; - } + // - // check depthFunc bits - // - if ( diff & GLS_DEPTHFUNC_EQUAL ) - { - if ( stateBits & GLS_DEPTHFUNC_EQUAL ) - { - qglDepthFunc( GL_EQUAL ); - } - else - { - qglDepthFunc( GL_LEQUAL ); - } - } - // // check blend bits // - if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - GLenum srcFactor, dstFactor; - if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) - { - srcFactor = GL_SRC_ALPHA; - dstFactor = GL_ONE_MINUS_SRC_ALPHA; // leilei - for pvr debug only! - - qglEnable( GL_BLEND ); - qglBlendFunc( srcFactor, dstFactor ); - } - else - { - qglDisable( GL_BLEND ); - } - } + qglEnable( GL_BLEND ); + qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // // check depthmask // diff --git a/code/renderer_oa/tr_bloom.c b/code/renderer_oa/tr_bloom.c index 31bb334c..50f33fa0 100644 --- a/code/renderer_oa/tr_bloom.c +++ b/code/renderer_oa/tr_bloom.c @@ -136,6 +136,7 @@ static struct { cvar_t *r_film; extern int force32upload; int leifxmode; +int leifxpass; int fakeit = 0; int tvinterlace = 1; @@ -795,6 +796,8 @@ static void R_Bloom_RestoreScreen_Postprocessed( void ) { if (program->u_CC_Saturation > -1) R_GLSL_SetUniform_u_CC_Saturation(program, 1.0); if (program->u_CC_Contrast > -1) R_GLSL_SetUniform_u_CC_Contrast(program, 1.0); + // + if (leifxmode == 3){ R_GLSL_SetUniform_u_CC_Brightness(program, leifxpass); } if (program->u_zFar > -1) R_GLSL_SetUniform_u_zFar(program, tr.viewParms.zFar); GL_SelectTexture(0); @@ -1377,17 +1380,18 @@ void R_LeiFXPostprocessFilterScreen( void ) leifxmode = 3; // filter - 4 pass // The stupidest hack in america R_LeiFX_Stupid_Hack(); + leifxpass = 0; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); + leifxpass = 1; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); + leifxpass = 2; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); + leifxpass = 3; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); - // leifxmode = 2; - // R_Postprocess_BackupScreen(); - // R_Bloom_RestoreScreen_Postprocessed(); } backEnd.doneleifx = qtrue; diff --git a/code/renderer_oa/tr_cmds.c b/code/renderer_oa/tr_cmds.c index a8f85c7c..ebc216f2 100644 --- a/code/renderer_oa/tr_cmds.c +++ b/code/renderer_oa/tr_cmds.c @@ -206,6 +206,8 @@ void RE_SetColor( const float *rgba ) { RE_StretchPic ============= */ + +extern int hackoperation; void RE_StretchPic ( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ) { stretchPicCommand_t *cmd; @@ -217,6 +219,7 @@ void RE_StretchPic ( float x, float y, float w, float h, if ( !cmd ) { return; } + hackoperation = 0; cmd->commandId = RC_STRETCH_PIC; cmd->shader = R_GetShaderByHandle( hShader ); cmd->x = x; diff --git a/code/renderer_oa/tr_image.c b/code/renderer_oa/tr_image.c index 392a91ed..f6eaf37d 100644 --- a/code/renderer_oa/tr_image.c +++ b/code/renderer_oa/tr_image.c @@ -1172,6 +1172,7 @@ static void Upload32( unsigned *data, unsigned *scaledBuffer = NULL; unsigned *resampledBuffer = NULL; int scaled_width, scaled_height; + int orig_width, orig_height; int i, c; byte *scan; GLenum internalFormat = GL_RGB; @@ -1182,28 +1183,61 @@ static void Upload32( unsigned *data, int forceBits = 0; + if (lightMap && r_parseStageSimple->integer) hackoperation = 4; + + // leilei - npot support + orig_width = width; + orig_height = height; + // // convert to exact power of 2 sizes // - for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) - ; - if ( r_roundImagesDown->integer && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - //scaled_width *= 1.5; - ////scaled_height *= 1.5; - if ( scaled_width != width || scaled_height != height ) { - resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - if (hqresample) - Image_Resample32Lerp(data, width, height, resampledBuffer, scaled_width, scaled_height - 1); - else - ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); - data = resampledBuffer; - width = scaled_width; - height = scaled_height; + + + if (r_roundImagesDown->integer == 2) + { + + scaled_width = width; + scaled_height = height; + + //for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + // ; + //for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + // ; + + if ( scaled_width != width || scaled_height != height ) { + resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); + ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); + data = resampledBuffer; + width = scaled_width; + height = scaled_height; + } + + + } + else + { + + for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) + ; + for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) + ; + if ( (r_roundImagesDown->integer == 1) && scaled_width > width ) + scaled_width >>= 1; + if ( (r_roundImagesDown->integer == 1) && scaled_height > height ) + scaled_height >>= 1; + + if ( scaled_width != width || scaled_height != height ) { + resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); + if (hqresample) + Image_Resample32Lerp(data, width, height, resampledBuffer, scaled_width, scaled_height - 1); + else + ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); + data = resampledBuffer; + width = scaled_width; + height = scaled_height; + } + } @@ -1321,8 +1355,48 @@ static void Upload32( unsigned *data, // leilei - additive to alpha for ( i = 0; i < c; i++ ) { + int r, g, b; + vec3_t rgb; + float amplify; byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); + //byte alfa = (scan[i*4]+ scan[i*4 + 1]+ scan[i*4 + 2]) / 3; + + r = scan[i*4 + 0]; + g = scan[i*4 + 1]; + b = scan[i*4 + 2]; + rgb[0] = r; + rgb[1] = g; + rgb[2] = b; + VectorNormalize(rgb); + r = rgb[0] * 256; + g = rgb[1] * 256; + b = rgb[2] * 256; + + if (r>255) r=255; + if (g>255) g=255; + if (b>255) b=255; + + if (scan[i*4 + 0] > r) r = scan[i*4 + 0]; + if (scan[i*4 + 1] > g) g = scan[i*4 + 1]; + if (scan[i*4 + 2] > b) b = scan[i*4 + 2]; + + scan[i*4 + 0] = r; + scan[i*4 + 1] = g; + scan[i*4 + 2] = b; scan[i*4 + 3] = alfa; + + } + + } + + + else if (hackoperation == 2) + { + // leilei - alpha killing + for ( i = 0; i < c; i++ ) + { + scan[i*4 + 3] = 255; + } } @@ -1332,34 +1406,68 @@ static void Upload32( unsigned *data, { for ( i = 0; i < c; i++ ) { - byte alfa = LUMA(scan[i*4] * -1, scan[i*4 + 1] * -1, scan[i*4 + 2] * -1); - scan[i*4 + 3] = alfa; + + byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); + scan[i*4] = 0; + scan[i*4 + 1] = 0; + scan[i*4 + 2] = 0; + scan[i*4 + 3] = alfa; + } } - else if(hackoperation == 4 ) // Multiplies + else if (hackoperation == 4) // modulateply { - int yee; - int yer; - int yeah; - int yo; - for ( i = 0; i < c; i++ ) - { - yee = scan[i*4] - 127 * 1.18; // highlights - yer = scan[i*4] * -1 + 127 ; // darks - if (yee < 0) yee = 0; - if (yer < 0) yer = 0; - yer *= 1.5; - yee = 0; - yeah = yee + yer; - yo = 0; - scan[i*4] = yo; - scan[i*4 + 1] = yo; - scan[i*4 + 2] = yo; - scan[i*4 + 3] = yeah; - } + + for ( i = 0; i < c; i++ ) + { + int r, g, b; + vec3_t rgb; + + float amplify; + byte alfa = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); + //byte alfa = (scan[i*4]+ scan[i*4 + 1]+ scan[i*4 + 2]) / 3; + alfa = sin(alfa/64) * 32; + + amplify = (alfa - 128) / 255; + r = scan[i*4 + 0]; + g = scan[i*4 + 1]; + b = scan[i*4 + 2]; + rgb[0] = r; + rgb[1] = g; + rgb[2] = b; + VectorNormalize(rgb); + r = rgb[0] * 256; + g = rgb[1] * 256; + b = rgb[2] * 256; + + r *= amplify; + g *= amplify; + b *= amplify; + + + if (r<0) r=0; + if (g<0) g=0; + if (b<0) b=0; + + if (r>255) r=255; + if (g>255) g=255; + if (b>255) b=255; + + if (scan[i*4 + 0] > r) r = scan[i*4 + 0]; + if (scan[i*4 + 1] > g) g = scan[i*4 + 1]; + if (scan[i*4 + 2] > b) b = scan[i*4 + 2]; + + scan[i*4 + 0] = r; + scan[i*4 + 1] = g; + scan[i*4 + 2] = b; + scan[i*4 + 3] = alfa; + + } + } + if(r_textureDither->integer) // possibly the stupidest texture dithering ever { #ifdef DONTEVENTHINKABOUTTHIS @@ -2245,6 +2353,8 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height ) ext = COM_GetExtension( localName ); + + if( *ext ) { // Look for the correct loader and use it @@ -2414,8 +2524,25 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) // loadtime = backEnd.refdef.floatTime - oldtime; - image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); + // leilei - if we need to change the texture upload with a special image prefix to separate from differently blended things + if (hackoperation) + { + char hackName[MAX_QPATH]; + char *hackedName; + COM_StripExtension( name, hackName, MAX_QPATH ); + if(hackoperation==1) hackedName = va("%shackadd", hackName); + if(hackoperation==2) hackedName = va("%shacknob", hackName); + if(hackoperation==3) hackedName = va("%shacksub", hackName); + if(hackoperation==4) hackedName = va("%shackmod", hackName); + else hackedName = va("%shackblend", hackName); + image = R_CreateImage( ( char * ) hackedName, pic, width, height, type, flags, 0 ); + } + else + + { + image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); + } ri.Free( pic ); diff --git a/code/renderer_oa/tr_init.c b/code/renderer_oa/tr_init.c index a71c2201..16a48d2e 100644 --- a/code/renderer_oa/tr_init.c +++ b/code/renderer_oa/tr_init.c @@ -202,6 +202,7 @@ cvar_t *r_flaresDlightScale; //cvar_t *r_flaresSurfradii; cvar_t *r_alternateBrightness; // leilei - linux overbright fix cvar_t *r_mockvr; // Leilei - for debugging PVR only! +cvar_t *r_parseStageSimple; // Leilei - for debugging PVR only! cvar_t *r_leifx; // Leilei - leifx nostalgia filter cvar_t *r_modelshader; // Leilei @@ -1282,7 +1283,8 @@ void R_Register( void ) r_flareSun = ri.Cvar_Get( "r_flareSun", "0" , CVAR_ARCHIVE); // it's 0 because mappers expect 0. - r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_ARCHIVE | CVAR_CHEAT); + r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_CHEAT); + r_parseStageSimple = ri.Cvar_Get( "r_parseStageSimple", "0" , CVAR_CHEAT); r_leifx = ri.Cvar_Get( "r_leifx", "0" , CVAR_ARCHIVE | CVAR_LATCH); r_modelshader = ri.Cvar_Get( "r_modelshader", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - load and use special shaders for lightDiffuse models r_detailTextureScale = ri.Cvar_Get( "r_detailtextureScale", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - adjust scale of detail textures diff --git a/code/renderer_oa/tr_local.h b/code/renderer_oa/tr_local.h index e6cf6518..3a9d7f02 100644 --- a/code/renderer_oa/tr_local.h +++ b/code/renderer_oa/tr_local.h @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qfiles.h" #include "../qcommon/qcommon.h" + #include "../renderercommon/tr_public.h" #include "../renderercommon/tr_common.h" #include "../renderercommon/iqm.h" @@ -316,6 +317,10 @@ typedef struct { int isBlend; // leilei - for leifx qboolean isLeiShade; // leilei - for the automatic shader qhandle_t program; + + int imgWidth; + int imgHeight; //leilei for glsl shaders + } shaderStage_t; struct shaderCommands_s; @@ -1344,7 +1349,7 @@ extern cvar_t *r_flaresDlightScale; //extern cvar_t *r_flaresSurfradii; extern cvar_t *r_alternateBrightness; // leilei - alternate brightness - +extern cvar_t *r_parseStageSimple; // Leilei - handling textures into alphas extern cvar_t *r_leifx; // Leilei - leifx nostalgia filter extern cvar_t *r_modelshader; // Leilei - new model shading diff --git a/code/renderer_oa/tr_shade.c b/code/renderer_oa/tr_shade.c index 907ff61c..396f93ce 100644 --- a/code/renderer_oa/tr_shade.c +++ b/code/renderer_oa/tr_shade.c @@ -1031,6 +1031,41 @@ static void ComputeColors( shaderStage_t *pStage ) break; } + // leilei PowerVR Hack + + if (r_parseStageSimple->integer) + { + float scale; + vec3_t normme; + if ((pStage->isBlend == 1) || (pStage->isBlend == 3)){ // additive or subtracive + + for(i = 0; i < tess.numVertexes; i++) + { + scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); + tess.svars.colors[i][3] = scale - tess.svars.colors[i][3]; + if (tess.svars.colors[i][3] > 255) tess.svars.colors[i][3] = 255; + + + normme[0] = tess.svars.colors[i][0]; + normme[1] = tess.svars.colors[i][1]; + normme[2] = tess.svars.colors[i][2]; + + // normme[0] *= (4 * tr.identityLight); + // normme[1] *= (4 * tr.identityLight); + // normme[2] *= (4 * tr.identityLight); + + + VectorNormalize(normme); + + + tess.svars.colors[i][0] = normme[0]*255; + tess.svars.colors[i][1] = normme[1]*255; + tess.svars.colors[i][2] = normme[2]*255; + } + } + + } + // // alphaGen // diff --git a/code/renderer_oa/tr_shader.c b/code/renderer_oa/tr_shader.c index f328b4d4..58b1a843 100644 --- a/code/renderer_oa/tr_shader.c +++ b/code/renderer_oa/tr_shader.c @@ -401,6 +401,8 @@ static qboolean R_GLSL_LoadProgram(glslProgram_t *program, const char *name, con } /* attach fragment shader to program */ + //qglBindRenderbufferEXT(shader_fp, 0); + //qglBindFramebufferEXT(shader_fp, 0); qglAttachObjectARB(program->program, shader_fp); qglDeleteObjectARB(shader_fp); } @@ -1038,6 +1040,10 @@ static void ParseTexMod( char *_text, shaderStage_t *stage ) ParseStage =================== */ + +qboolean ParseStageSimple( shaderStage_t *stage, char **text ); +extern cvar_t *r_parseStageSimple; // Leilei - for debugging PVR only! + static qboolean ParseStage( shaderStage_t *stage, char **text ) { char *token; @@ -1050,6 +1056,14 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) qboolean depthMaskExplicit = qfalse; qboolean stageMipmaps = !shader.noMipMaps; + + // leilei - switch to simple for simple cards + if (r_parseStageSimple->integer){ + + return ParseStageSimple(stage, text); + } + + stage->active = qtrue; Com_Memset(programName, 0, sizeof(programName)); @@ -2817,6 +2831,852 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) return qtrue; } + +/* +=================== +ParseStageSimple + + +leilei - the purpose of this is to load textures after processing their blending properties, + so we can approximate effects on incapable hardware such as Matrox Mystique, S3 ViRGE, + PowerVR PCX2, software rendering... + A lot of things are stripped out (like GLSL and multitexture stuff) +=================== +*/ + +extern int hackoperation; +extern int ismaptexture; +int surfaceflagsy; +qboolean ParseStageSimple( shaderStage_t *stage, char **text ) +{ + char *token; + char programName[MAX_QPATH]; + char programVertexObjects[MAX_PROGRAM_OBJECTS][MAX_QPATH]; + char programFragmentObjects[MAX_PROGRAM_OBJECTS][MAX_QPATH]; + char imageName[MAX_QPATH]; // for loading later + char imageNameAnim0[MAX_QPATH]; + char imageNameAnim1[MAX_QPATH]; + char imageNameAnim2[MAX_QPATH]; + char imageNameAnim3[MAX_QPATH]; + char imageNameAnim4[MAX_QPATH]; + char imageNameAnim5[MAX_QPATH]; + char imageNameAnim6[MAX_QPATH]; + char imageNameAnim7[MAX_QPATH]; + char imageNameAnim8[MAX_QPATH]; + imgType_t itype = IMGTYPE_COLORALPHA; + imgFlags_t iflags = IMGFLAG_NONE; + int numVertexObjects = 0; + int numFragmentObjects = 0; + int loadlater = 0; + int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0; + qboolean depthMaskExplicit = qfalse; + + qboolean stageMipmaps = !shader.noMipMaps; + stage->active = qtrue; + Com_Memset(programName, 0, sizeof(programName)); + + + hackoperation = 2; // reset the hackop + + while ( 1 ) + { + + + + //stage->isBlend = 0; + token = COM_ParseExt( text, qtrue ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" ); + return qfalse; + } + + if ( token[0] == '}' ) + { + if (programName[0]) { + if (!Q_stricmp(programName, "skip")) { + stage->program = tr.skipProgram; + } else { + if (!numVertexObjects) { + ri.Printf(PRINT_WARNING, "WARNING: no 'vertexProgram' specified for 'program %s' in shader '%s'\n", programName, shader.name); + return qfalse; + } + + if (!numFragmentObjects) { + ri.Printf(PRINT_WARNING, "WARNING: no 'fragmentProgram' specified for 'program %s' in shader '%s'\n", programName, shader.name); + return qfalse; + } + + stage->isGLSL=0; + stage->program = RE_GLSL_RegisterProgram(programName, (const char *)programVertexObjects, numVertexObjects, (const char *)programFragmentObjects, numFragmentObjects); + if (!stage->program) { + ri.Printf(PRINT_WARNING, "WARNING: RE_GLSL_RegisterProgram failed for 'program %s' in shader '%s'\n", programName, shader.name); + //return qfalse; + } + else + stage->isGLSL=1; + } + } else if (numVertexObjects) { + ri.Printf(PRINT_WARNING, "WARNING: no 'program' specified for 'vertexProgram' in shader '%s'\n", shader.name); + return qfalse; + } else if (numFragmentObjects) { + ri.Printf(PRINT_WARNING, "WARNING: no 'program' specified for 'fragmentProgram' in shader '%s'\n", shader.name); + return qfalse; + } + + break; + } + // + // program + // + else if (!Q_stricmp(token, "program")) { + token = COM_ParseExt(text, qfalse); + + if (!vertexShaders) + continue; + + if (!token[0]) { + ri.Printf(PRINT_WARNING, "WARNING: missing parameter for 'program' keyword in shader '%s'\n", shader.name); + return qfalse; + } + + Q_strncpyz(programName, token, sizeof(programName)); + } + // + // vertexProgram .... + // + else if (!Q_stricmp(token, "vertexProgram")) { + token = COM_ParseExt(text, qfalse); + + if (!vertexShaders) { + while (token[0]) + token = COM_ParseExt(text, qfalse); + + continue; + } + + if (!token[0]) { + ri.Printf(PRINT_WARNING, "WARNING: missing parameter(s) for 'vertexProgram' keyword in shader '%s'\n", shader.name); + return qfalse; + } + + // parse up to MAX_PROGRAM_OBJECTS files + for(;;) { + if (numVertexObjects < MAX_PROGRAM_OBJECTS) { + Q_strncpyz(programVertexObjects[numVertexObjects], token, sizeof(programVertexObjects[numVertexObjects])); + numVertexObjects++; + } else { + ri.Printf(PRINT_WARNING, "WARNING: Too many parameters for 'vertexProgram' keyword in shader '%s'\n", shader.name); + return qfalse; + } + + token = COM_ParseExt(text, qfalse); + if (!token[0]) + break; + } + } + // + // fragmentProgram .... + // + else if (!Q_stricmp(token, "fragmentProgram")) { + token = COM_ParseExt(text, qfalse); + + if (!vertexShaders) { + while (token[0]) + token = COM_ParseExt(text, qfalse); + + continue; + } + + if (!token[0]) { + ri.Printf(PRINT_WARNING, "WARNING: missing parameter(s) for 'fragmentProgram' keyword in shader '%s'\n", shader.name); + return qfalse; + } + + // parse up to MAX_PROGRAM_OBJECTS files + for(;;) { + if (numFragmentObjects < MAX_PROGRAM_OBJECTS) { + Q_strncpyz(programFragmentObjects[numFragmentObjects], token, sizeof(programFragmentObjects[numFragmentObjects])); + numFragmentObjects++; + } else { + ri.Printf(PRINT_WARNING, "WARNING: Too many parameters for 'fragmentProgram' keyword in shader '%s'\n", shader.name); + return qfalse; + } + + token = COM_ParseExt(text, qfalse); + if (!token[0]) + break; + } + } + else if ( !Q_stricmp( token, "mipOffset" ) ){ + token = COM_ParseExt(text,qfalse); + stage->mipBias = atoi(token); + } + else if ( !Q_stricmp( token, "nomipmaps" ) ){ + stageMipmaps = qfalse; + } + // + // map + // + else if ( !Q_stricmp( token, "map" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + if ( !Q_stricmp( token, "$whiteimage" ) ) + { + stage->bundle[0].image[0] = tr.whiteImage; + continue; + } + else if ( !Q_stricmp( token, "$lightmap" ) ) + { + stage->bundle[0].isLightmap = qtrue; + if ( shader.lightmapIndex < 0 || !tr.lightmaps ) { + stage->bundle[0].image[0] = tr.whiteImage; + } else { + stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; + } + continue; + } + else + { + imgType_t type = IMGTYPE_COLORALPHA; + imgFlags_t flags = IMGFLAG_NONE; + + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + //stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); + stage->bundle[0].image[0] = tr.whiteImage; + COM_StripExtension( token, imageName, MAX_QPATH ); + itype = type; iflags = flags; + loadlater = 1; +// imageName = va("%s",token); + + // if ( !stage->bundle[0].image[0] ) + // { + // ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + // return qfalse; + // } + } + } + // + // clampmap + // + else if ( !Q_stricmp( token, "clampmap" ) ) + { + imgType_t type = IMGTYPE_COLORALPHA; + imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + stage->bundle[0].image[0] = tr.whiteImage; + COM_StripExtension( token, imageName, MAX_QPATH ); + itype = type; iflags = flags; + loadlater = 1; + } + // + // animMap .... + // + else if ( !Q_stricmp( token, "animMap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[0].imageAnimationSpeed = atof( token ); + + // parse up to MAX_IMAGE_ANIMATIONS animations + while ( 1 ) { + int num; + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + break; + } + num = stage->bundle[0].numImageAnimations; + if ( num < MAX_IMAGE_ANIMATIONS ) { + imgFlags_t flags = IMGFLAG_NONE; + + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + //stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); + stage->bundle[0].image[num] = tr.whiteImage; + if(num == 0) COM_StripExtension( token, imageNameAnim0, MAX_QPATH ); + if(num == 1) COM_StripExtension( token, imageNameAnim1, MAX_QPATH ); + if(num == 2) COM_StripExtension( token, imageNameAnim2, MAX_QPATH ); + if(num == 3) COM_StripExtension( token, imageNameAnim3, MAX_QPATH ); + if(num == 4) COM_StripExtension( token, imageNameAnim4, MAX_QPATH ); + if(num == 5) COM_StripExtension( token, imageNameAnim5, MAX_QPATH ); + if(num == 6) COM_StripExtension( token, imageNameAnim6, MAX_QPATH ); + if(num == 7) COM_StripExtension( token, imageNameAnim7, MAX_QPATH ); + if(num == 8) COM_StripExtension( token, imageNameAnim8, MAX_QPATH ); + iflags = flags; + loadlater = 1; + stage->bundle[0].numImageAnimations++; + } + } + } + else if ( !Q_stricmp( token, "clampAnimMap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampAnimMmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[0].imageAnimationSpeed = atof( token ); + + // parse up to MAX_IMAGE_ANIMATIONS animations + while ( 1 ) { + int num; + + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) { + break; + } + num = stage->bundle[0].numImageAnimations; + if ( num < MAX_IMAGE_ANIMATIONS ) { + imgFlags_t flags = IMGFLAG_SRGB; + + if (stageMipmaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); + + if ( !stage->bundle[0].image[num] ) + { + ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + stage->bundle[0].numImageAnimations++; + } + } + } + else if ( !Q_stricmp( token, "videoMap" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader)); + if (stage->bundle[0].videoMapHandle != -1) { + stage->bundle[0].isVideoMap = qtrue; + stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; + } + } + // + // alphafunc + // + else if ( !Q_stricmp( token, "alphaFunc" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + atestBits = NameToAFunc( token ); + } + // + // depthFunc + // + else if ( !Q_stricmp( token, "depthfunc" ) ) + { + token = COM_ParseExt( text, qfalse ); + + if ( !token[0] ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name ); + return qfalse; + } + + if ( !Q_stricmp( token, "lequal" ) ) + { + depthFuncBits = 0; + } + else if ( !Q_stricmp( token, "equal" ) ) + { + depthFuncBits = GLS_DEPTHFUNC_EQUAL; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // detail + // + else if ( !Q_stricmp( token, "detail" ) ) + { + stage->isDetail = qtrue; + } + // + // blendfunc + // or blendfunc + // + else if ( !Q_stricmp( token, "blendfunc" ) ) + { + hackoperation = 0; + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); + hackoperation = 0; + continue; + } + // check for "simple" blends first + if ( !Q_stricmp( token, "add" ) ) { + blendSrcBits = GLS_SRCBLEND_ONE; + blendDstBits = GLS_DSTBLEND_ONE; + hackoperation = 1; + } else if ( !Q_stricmp( token, "filter" ) ) { + blendSrcBits = GLS_SRCBLEND_DST_COLOR; + blendDstBits = GLS_DSTBLEND_ZERO; + // hackoperation = 4; + } else if ( !Q_stricmp( token, "blend" ) ) { + blendSrcBits = GLS_SRCBLEND_SRC_ALPHA; + blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; + hackoperation = 0; + + } else { + // complex double blends + blendSrcBits = NameToSrcBlendMode( token ); + hackoperation = 0; + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name ); + continue; + } + blendDstBits = NameToDstBlendMode( token ); + } + + stage->isBlend = 1; // 2x2 + + // clear depth mask for blended surfaces + if ( !depthMaskExplicit ) + { + depthMaskBits = 0; + } + + + } + // + // rgbGen + // + else if ( !Q_stricmp( token, "rgbGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "wave" ) ) + { + ParseWaveForm( text, &stage->rgbWave ); + stage->rgbGen = CGEN_WAVEFORM; + } + else if ( !Q_stricmp( token, "const" ) ) + { + vec3_t color; + + ParseVector( text, 3, color ); + stage->constantColor[0] = 255 * color[0]; + stage->constantColor[1] = 255 * color[1]; + stage->constantColor[2] = 255 * color[2]; + + stage->rgbGen = CGEN_CONST; + } + else if ( !Q_stricmp( token, "identity" ) ) + { + stage->rgbGen = CGEN_IDENTITY; + } + else if ( !Q_stricmp( token, "identityLighting" ) ) + { + stage->rgbGen = CGEN_IDENTITY_LIGHTING; + } + else if ( !Q_stricmp( token, "entity" ) ) + { + stage->rgbGen = CGEN_ENTITY; + } + else if ( !Q_stricmp( token, "oneMinusEntity" ) ) + { + stage->rgbGen = CGEN_ONE_MINUS_ENTITY; + } + else if ( !Q_stricmp( token, "vertex" ) ) + { + stage->rgbGen = CGEN_VERTEX; + if ( stage->alphaGen == 0 ) { + stage->alphaGen = AGEN_VERTEX; + } + } + else if ( !Q_stricmp( token, "exactVertex" ) ) + { + stage->rgbGen = CGEN_EXACT_VERTEX; + } + else if ( !Q_stricmp( token, "vertexLighting" ) ) // leilei - vertex WITH a lighting pass after + { + stage->rgbGen = CGEN_VERTEX_LIT; + if ( stage->alphaGen == 0 ) { + stage->alphaGen = AGEN_VERTEX; + } + } + else if ( !Q_stricmp( token, "vertexLighting2" ) ) // leilei - second vertex color + { + stage->rgbGen = CGEN_VERTEX_LIT; + if ( stage->alphaGen == 0 ) { + stage->alphaGen = AGEN_VERTEX; + } + } + else if ( !Q_stricmp( token, "lightingDiffuse" ) ) + { + stage->rgbGen = CGEN_LIGHTING_DIFFUSE; + } + else if ( !Q_stricmp( token, "lightingUniform" ) ) + { + stage->rgbGen = CGEN_LIGHTING_UNIFORM; + } + else if ( !Q_stricmp( token, "lightingDynamic" ) ) + { + stage->rgbGen = CGEN_LIGHTING_DYNAMIC; + } + else if ( !Q_stricmp( token, "flatAmbient" ) ) + { + stage->rgbGen = CGEN_LIGHTING_FLAT_AMBIENT; + } + else if ( !Q_stricmp( token, "flatDirect" ) ) + { + stage->rgbGen = CGEN_LIGHTING_FLAT_DIRECT; + } + else if ( !Q_stricmp( token, "oneMinusVertex" ) ) + { + stage->rgbGen = CGEN_ONE_MINUS_VERTEX; + } + else if ( !Q_stricmp( token, "lightingSpecularDiffuse" ) ) // leilei - deprecated + { + stage->rgbGen = CGEN_LIGHTING_DIFFUSE; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // alphaGen + // + else if ( !Q_stricmp( token, "alphaGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "wave" ) ) + { + ParseWaveForm( text, &stage->alphaWave ); + stage->alphaGen = AGEN_WAVEFORM; + } + else if ( !Q_stricmp( token, "const" ) ) + { + token = COM_ParseExt( text, qfalse ); + stage->constantColor[3] = 255 * atof( token ); + stage->alphaGen = AGEN_CONST; + } + else if ( !Q_stricmp( token, "identity" ) ) + { + stage->alphaGen = AGEN_IDENTITY; + } + else if ( !Q_stricmp( token, "entity" ) ) + { + stage->alphaGen = AGEN_ENTITY; + } + else if ( !Q_stricmp( token, "oneMinusEntity" ) ) + { + stage->alphaGen = AGEN_ONE_MINUS_ENTITY; + } + else if ( !Q_stricmp( token, "vertex" ) ) + { + stage->alphaGen = AGEN_VERTEX; + } + else if ( !Q_stricmp( token, "lightingSpecular" ) ) + { + stage->alphaGen = AGEN_LIGHTING_SPECULAR; + } + else if ( !Q_stricmp( token, "oneMinusVertex" ) ) + { + stage->alphaGen = AGEN_ONE_MINUS_VERTEX; + } + else if ( !Q_stricmp( token, "portal" ) ) + { + stage->alphaGen = AGEN_PORTAL; + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + shader.portalRange = 256; + ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name ); + } + else + { + shader.portalRange = atof( token ); + } + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name ); + continue; + } + } + // + // tcGen + // + else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + { + ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "environment" ) ) + { + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED; + } + else if ( !Q_stricmp( token, "cel" ) ) + { + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_MAPPED; + } + else if ( !Q_stricmp( token, "celshading" ) ) // leilei - my technique is different + { + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_CELSHADE_LEILEI; + } + else if ( !Q_stricmp( token, "eyeleft" ) ) // leilei - eye tracking + { + stage->bundle[0].tcGen = TCGEN_EYE_LEFT; + } + else if ( !Q_stricmp( token, "eyeright" ) ) // leilei - eye tracking + { + stage->bundle[0].tcGen = TCGEN_EYE_RIGHT; + } + else if ( !Q_stricmp( token, "environmentWater" ) ) + { + stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED_WATER; // leilei - water's envmaps + } + else if ( !Q_stricmp( token, "lightmap" ) ) + { + stage->bundle[0].tcGen = TCGEN_LIGHTMAP; + } + else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) + { + stage->bundle[0].tcGen = TCGEN_TEXTURE; + } + else if ( !Q_stricmp( token, "vector" ) ) + { + ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] ); + ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] ); + + stage->bundle[0].tcGen = TCGEN_VECTOR; + } + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name ); + } + } + // + // tcMod <...> + // + else if ( !Q_stricmp( token, "tcMod" ) ) + { + char buffer[1024] = ""; + + while ( 1 ) + { + token = COM_ParseExt( text, qfalse ); + if ( token[0] == 0 ) + break; + strcat( buffer, token ); + strcat( buffer, " " ); + } + + ParseTexMod( buffer, stage ); + + continue; + } + // + // depthmask + // + else if ( !Q_stricmp( token, "depthwrite" ) ) + { + depthMaskBits = GLS_DEPTHMASK_TRUE; + depthMaskExplicit = qtrue; + + continue; + } + + else + { + ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name ); + return qfalse; + } + + + + + } + + // + // if cgen isn't explicitly specified, use either identity or identitylighting + // + if ( stage->rgbGen == CGEN_BAD ) { + if ( blendSrcBits == 0 || + blendSrcBits == GLS_SRCBLEND_ONE || + blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) { + stage->rgbGen = CGEN_IDENTITY_LIGHTING; + } else { + stage->rgbGen = CGEN_IDENTITY; + } + } + + + // + // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending + // + if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && + ( blendDstBits == GLS_DSTBLEND_ZERO ) ) + { + blendDstBits = blendSrcBits = 0; + depthMaskBits = GLS_DEPTHMASK_TRUE; + } + + // decide which agens we can skip + if ( stage->alphaGen == AGEN_IDENTITY ) { + if ( stage->rgbGen == CGEN_IDENTITY + || stage->rgbGen == CGEN_LIGHTING_DIFFUSE + || stage->rgbGen == CGEN_LIGHTING_UNIFORM + || stage->rgbGen == CGEN_LIGHTING_DYNAMIC) { + stage->alphaGen = AGEN_SKIP; + } + } + + // + // compute state bits + // + stage->stateBits = depthMaskBits | + blendSrcBits | blendDstBits | + atestBits | + depthFuncBits; + // + // now load our image! + // + + //hackoperation = 2; + if (loadlater){ + if (!blendDstBits) hackoperation = 2; + + if (ismaptexture){ + + if (surfaceflagsy & CONTENTS_TRANSLUCENT) + hackoperation = 0; + else + hackoperation = 2; + } + + if (blendSrcBits == GLS_SRCBLEND_ONE) hackoperation = 1; + if (blendDstBits == GLS_DSTBLEND_ONE) hackoperation = 1; + + + if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA) hackoperation = 0; + if (blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA) hackoperation = 0; + + if (blendSrcBits == GLS_SRCBLEND_DST_COLOR && + blendDstBits == GLS_DSTBLEND_SRC_COLOR) + hackoperation = 4; + + if (blendSrcBits == GLS_SRCBLEND_DST_COLOR && + blendDstBits == GLS_SRCBLEND_ONE) + hackoperation = 1; + + if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && + blendDstBits == GLS_SRCBLEND_ONE) // additive, but blended away by alpha + hackoperation = 1; + + + if (!ismaptexture){ + if (blendSrcBits == GLS_SRCBLEND_ZERO) hackoperation = 3; + //if (blendDstBits == GLS_DSTBLEND_ZERO) hackoperation = 3; + } + if (stage->bundle[0].numImageAnimations>0){ + int n, o; + n= stage->bundle[0].numImageAnimations; + for (o=0; obundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); + + if(o == 0) COM_StripExtension( imageNameAnim0, imageName, MAX_QPATH ); + if(o == 1) COM_StripExtension( imageNameAnim1, imageName, MAX_QPATH ); + if(o == 2) COM_StripExtension( imageNameAnim2, imageName, MAX_QPATH ); + if(o == 3) COM_StripExtension( imageNameAnim3, imageName, MAX_QPATH ); + if(o == 4) COM_StripExtension( imageNameAnim4, imageName, MAX_QPATH ); + if(o == 5) COM_StripExtension( imageNameAnim5, imageName, MAX_QPATH ); + if(o == 6) COM_StripExtension( imageNameAnim6, imageName, MAX_QPATH ); + if(o == 7) COM_StripExtension( imageNameAnim7, imageName, MAX_QPATH ); + if(o == 8) COM_StripExtension( imageNameAnim8, imageName, MAX_QPATH ); + stage->bundle[0].image[o] = R_FindImageFile( imageName, itype, iflags ); + + } + } + else + stage->bundle[0].image[0] = R_FindImageFile( imageName, itype, iflags ); + stage->isBlend = hackoperation; + + if (blendSrcBits == GLS_SRCBLEND_SRC_ALPHA && + blendDstBits == GLS_SRCBLEND_ONE) // additive, but blended away by alpha + stage->isBlend = 0; + + } + + return qtrue; +} + + /* =============== ParseDeform @@ -3194,6 +4054,7 @@ static qboolean ParseShader( char **text ) { break; } + // stage definition else if ( token[0] == '{' ) { @@ -3379,6 +4240,8 @@ static qboolean ParseShader( char **text ) } shader.explicitlyDefined = qtrue; + surfaceflagsy = shader.surfaceFlags; + return qtrue; } @@ -3935,6 +4798,8 @@ static shader_t *FinishShader( void ) { shader.sort = SS_DECAL; } + + // // set appropriate stage information // @@ -3945,6 +4810,37 @@ static shader_t *FinishShader( void ) { break; } + + // Try to use leifx dither here instead of postprocess for more authentic overdraw artifacts + if (r_leifx->integer > 1) + { + + if (pStage->isBlend == 1){ + pStage->program = RE_GLSL_RegisterProgram("leifxify2", "glsl/leifxify2_vp.glsl", 1, "glsl/leifxify2_fp.glsl", 1); // 2x2 dither blend for vertex colors, 4x4 for texture + ri.Printf( PRINT_DEVELOPER, "picking blended\n"); + } + else + pStage->program = RE_GLSL_RegisterProgram("leifxify", "glsl/leifxify2_vp.glsl", 1, "glsl/leifxify_fp.glsl", 1); // 4x4 dither blend for both color and texture + pStage->isGLSL=1; + } + + // Mockvr faking of the filtering and alpha precision of PCX2 cards + if ((r_mockvr->integer > 1)) + { + pStage->program = RE_GLSL_RegisterProgram("leivrify", "glsl/leivrify_vp.glsl", 1, "glsl/leivrify_fp.glsl", 1); + + pStage->isGLSL=1; + + // pass texture width/height (filtering etc) + if(!pStage->imgWidth) pStage->imgWidth = 128; + if(!pStage->imgHeight) pStage->imgHeight = 128; + // R_GLSL_SetUniform_u_ScreenSizeX(pStage->program, pStage->imgWidth); + // R_GLSL_SetUniform_u_ScreenSizeY(pStage->program, pStage->imgHeight); + // R_GLSL_SetUniform_u_ScreenToNextPixelX(pStage->program, (float)1.0/(float)pStage->imgWidth); + // R_GLSL_SetUniform_u_ScreenToNextPixelY(pStage->program, (float)1.0/(float)pStage->imgHeight); + + } + // check for a missing texture if ( !pStage->bundle[0].image[0] ) { ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name ); @@ -4002,25 +4898,7 @@ static shader_t *FinishShader( void ) { // vertexLightmap = qtrue; //} - // Try to use leifx dither here instead of postprocess for more authentic overdraw artifacts - if (r_leifx->integer > 1) - { - - if (pStage->isBlend == 1){ - pStage->program = RE_GLSL_RegisterProgram("leifxify2", "glsl/leifxify2_vp.glsl", 1, "glsl/leifxify2_fp.glsl", 1); // 2x2 dither blend for vertex colors, 4x4 for texture - ri.Printf( PRINT_DEVELOPER, "picking blended\n"); - } - else - pStage->program = RE_GLSL_RegisterProgram("leifxify", "glsl/leifxify_vp.glsl", 1, "glsl/leifxify_fp.glsl", 1); // 4x4 dither blend for both color and texture - pStage->isGLSL=1; - } - // Mockvr faking of the filtering and alpha precision of PCX2 cards - if ((r_mockvr->integer > 1)) - { - pStage->program = RE_GLSL_RegisterProgram("leivrify", "glsl/leivrify_vp.glsl", 1, "glsl/leivrify_fp.glsl", 1); - pStage->isGLSL=1; - } // leilei - force new phong on lightdiffuse and lightdiffusespecular models @@ -4383,6 +5261,7 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw int thisstage = 0; material = 0; wi = hi = 32; // reset to none.... + shouldIDetail = 0; //yeah for (f=0;finteger){ // leilei - for powervr + hackoperation = 0; + + if ( shader.lightmapIndex == LIGHTMAP_NONE ) { + // dynamic colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) { + // explicit colors at vertexes + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_EXACT_VERTEX; + stages[0].alphaGen = AGEN_SKIP; + stages[0].stateBits = GLS_DEFAULT; + } else if ( shader.lightmapIndex == LIGHTMAP_2D ) { + // GUI elements + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_VERTEX; + stages[0].alphaGen = AGEN_VERTEX; + stages[0].stateBits = GLS_DEPTHTEST_DISABLE; + stages[0].isBlend = 0; + hackoperation = 0; + } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) { + // fullbright level + stages[1].bundle[0].image[0] = tr.whiteImage; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY_LIGHTING; + stages[1].stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_DST_ALPHA; + + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY; + stages[0].stateBits = GLS_DEFAULT; + } else { + + // two pass lightmap + + hackoperation = 0; + stages[0].isBlend = 0; + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].rgbGen = CGEN_IDENTITY; + stages[0].stateBits = GLS_DEFAULT; + + hackoperation = 4; + stages[1].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; + stages[1].bundle[0].isLightmap = qtrue; + stages[1].active = qtrue; + stages[1].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation + stages[1].isBlend = 1; + // for identitylight + stages[1].stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_DST_ALPHA; + + + } + + + + } + else // normal + { + if ( shader.lightmapIndex == LIGHTMAP_NONE ) { // dynamic colors at vertexes stages[0].bundle[0].image[0] = image; @@ -4527,7 +5472,6 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw if (r_detailTextures->integer > 2){ // three pass lightmap with a detail after the texture. slow but is how U did it - stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex]; stages[0].bundle[0].isLightmap = qtrue; stages[0].active = qtrue; @@ -4539,12 +5483,14 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw stages[1].active = qtrue; stages[1].rgbGen = CGEN_IDENTITY; stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO; - // detail { int f; + if (r_parseStageSimple->integer) hackoperation = 4; for (f=0;f MAX_SHADER_STAGES) break;// don't exceed limit! + stages[2+f].bundle[0].image[0] = R_FindImageFile( "gfx/fx/detail/d_generic.tga", IMGFLAG_MIPMAP , IMGFLAG_MIPMAP); // TODO: use metal detail for metal surfaces // determine detail size first, our detail textures are typically 128x128 @@ -4585,6 +5531,22 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw } } + + // leilei - handle image height + + int y; + for(y=0;y