- Detail texture forcing; adds detail texture layers to shaders that don't specify for one. Slightly broken and still needs work.

- Detail texture scale and layesr also adjust the amplification and density of this effect
- Detail mip fade fixed
- r_suggestiveThemes 0 properly loads models and shaders and textures from models/player only. speedup a bit
- r_suggestiveThemes 2 loads _lewd models, shaders and textures.  To keep 'safe' and 'sexy' safe from autodownloaded lewd that respect the prefix.
- removing r_anime _cel loading, which conflicts with the above system and i'm going all out shader on that anyway
- even more waterimage removal
- r_leifx no longer allows trilinear filter. closer to actual real world voodoo behavior
This commit is contained in:
leilei-
2015-03-01 04:57:37 -05:00
parent 0339e71c2f
commit fd5f8bc4a6
8 changed files with 357 additions and 182 deletions

View File

@@ -1209,10 +1209,13 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
qglEnd ();
}
extern int force32upload;
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
GL_Bind( tr.scratchImage[client] );
// if the scratchImage isn't in the format we want, specify it as a new texture
if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;

View File

@@ -2072,84 +2072,13 @@ void R_PaletteScreen( void )
static struct {
struct {
image_t *texture;
int width, height;
float readW, readH;
} effect;
struct {
image_t *texture;
int width, height;
float readW, readH;
} effect2;
struct {
image_t *texture;
int width, height;
float readW, readH;
} screen;
struct {
int width, height;
} work;
qboolean started;
// NO!
} water;
// leilei - experimental water effect
static void R_Water_InitTextures( void )
{
byte *data;
// find closer power of 2 to screen size
for (water.screen.width = 1;water.screen.width< glConfig.vidWidth;water.screen.width *= 2);
for (water.screen.height = 1;water.screen.height < glConfig.vidHeight;water.screen.height *= 2);
water.screen.readW = glConfig.vidWidth / (float)water.screen.width;
water.screen.readH = glConfig.vidHeight / (float)water.screen.height;
// find closer power of 2 to effect size
water.work.width = 256;
water.work.height = water.work.width * ( glConfig.vidWidth / glConfig.vidHeight );
for (water.effect.width = 1;water.effect.width < water.work.width;water.effect.width *= 2);
for (water.effect.height = 1;water.effect.height < water.work.height;water.effect.height *= 2);
water.effect.readW = water.work.width / (float)water.effect.width;
water.effect.readH = water.work.height / (float)water.effect.height;
water.effect2.readW=water.effect.readW;
water.effect2.readH=water.effect.readH;
water.effect2.width=water.effect.width;
water.effect2.height=water.effect.height;
// disable waters if we can't handle a texture of that size
if( water.screen.width > glConfig.maxTextureSize ||
water.screen.height > glConfig.maxTextureSize ||
water.effect.width > glConfig.maxTextureSize ||
water.effect.height > glConfig.maxTextureSize ||
water.work.width > glConfig.vidWidth ||
water.work.height > glConfig.vidHeight
) {
ri.Cvar_Set( "r_leiwater", "0" );
Com_Printf( S_COLOR_YELLOW"WARNING: 'R_InitWaterTextures' too high resolution for water, effect disabled\n" );
return;
}
// leilei - let's not do that water disabling anymore
force32upload = 1;
data = ri.Hunk_AllocateTempMemory( water.screen.width * water.screen.height * 4 );
Com_Memset( data, 0, water.screen.width * water.screen.height * 4 );
water.screen.texture = R_CreateImage( "***water screen texture***", data, water.screen.width, water.screen.height, qfalse, qfalse, GL_CLAMP_TO_EDGE );
ri.Hunk_FreeTempMemory( data );
data = ri.Hunk_AllocateTempMemory( water.effect.width * water.effect.height * 4 );
Com_Memset( data, 0, water.effect.width * water.effect.height * 4 );
tr.waterImage = R_CreateImage( "*water", data, water.effect.width, water.effect.height, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 );
//tr.waterImage = R_CreateImage( "*waterimage", data, water.effect.width, water.effect.height, qfalse, qfalse, GL_CLAMP_TO_EDGE );;
ri.Hunk_FreeTempMemory( data );
water.started = qtrue;
force32upload = 0;
// NO!
}
@@ -2157,72 +2086,34 @@ static void R_Water_InitTextures( void )
void R_InitWaterTextures( void )
{
if( !r_leiwater->integer )
return;
memset( &water, 0, sizeof( water ));
R_Water_InitTextures ();
// NO!
}
static void R_Water_BackupScreen( void ) {
GL_Bind( water.screen.texture );
qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight );
static void R_Water_BackupScreen( void )
{
// NO!
}
static void R_WaterWorks( void )
{
int i, j, k;
float intensity, scale, *diamond;
qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
GL_Bind( water.screen.texture );
//GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
R_Bloom_Quad( water.work.width, water.work.height, 0, 0, water.screen.readW, water.screen.readH );
//Copy downscaled framebuffer into a texture
GL_Bind( tr.waterImage );
qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, water.work.width, water.work.height );
// NO!
}
static void R_Water_RestoreScreen( void ) {
GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
GL_Bind( water.screen.texture );
qglColor4f( 1,1,1, 1 );
R_Bloom_Quad( water.screen.width, water.screen.height, 0, 0,
1.f,
1.f );
// NO!
}
void R_WaterInit( void ) {
memset( &water, 0, sizeof( water ));
// NO!
}
void R_WaterScreen( void )
{
if( !r_leiwater->integer )
return;
if ( backEnd.donewater )
return;
if ( !backEnd.doneSurfaces )
return;
backEnd.donewater= qtrue;
if( !water.started ) {
R_Water_InitTextures();
if( !water.started )
return;
}
if ( !backEnd.projection2D )
RB_SetGL2D();
//// All we want to do is copy the thing
R_Water_BackupScreen();
R_WaterWorks ();
R_Water_RestoreScreen();
// NO!
}

View File

@@ -269,6 +269,7 @@ void GLimp_InitExtraExtensions()
{
ri.Cvar_Set( "r_postprocess", "none");
ri.Cvar_Set( "r_ext_vertex_shader", "0");
ri.Cvar_Set( "r_leifx", "0"); // leilei FIXME - q3 cinematics crash leifx modes
}
@@ -325,12 +326,6 @@ void GLimp_InitExtraExtensions()
}
else if ( strstr( buf, "generic" ) || strstr( buf, "brian" ) || strstr( buf, "paul" ) || strstr( buf, "GDI" ) ) // software mode opengl needs speedup tricks
{
//glConfig.hardwareType = GLHW_SOFTWARE;
// ri.Cvar_Set( "r_texturemode", "GL_NEAREST" );
// ri.Cvar_Set( "r_picmip", "2" );
// ri.Cvar_Set( "r_detailtextures", "0" );
// ri.Cvar_Set( "r_primitives", "2" );
// ri.Cvar_Get( "r_picmip", "0", CVAR_ARCHIVE | CVAR_LATCH );
softwaremode = 1;
}
else if ( strstr( buf, "riva 128" ) )

View File

@@ -356,7 +356,7 @@ void GL_TextureMode( const char *string ) {
// hack to prevent trilinear from being set on voodoo,
// because their driver freaks...
if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D || r_leifx->integer ) {
ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
i = 3;
}
@@ -1055,10 +1055,16 @@ static void R_BlendToGray( byte *data, int pixelCount, int fadeto) {
float alphed, alpher;
if (fadeto < 1)
return; // we don't need to.
return; // we don't need to for the highest mip.
alphed = 1 / fadeto;
alpher = 1 - alphed;
if (fadeto == 1){ alphed = 0.75; alpher = 0.25; }
else if (fadeto == 2){ alphed = 0.50; alpher = 0.50; }
else if (fadeto == 3){ alphed = 0.25; alpher = 0.75; }
else { alphed = 0.0; alpher = 1.00; }
//alphed = 1 / fadeto;
//alpher = 1 - alphed;
fadeto += 1;
@@ -2182,6 +2188,7 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
{
image_t *image;
int width, height;
int dontgotsafe;
byte *pic;
long hash;
float oldtime;
@@ -2228,11 +2235,53 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
//
// load the pic from disk
//
//oldtime = backEnd.refdef.floatTime;
oldtime = ri.Milliseconds() * 100;
dontgotsafe = 0;
if (r_suggestiveThemes->integer == 1) dontgotsafe = 1;
// leilei - load safe or lewd textures if desired.
if (!Q_strncmp( name, "models/players", 14) ){
if (r_suggestiveThemes->integer < 1){
char narm[ MAX_QPATH ];
COM_StripExtension( name, narm, MAX_QPATH );
R_LoadImage( va("%s_safe", narm), &pic, &width, &height );
if ( pic == NULL )
dontgotsafe = 1;
else
dontgotsafe = 0;
}
else if (r_suggestiveThemes->integer > 1){
char narm[ MAX_QPATH ];
COM_StripExtension( name, narm, MAX_QPATH );
R_LoadImage( va("%s_lewd", narm), &pic, &width, &height );
if ( pic == NULL )
dontgotsafe = 1;
else
dontgotsafe = 0;
}
}
else
{
dontgotsafe = 1;
}
//oldtime = backEnd.refdef.floatTime;
if (dontgotsafe){
R_LoadImage( name, &pic, &width, &height );
if ( pic == NULL ) {
return NULL;
if ( pic == NULL ) {
return NULL;
}
}
loadtime = (ri.Milliseconds() * 100) - oldtime;
// loadtime = backEnd.refdef.floatTime - oldtime;

View File

@@ -55,6 +55,8 @@ cvar_t *r_verbose;
cvar_t *r_ignore;
cvar_t *r_detailTextures;
cvar_t *r_detailTextureScale;
cvar_t *r_detailTextureLayers;
cvar_t *r_shadeSpecular;
cvar_t *r_znear;
@@ -208,7 +210,6 @@ cvar_t *r_anime; // Leilei - anime filter
cvar_t *r_palletize; // Leilei - palletization
cvar_t *r_leidebug; // Leilei - debug
cvar_t *r_leidebugeye; // Leilei - eye debug
cvar_t *r_leiwater; // Leilei - water effect test
cvar_t *r_suggestiveThemes; // leilei - mature content control
@@ -1278,10 +1279,10 @@ void R_Register( void )
r_mockvr = ri.Cvar_Get( "r_mockvr", "0" , CVAR_ARCHIVE | 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
r_detailTextureLayers = ri.Cvar_Get( "r_detailtextureLayers", "0", CVAR_ARCHIVE | CVAR_LATCH ); // leilei - add more detail layers
r_ntsc = ri.Cvar_Get( "r_ntsc", "0" , CVAR_ARCHIVE | CVAR_LATCH);
r_leiwater = ri.Cvar_Get( "r_leiwater", "0" , CVAR_ARCHIVE | CVAR_LATCH);
r_ntsc = ri.Cvar_Get( "r_ntsc", "0" , CVAR_ARCHIVE | CVAR_LATCH); // leilei - ntsc filter
//r_tvMode = ri.Cvar_Get( "r_tvMode", "0" , CVAR_ARCHIVE | CVAR_LATCH);
r_retroAA = ri.Cvar_Get( "r_retroAA", "0" , CVAR_ARCHIVE | CVAR_LATCH);

View File

@@ -70,12 +70,6 @@ typedef struct {
vec3_t dynamicLight;
float lightDistance;
// leilei - better quality lighting hack
vec3_t directedLightA;
vec3_t lightDirA;
// leilei - eyes
vec3_t eyepos[2]; // looking from
} trRefEntity_t;
@@ -391,6 +385,11 @@ typedef struct shader_s {
qboolean needsST2;
qboolean needsColor;
// leilei - automatic detail texturing
int hasDetail; // shader has a detail stage
int hasDepthWrite; // shader has a depthwrite stage (detailing around holes)
int hasMaterial; // shader represents this material
int numDeforms;
deformStage_t deforms[MAX_SHADER_DEFORMS];
@@ -408,6 +407,18 @@ typedef struct shader_s {
} shader_t;
// leilei - shader materials for detail texturing
#define SHADMAT_GENERIC 0 // none
#define SHADMAT_METAL 1 // from metalsteps
#define SHADMAT_WOOD 2 // ql
#define SHADMAT_FLESH 3 // unused
#define SHADMAT_SAND 4 // from dust?
#define SHADMAT_SNOW 5 // unused
#define SHADMAT_EARTH 6 // unused
#define SHADMAT_CONCRETE 7 // unused? redundant?
#define SHADMAT_ICE 8 // from slick
// trRefdef_t holds everything that comes in refdef_t,
// as well as the locally generated scene information
typedef struct {
@@ -1337,7 +1348,7 @@ extern cvar_t *r_alternateBrightness; // leilei - alternate brightness
extern cvar_t *r_leifx; // Leilei - leifx nostalgia filter
extern cvar_t *r_modelshader; // Leilei - new model shading
extern cvar_t *r_leiwater; // Leilei - water test
extern cvar_t *r_ntsc; // Leilei - ntsc
@@ -1361,6 +1372,9 @@ extern cvar_t *r_iconmip; // leilei - icon mip - picmip for 2d icons
extern cvar_t *r_texdump; // leilei - texture dumping
extern cvar_t *r_detailTextureScale; // leilei - scale tweak the detail textures, 0 doesn't tweak at all.
extern cvar_t *r_detailTextureLayers; // leilei - add in more smaller detail texture layers, expensive!
//====================================================================
void R_SwapBuffers( int );

View File

@@ -371,8 +371,8 @@ qhandle_t RE_RegisterModelReal( const char *name ) {
qhandle_t RE_RegisterModel( const char *name ) {
if (!r_suggestiveThemes->integer){
if (!Q_strncmp( name, "models/players", 14)){
if (r_suggestiveThemes->integer == 0){ // safe models that will ship, much needed option of modesty
qhandle_t eh;
char narm[ MAX_QPATH ];
COM_StripExtension( name, narm, MAX_QPATH );
@@ -383,10 +383,28 @@ qhandle_t RE_RegisterModel( const char *name ) {
// TODO: Free the previous _safe qhandle
return eh;
}
else if (r_suggestiveThemes->integer > 1){ // lewd models, won't ship, but adding support anyway so normal
// models aren't replaced with lewd
qhandle_t eh;
char narm[ MAX_QPATH ];
COM_StripExtension( name, narm, MAX_QPATH );
eh = RE_RegisterModelReal( va("%s_lewd", narm) );
if (!eh)
eh = RE_RegisterModelReal( name );
// TODO: Free the previous _lewd qhandle
return eh;
}
else
{
return RE_RegisterModelReal( name );
}
}
else
{
return RE_RegisterModelReal( name ); // OK!!!
}
}

View File

@@ -1046,7 +1046,6 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
char programFragmentObjects[MAX_PROGRAM_OBJECTS][MAX_QPATH];
int numVertexObjects = 0;
int numFragmentObjects = 0;
int leifxmode = 0; // for picking different dither tanles for blended stuff
int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
qboolean depthMaskExplicit = qfalse;
@@ -1059,7 +1058,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
//stage->isBlend = 0;
token = COM_ParseExt( text, qtrue );
if ( !token[0] )
{
@@ -1255,11 +1254,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->bundle[2].image[0] = tr.whiteImage;
continue;
}
if ( !Q_stricmp( token, "$waterimage" ) )
{
stage->bundle[2].image[0] = tr.waterImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[2].isLightmap = qtrue;
@@ -1293,7 +1288,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
//
// map3 <name>
//
else if ( !Q_stricmp( token, "map3" ) )
else if ( !Q_stricmp( token, "map3" ) || (!Q_stricmp( token, "normalmap" ) && r_modelshader->integer))
{
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
@@ -1307,11 +1302,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->bundle[3].image[0] = tr.whiteImage;
continue;
}
if ( !Q_stricmp( token, "$waterimage" ) )
{
stage->bundle[3].image[0] = tr.waterImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[3].isLightmap = qtrue;
@@ -1345,7 +1336,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
//
// map4 <name>
//
else if ( !Q_stricmp( token, "map4" ) )
else if ( !Q_stricmp( token, "map4" ) || (!Q_stricmp( token, "specmap" ) && r_modelshader->integer))
{
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
@@ -1392,7 +1383,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
//
// map5 <name>
//
else if ( !Q_stricmp( token, "map5" ) )
else if ( !Q_stricmp( token, "map5" ) || (!Q_stricmp( token, "shadeballmap" ) && r_modelshader->integer))
{
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
@@ -1406,11 +1397,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->bundle[5].image[0] = tr.whiteImage;
continue;
}
if ( !Q_stricmp( token, "$waterimage" ) )
{
stage->bundle[5].image[0] = tr.waterImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[5].isLightmap = qtrue;
@@ -1458,11 +1445,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->bundle[6].image[0] = tr.whiteImage;
continue;
}
if ( !Q_stricmp( token, "$waterimage" ) )
{
stage->bundle[6].image[0] = tr.waterImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[6].isLightmap = qtrue;
@@ -1510,11 +1493,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
stage->bundle[7].image[0] = tr.whiteImage;
continue;
}
if ( !Q_stricmp( token, "$waterimage" ) )
{
stage->bundle[7].image[0] = tr.waterImage;
continue;
}
else if ( !Q_stricmp( token, "$lightmap" ) )
{
stage->bundle[7].isLightmap = qtrue;
@@ -2493,15 +2472,13 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
if ( !Q_stricmp( token, "add" ) ) {
blendSrcBits = GLS_SRCBLEND_ONE;
blendDstBits = GLS_DSTBLEND_ONE;
leifxmode = 1; // 2x2
} else if ( !Q_stricmp( token, "filter" ) ) {
blendSrcBits = GLS_SRCBLEND_DST_COLOR;
blendDstBits = GLS_DSTBLEND_ZERO;
leifxmode = 1; // 2x2
} else if ( !Q_stricmp( token, "blend" ) ) {
blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
leifxmode = 1; // 4x4
} else {
// complex double blends
blendSrcBits = NameToSrcBlendMode( token );
@@ -2513,8 +2490,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue;
}
blendDstBits = NameToDstBlendMode( token );
leifxmode = 1; // 2x2
}
stage->isBlend = 1; // 2x2
// clear depth mask for blended surfaces
if ( !depthMaskExplicit )
@@ -3452,6 +3430,7 @@ static void ComputeStageIteratorFunc( void )
return; // lightmaps with a different dithering table
//
// see if this can go into the vertex lit fast path
//
@@ -3576,7 +3555,7 @@ static qboolean CollapseMultitexture( void ) {
}
// on voodoo2, don't combine different tmus
if ( glConfig.driverType == GLDRV_VOODOO ) {
if ( glConfig.driverType == GLDRV_VOODOO || r_leifx->integer ) {
if ( stages[0].bundle[0].image[0]->TMU ==
stages[1].bundle[0].image[0]->TMU ) {
return qfalse;
@@ -3938,10 +3917,13 @@ static shader_t *FinishShader( void ) {
int stage;
qboolean hasLightmapStage;
qboolean vertexLightmap;
hasLightmapStage = qfalse;
vertexLightmap = qfalse;
//
// set sky stuff appropriate
//
@@ -3974,6 +3956,7 @@ static shader_t *FinishShader( void ) {
continue;
}
//
// ditch this stage if it's detail and detail textures are disabled
//
@@ -4015,6 +3998,7 @@ static shader_t *FinishShader( void ) {
}
// not a true lightmap but we want to leave existing
// behaviour in place and not print out a warning
//if (pStage->rgbGen == CGEN_VERTEX) {
@@ -4024,7 +4008,13 @@ static shader_t *FinishShader( void ) {
// Try to use leifx dither here instead of postprocess for more authentic overdraw artifacts
if (r_leifx->integer > 1)
{
pStage->program = RE_GLSL_RegisterProgram("leifxify", "glsl/leifxify_vp.glsl", 1, "glsl/leifxify_fp.glsl", 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;
}
@@ -4036,6 +4026,13 @@ static shader_t *FinishShader( void ) {
}
// leilei - force new phong on lightdiffuse and lightdiffusespecular models
if ((r_modelshader->integer) && (pStage->isGLSL==0) && (r_ext_vertex_shader->integer) && ((pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) || (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE_SPECULAR)))
{
pStage->program = RE_GLSL_RegisterProgram("leishade", "glsl/leishade_vp.glsl", 1, "glsl/leishade_fp.glsl", 1);
pStage->isGLSL=1;
pStage->isLeiShade=1;
}
//
// determine sort order and fog color adjustment
@@ -4260,8 +4257,21 @@ Other lightmapIndex values will have a lightmap stage created
and src*dest blending applied with the texture, as apropriate for
most world construction surfaces.
Leilei TODO - and if it has a lightmapindex and no detail texture please
try to generate a generic detail stage for the sake of consistency with
the other textures with details so there's one big grainy world
(only if r_detailTextures 3)
TODO: if r_detailTextures 2, try to move the detail texture before the lightmap
stage and use filterblend , so we can use the multitexturing
pass performance advantage
===============
*/
static int sugthem;
shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRawImage ) {
char strippedName[MAX_QPATH];
int i, hash;
@@ -4269,6 +4279,31 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
image_t *image;
shader_t *sh;
//
// LEILEI's DETAIL TEXTURE STUFFS
//
int material; // leilei - for picking detail texture
int shouldIDetail = 0; // leilei - checking if I should detail.
int wi, hi; // leilei - for determining detail texture size by uploaded texture
int detailScale; // leilei - detail scale hack
int detailLayer; // leilei - detail layer hack
// leilei - for adjusting detail textures
if ( r_detailTextureScale->integer > 0)
detailScale = r_detailTextureScale->integer;
else
detailScale = 8;
if ( r_detailTextureLayers->integer > 0)
detailLayer = r_detailTextureLayers->integer;
else
detailLayer = 1; // one usual layer
if (detailLayer > 6) detailLayer = 6; // limit 6 for now
//
//
//
if ( name[0] == 0 ) {
return tr.defaultShader;
}
@@ -4317,6 +4352,7 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
shader.needsST2 = qtrue;
shader.needsColor = qtrue;
//
// attempt to define shader from an explicit parameter file
//
@@ -4332,6 +4368,94 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
// had errors, so use default shader
shader.defaultShader = qtrue;
}
if (shader.surfaceFlags || SURF_METALSTEPS)
material = 1;
// leilei - SUPER detail hack to existing shaders,very aggressive and won't look good on 100% of shaders
if((shader.lightmapIndex != LIGHTMAP_WHITEIMAGE && shader.lightmapIndex != LIGHTMAP_BY_VERTEX && shader.lightmapIndex != LIGHTMAP_2D && shader.lightmapIndex != LIGHTMAP_NONE) ){
if (r_detailTextures->integer)
{
image_t *imageDetail; // for snagging it into more layers if we find a defined one
int e = 0;
int f = 0;
int gotdetailalready = 0;
int hasaDetailImage = 0;
int thisstage = 0;
material = 0;
wi = hi = 32; // reset to none....
shouldIDetail = 0; //yeah
for (f=0;f<detailLayer;f++){
for (e=0;e<(MAX_SHADER_STAGES-1);e++)
{
if (shader.defaultShader)
break; // DON'T! This fixes a crash, trying to stage up placeholder/default textures
// Pick the first free stage to do, hopefully the last
if (stages[e].active == qfalse){ thisstage = e; shouldIDetail = 1; break;}
// find detail texture scale by determining which of the stages have the largest image
if (stages[e].bundle[0].image[0]->uploadHeight > wi) wi = stages[e].bundle[0].image[0]->uploadWidth;
if (stages[e].bundle[0].image[0]->uploadHeight > hi) hi = stages[e].bundle[0].image[0]->uploadHeight;
// for adjusting the detail textures and skipping some redundancy
if (stages[e].isDetail){
if (f < 1){ gotdetailalready = 1; shouldIDetail = 0;
imageDetail = stages[e].bundle[0].image[0]; // this is it
hasaDetailImage = 1;
}
if (r_detailTextureScale->integer){
if (stages[e].bundle[0].texMods[0].type == TMOD_SCALE)
{
wi = 0.25 * wi / (detailScale / (f + 1));
hi = 0.25 * hi / (detailScale / (f + 1));
stages[e].bundle[0].texMods[0].scale[0] = wi;
stages[e].bundle[0].texMods[0].scale[1] = hi;
}
}
}
}
if (r_detailTextures->integer < 3) shouldIDetail = 0; // don't add detail for low settings
if ((!gotdetailalready || thisstage) && (shouldIDetail)){
// detail it up because i don't care.
{
wi = 0.25 * (f + 1) * wi / detailScale;
hi = 0.25 * (f + 1) * hi / detailScale;
if (material == 1) // metalsteps
stages[thisstage].bundle[0].image[0] = R_FindImageFile( "gfx/fx/detail/d_genericmetal.tga", IMGFLAG_MIPMAP , IMGFLAG_MIPMAP);
else if (hasaDetailImage && imageDetail)
stages[thisstage].bundle[0].image[0] = imageDetail;
else
stages[thisstage].bundle[0].image[0] = R_FindImageFile( "gfx/fx/detail/d_generic.tga", IMGFLAG_MIPMAP , IMGFLAG_MIPMAP);
stages[thisstage].active = qtrue;
stages[thisstage].rgbGen = CGEN_IDENTITY;
stages[thisstage].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR | GLS_DEPTHFUNC_EQUAL;
stages[thisstage].bundle[0].texMods[0].scale[0] = wi;
stages[thisstage].bundle[0].texMods[0].scale[1] = hi;
stages[thisstage].bundle[0].texMods[0].type = TMOD_SCALE;
stages[thisstage].isDetail = qtrue;
stages[thisstage].bundle[0].numTexMods = 1;
}
}
}
}
}
sh = FinishShader();
return sh;
}
@@ -4363,6 +4487,8 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
}
}
//
// create the default shading commands
//
@@ -4400,6 +4526,53 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
stages[1].rgbGen = CGEN_IDENTITY;
stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
} else {
// leilei - automatic detail adding hack
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;
stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
// for identitylight
stages[0].stateBits = GLS_DEFAULT;
stages[1].bundle[0].image[0] = image;
stages[1].active = qtrue;
stages[1].rgbGen = CGEN_IDENTITY;
stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
// detail
{
int f;
for (f=0;f<detailLayer;f++){
if (f+2 > 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
wi = 0.25 * (f + 1) * stages[1].bundle[0].image[0]->uploadWidth / detailScale;
hi = 0.25 * (f + 1) * stages[1].bundle[0].image[0]->uploadHeight / detailScale;
stages[2+f].active = qtrue;
stages[2+f].rgbGen = CGEN_IDENTITY;
stages[2+f].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR;
stages[2+f].bundle[0].texMods[0].scale[0] = wi;
stages[2+f].bundle[0].texMods[0].scale[1] = hi;
stages[2+f].bundle[0].texMods[0].type = TMOD_SCALE;
stages[2+f].bundle[0].numTexMods = 1;
stages[2+f].isDetail = qtrue;
}
}
}
else
{
// two pass lightmap
stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
stages[0].bundle[0].isLightmap = qtrue;
@@ -4412,6 +4585,7 @@ 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;
}
}
return FinishShader();
@@ -4420,15 +4594,45 @@ shader_t *R_FindShaderReal( const char *name, int lightmapIndex, qboolean mipRaw
// leilei - rather stupid way to do a cel wrapper to work for all textures
shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {
shader_t *sh;
shader_t *ahsh;
/* // Sadly, I have deprecated the old cel hack. I am leaving it here. It breaks 2D textures BTW!!! :(
if (r_anime->integer){
sh = R_FindShaderReal(va("%s_cel",name), lightmapIndex, mipRawImage);
if ( sh->defaultShader )
sh = R_FindShaderReal(name, lightmapIndex, mipRawImage);
return sh;
}
else*/
// load real shader first?
sh = R_FindShaderReal(name, lightmapIndex, mipRawImage);
if (!Q_strncmp( name, "models/players", 14) ){ // restrict to players; speedup
if (r_suggestiveThemes->integer < 1) // find safe textures/shaders if available
{
sugthem = 1;
ahsh = R_FindShaderReal(va("%s_safe",name), lightmapIndex, mipRawImage);
if ( ahsh->defaultShader ){
return sh;
}
else
return ahsh;
}
else if (r_suggestiveThemes->integer > 1) // find lewd textures/shaders if available
{
sugthem = 2;
ahsh = R_FindShaderReal(va("%s_lewd",name), lightmapIndex, mipRawImage);
if ( ahsh->defaultShader ){
return sh;
}
else
return ahsh;
}
else // if just normally suggestive or an otherwise normal shader, default
return sh;
}
else
sh = R_FindShaderReal(name, lightmapIndex, mipRawImage);
return sh;
}