mempool_t *r_main_mempool;
rtexturepool_t *r_main_texturepool;
-static int r_frame = 0; // used only by R_GetCurrentTexture
+static int r_frame = 0; ///< used only by R_GetCurrentTexture
//
// screen size info
//
r_refdef_t r_refdef;
+cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "motionblur value scale - 0.5 recommended"};
+cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage"};
+cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "minimum influence from velocity"};
+cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "maximum influence from velocity"};
+cvar_t r_motionblur_bmin = {CVAR_SAVE, "r_motionblur_bmin", "0.5", "velocity at which there is no blur yet (may be negative to always have some blur)"};
+cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding average reaction time for velocity"};
+cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"};
+cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
+
+cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
+
cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
-cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows DOWN, otherwise use the model lighting"};
+cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
+cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
+cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
+cvar_t r_shadows_drawafterrtlightning = {CVAR_SAVE, "r_shadows_drawafterrtlightning", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
+cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
+cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
extern cvar_t v_glslgamma;
int bloomwidth, bloomheight;
int screentexturewidth, screentextureheight;
- rtexture_t *texture_screen;
+ rtexture_t *texture_screen; /// \note also used for motion blur if enabled!
int bloomtexturewidth, bloomtextureheight;
rtexture_t *texture_bloom;
r_waterstate_t r_waterstate;
-// shadow volume bsp struct with automatically growing nodes buffer
+/// shadow volume bsp struct with automatically growing nodes buffer
svbsp_t r_svbsp;
rtexture_t *r_texture_blanknormalmap;
char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
-// vertex coordinates for a quad that covers the screen exactly
+/// vertex coordinates for a quad that covers the screen exactly
const static float r_screenvertex3f[12] =
{
0, 0, 0,
"#ifdef USEGAMMARAMPS\n"
"uniform sampler2D Texture_GammaRamps;\n"
"#endif\n"
+"#ifdef USESATURATION\n"
+"uniform float Saturation;\n"
+"#endif\n"
"#ifdef USEVERTEXTEXTUREBLEND\n"
"uniform vec4 TintColor;\n"
"#endif\n"
" gl_FragColor /= (1 + 5 * UserVec1.y);\n"
"#endif\n"
"\n"
+"#ifdef USESATURATION\n"
+" //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
+" myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
+" //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
+" gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n" // TODO: test this on ATI
+"#endif\n"
+"\n"
"#ifdef USEGAMMARAMPS\n"
" gl_FragColor.r = texture2D(Texture_GammaRamps, vec2(gl_FragColor.r, 0)).r;\n"
" gl_FragColor.g = texture2D(Texture_GammaRamps, vec2(gl_FragColor.g, 0)).g;\n"
"#else // !MODE_GENERIC\n"
"\n"
"varying vec2 TexCoord;\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+"varying vec2 TexCoord2;\n"
+"#endif\n"
"varying vec2 TexCoordLightmap;\n"
"\n"
"#ifdef MODE_LIGHTSOURCE\n"
" gl_FrontColor = gl_Color;\n"
" // copy the surface texcoord\n"
" TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+" TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
+"#endif\n"
"#ifndef MODE_LIGHTSOURCE\n"
"# ifndef MODE_LIGHTDIRECTION\n"
" TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
" myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
" //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n"
" //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n"
-" color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord)), color.rgb, terrainblend);\n"
+" color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n"
" color.a = 1.0;\n"
" //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
"#endif\n"
"#ifdef USEDIFFUSE\n"
" // get the surface normal and the gloss color\n"
"# ifdef USEVERTEXTEXTUREBLEND\n"
-" myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
+" myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
"# ifdef USESPECULAR\n"
-" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
+" myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
"# endif\n"
"# else\n"
" myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
" color *= TintColor;\n"
"\n"
"#ifdef USEGLOW\n"
+"#ifdef USEVERTEXTEXTUREBLEND\n"
+" color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend);\n"
+"#else\n"
" color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
"#endif\n"
+"#endif\n"
"\n"
"#ifdef USECONTRASTBOOST\n"
" color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhalf3(1, 1, 1));\n"
typedef enum shaderpermutation_e
{
- SHADERPERMUTATION_DIFFUSE = 1<<0, // (lightsource) whether to use directional shading
- SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, // indicates this is a two-layer material blend based on vertex alpha (q3bsp)
- SHADERPERMUTATION_COLORMAPPING = 1<<2, // indicates this is a colormapped skin
- SHADERPERMUTATION_CONTRASTBOOST = 1<<3, // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
- SHADERPERMUTATION_FOG = 1<<4, // tint the color by fog color or black if using additive blend mode
- SHADERPERMUTATION_CUBEFILTER = 1<<5, // (lightsource) use cubemap light filter
- SHADERPERMUTATION_GLOW = 1<<6, // (lightmap) blend in an additive glow texture
- SHADERPERMUTATION_SPECULAR = 1<<7, // (lightsource or deluxemapping) render specular effects
- SHADERPERMUTATION_EXACTSPECULARMATH = 1<<8, // (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
- SHADERPERMUTATION_REFLECTION = 1<<9, // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
- SHADERPERMUTATION_OFFSETMAPPING = 1<<10, // adjust texcoords to roughly simulate a displacement mapped surface
- SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
- SHADERPERMUTATION_GAMMARAMPS = 1<<12, // gamma (postprocessing only)
- SHADERPERMUTATION_POSTPROCESSING = 1<<13, // user defined postprocessing
- SHADERPERMUTATION_LIMIT = 1<<14, // size of permutations array
- SHADERPERMUTATION_COUNT = 14 // size of shaderpermutationinfo array
+ SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
+ SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
+ SHADERPERMUTATION_COLORMAPPING = 1<<2, ///< indicates this is a colormapped skin
+ SHADERPERMUTATION_CONTRASTBOOST = 1<<3, ///< r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
+ SHADERPERMUTATION_FOG = 1<<4, ///< tint the color by fog color or black if using additive blend mode
+ SHADERPERMUTATION_CUBEFILTER = 1<<5, ///< (lightsource) use cubemap light filter
+ SHADERPERMUTATION_GLOW = 1<<6, ///< (lightmap) blend in an additive glow texture
+ SHADERPERMUTATION_SPECULAR = 1<<7, ///< (lightsource or deluxemapping) render specular effects
+ SHADERPERMUTATION_EXACTSPECULARMATH = 1<<8, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
+ SHADERPERMUTATION_REFLECTION = 1<<9, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
+ SHADERPERMUTATION_OFFSETMAPPING = 1<<10, ///< adjust texcoords to roughly simulate a displacement mapped surface
+ SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<11, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
+ SHADERPERMUTATION_GAMMARAMPS = 1<<12, ///< gamma (postprocessing only)
+ SHADERPERMUTATION_POSTPROCESSING = 1<<13, ///< user defined postprocessing
+ SHADERPERMUTATION_SATURATION = 1<<14, ///< user defined postprocessing
+ SHADERPERMUTATION_LIMIT = 1<<15, ///< size of permutations array
+ SHADERPERMUTATION_COUNT = 15 ///< size of shaderpermutationinfo array
}
shaderpermutation_t;
{"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
{"#define USEGAMMARAMPS\n", " gammaramps"},
{"#define USEPOSTPROCESSING\n", " postprocessing"},
+ {"#define USESATURATION\n", " saturation"},
};
-// this enum is multiplied by SHADERPERMUTATION_MODEBASE
+/// this enum is multiplied by SHADERPERMUTATION_MODEBASE
typedef enum shadermode_e
{
- SHADERMODE_GENERIC, // (particles/HUD/etc) vertex color, optionally multiplied by one texture
- SHADERMODE_POSTPROCESS, // postprocessing shader (r_glsl_postprocess)
- SHADERMODE_DEPTH_OR_SHADOW, // (depthfirst/shadows) vertex shader only
- SHADERMODE_FLATCOLOR, // (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
- SHADERMODE_VERTEXCOLOR, // (lightmap) modulate texture by vertex colors (q3bsp)
- SHADERMODE_LIGHTMAP, // (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
- SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, // (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
- SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, // (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
- SHADERMODE_LIGHTDIRECTION, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
- SHADERMODE_LIGHTSOURCE, // (lightsource) use directional pixel shading from light source (rtlight)
- SHADERMODE_REFRACTION, // refract background (the material is rendered normally after this pass)
- SHADERMODE_WATER, // refract background and reflection (the material is rendered normally after this pass)
+ SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture
+ SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess)
+ SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only
+ SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
+ SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp)
+ SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
+ SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
+ SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
+ SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp)
+ SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
+ SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
+ SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
SHADERMODE_COUNT
}
shadermode_t;
typedef struct r_glsl_permutation_s
{
- // indicates if we have tried compiling this permutation already
+ /// indicates if we have tried compiling this permutation already
qboolean compiled;
- // 0 if compilation failed
+ /// 0 if compilation failed
int program;
- // locations of detected uniforms in program object, or -1 if not found
+ /// locations of detected uniforms in program object, or -1 if not found
int loc_Texture_First;
int loc_Texture_Second;
int loc_Texture_GammaRamps;
int loc_DiffuseColor;
int loc_SpecularColor;
int loc_LightDir;
- int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost
- int loc_GammaCoeff; // 1 / gamma
+ int loc_ContrastBoostCoeff; ///< 1 - 1/ContrastBoost
+ int loc_GammaCoeff; ///< 1 / gamma
int loc_DistortScaleRefractReflect;
int loc_ScreenScaleRefractReflect;
int loc_ScreenCenterRefractReflect;
int loc_UserVec4;
int loc_ClientTime;
int loc_PixelSize;
+ int loc_Saturation;
}
r_glsl_permutation_t;
-// information about each possible shader permutation
+/// information about each possible shader permutation
r_glsl_permutation_t r_glsl_permutations[SHADERMODE_COUNT][SHADERPERMUTATION_LIMIT];
-// currently selected permutation
+/// currently selected permutation
r_glsl_permutation_t *r_glsl_permutation;
static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
p->loc_UserVec4 = qglGetUniformLocationARB(p->program, "UserVec4");
p->loc_ClientTime = qglGetUniformLocationARB(p->program, "ClientTime");
p->loc_PixelSize = qglGetUniformLocationARB(p->program, "PixelSize");
+ p->loc_Saturation = qglGetUniformLocationARB(p->program, "Saturation");
// initialize the samplers to refer to the texture units we use
if (p->loc_Texture_First >= 0) qglUniform1iARB(p->loc_Texture_First , GL20TU_FIRST);
if (p->loc_Texture_Second >= 0) qglUniform1iARB(p->loc_Texture_Second , GL20TU_SECOND);
Cvar_RegisterVariable (&gl_fogend);
Cvar_RegisterVariable (&gl_skyclip);
}
+ Cvar_RegisterVariable(&r_motionblur);
+ Cvar_RegisterVariable(&r_motionblur_maxblur);
+ Cvar_RegisterVariable(&r_motionblur_bmin);
+ Cvar_RegisterVariable(&r_motionblur_vmin);
+ Cvar_RegisterVariable(&r_motionblur_vmax);
+ Cvar_RegisterVariable(&r_motionblur_vcoeff);
+ Cvar_RegisterVariable(&r_motionblur_randomize);
+ Cvar_RegisterVariable(&r_damageblur);
+ Cvar_RegisterVariable(&r_animcache);
Cvar_RegisterVariable(&r_depthfirst);
Cvar_RegisterVariable(&r_useinfinitefarclip);
Cvar_RegisterVariable(&r_nearclip);
Cvar_RegisterVariable(&r_dynamic);
Cvar_RegisterVariable(&r_fullbright);
Cvar_RegisterVariable(&r_shadows);
+ Cvar_RegisterVariable(&r_shadows_darken);
+ Cvar_RegisterVariable(&r_shadows_drawafterrtlightning);
+ Cvar_RegisterVariable(&r_shadows_castfrombmodels);
Cvar_RegisterVariable(&r_shadows_throwdistance);
+ Cvar_RegisterVariable(&r_shadows_throwdirection);
Cvar_RegisterVariable(&r_q1bsp_skymasking);
Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
Cvar_RegisterVariable(&gl_lightmaps);
Cvar_RegisterVariable(&r_test);
Cvar_RegisterVariable(&r_batchmode);
+ Cvar_RegisterVariable(&r_glsl_saturation);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
//==================================================================================
+// LordHavoc: animcache written by Echon, refactored and reformatted by me
+
+/**
+ * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
+ * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
+ * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
+ */
+
+typedef struct r_animcache_entity_s
+{
+ float *vertex3f;
+ float *normal3f;
+ float *svector3f;
+ float *tvector3f;
+ int maxvertices;
+ qboolean wantnormals;
+ qboolean wanttangents;
+}
+r_animcache_entity_t;
+
+typedef struct r_animcache_s
+{
+ r_animcache_entity_t entity[MAX_EDICTS*2];
+ int maxindex;
+ int currentindex;
+}
+r_animcache_t;
+
+static r_animcache_t r_animcachestate;
+
+void R_AnimCache_Free(void)
+{
+ int idx;
+ for (idx=0 ; idx<r_animcachestate.maxindex ; idx++)
+ {
+ r_animcachestate.entity[idx].maxvertices = 0;
+ Mem_Free(r_animcachestate.entity[idx].vertex3f);
+ r_animcachestate.entity[idx].vertex3f = NULL;
+ r_animcachestate.entity[idx].normal3f = NULL;
+ r_animcachestate.entity[idx].svector3f = NULL;
+ r_animcachestate.entity[idx].tvector3f = NULL;
+ }
+ r_animcachestate.currentindex = 0;
+ r_animcachestate.maxindex = 0;
+}
+
+void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
+{
+ int arraySize;
+ float *base;
+ r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
+
+ if (cache->maxvertices >= numvertices)
+ return;
+
+ // Release existing memory
+ if (cache->vertex3f)
+ Mem_Free(cache->vertex3f);
+
+ // Pad by 1024 verts
+ cache->maxvertices = (numvertices + 1023) & ~1023;
+ arraySize = cache->maxvertices * 3;
+
+ // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later
+ base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4);
+ r_animcachestate.entity[cacheIdx].vertex3f = base;
+ r_animcachestate.entity[cacheIdx].normal3f = base + arraySize;
+ r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2;
+ r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3;
+
+// Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f);
+}
+
+void R_AnimCache_NewFrame(void)
+{
+ int i;
+
+ if (r_animcache.integer && r_drawentities.integer)
+ r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
+ else if (r_animcachestate.maxindex)
+ R_AnimCache_Free();
+
+ r_animcachestate.currentindex = 0;
+
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ r_refdef.scene.entities[i]->animcacheindex = -1;
+}
+
+qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+{
+ dp_model_t *model = ent->model;
+ r_animcache_entity_t *c;
+ // see if it's already cached this frame
+ if (ent->animcacheindex >= 0)
+ {
+ // add normals/tangents if needed
+ c = r_animcachestate.entity + ent->animcacheindex;
+ if (c->wantnormals)
+ wantnormals = false;
+ if (c->wanttangents)
+ wanttangents = false;
+ if (wantnormals || wanttangents)
+ model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ }
+ else
+ {
+ // see if this ent is worth caching
+ if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
+ return false;
+ if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0))
+ return false;
+ // assign it a cache entry and make sure the arrays are big enough
+ R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices);
+ ent->animcacheindex = r_animcachestate.currentindex++;
+ c = r_animcachestate.entity + ent->animcacheindex;
+ c->wantnormals = wantnormals;
+ c->wanttangents = wanttangents;
+ model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ }
+ return true;
+}
+
+void R_AnimCache_CacheVisibleEntities(void)
+{
+ int i;
+ qboolean wantnormals;
+ qboolean wanttangents;
+
+ if (!r_animcachestate.maxindex)
+ return;
+
+ wantnormals = !r_showsurfaces.integer;
+ wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight);
+
+ // TODO: thread this?
+
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ {
+ if (!r_refdef.viewcache.entityvisible[i])
+ continue;
+ R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
+ }
+}
+
+//==================================================================================
+
static void R_View_UpdateEntityLighting (void)
{
int i;
}
}
-// only used if skyrendermasked, and normally returns false
+/// only used if skyrendermasked, and normally returns false
int R_DrawBrushModelsSky (void)
{
int i, sky;
for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
}
- if ((r_hdr.integer || r_bloom.integer) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size))
+ if ((r_hdr.integer || r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size))
{
Cvar_SetValueQuick(&r_hdr, 0);
Cvar_SetValueQuick(&r_bloom, 0);
+ Cvar_SetValueQuick(&r_motionblur, 0);
+ Cvar_SetValueQuick(&r_damageblur, 0);
}
- if (!(r_glsl.integer && (r_glsl_postprocess.integer || (v_glslgamma.integer && !vid_gammatables_trivial) || r_bloom.integer || r_hdr.integer)) && !r_bloom.integer)
+ if (!(r_glsl.integer && (r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
screentexturewidth = screentextureheight = 0;
if (!r_hdr.integer && !r_bloom.integer)
bloomtexturewidth = bloomtextureheight = 0;
// TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
// TODO: add exposure compensation features
- // TODO: add fp16 framebuffer support
+ // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object)
r_refdef.view.showdebug = false;
r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
{
if (r_bloomstate.texture_screen)
{
- // copy view into the screen texture
+ // make sure the buffer is available
+ if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
+
R_ResetViewRendering2D();
R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
R_Mesh_ColorPointer(NULL, 0, 0);
R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
GL_ActiveTexture(0);CHECKGLERROR
+
+ if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
+ {
+ // declare variables
+ float speed;
+ static float avgspeed;
+
+ speed = VectorLength(cl.movement_velocity);
+
+ cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
+ avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
+
+ speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
+ speed = bound(0, speed, 1);
+ speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
+
+ // calculate values into a standard alpha
+ cl.motionbluralpha = 1 - exp(-
+ (
+ (r_motionblur.value * speed / 80)
+ +
+ (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
+ )
+ /
+ max(0.0001, cl.time - cl.oldtime) // fps independent
+ );
+
+ cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
+ cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
+ // apply the blur
+ if (cl.motionbluralpha > 0)
+ {
+ R_SetupGenericShader(true);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(1, 1, 1, cl.motionbluralpha);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
+ R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
+ r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
+ }
+ }
+
+ // copy view into the screen texture
qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
}
(r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0)
| (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)
| ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
- | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0);
+ | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
+ | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
{
sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
}
+ if (r_glsl_permutation->loc_Saturation >= 0)
+ qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
return;
r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
- r_refdef.scene.rtworld = r_shadow_realtime_world.integer;
+ r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
r_refdef.scene.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
r_frame++; // used only by R_GetCurrentTexture
rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+ R_AnimCache_NewFrame();
+
if (r_refdef.view.isoverlay)
{
// TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
R_TimeReport("bmodelsky");
}
+ R_AnimCache_CacheVisibleEntities();
+
if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
{
r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
- if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+ if (r_shadows.integer > 0 && !r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
{
R_DrawModelShadows();
-
R_ResetViewRendering3D();
-
// don't let sound skip if going slow
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
if (r_refdef.scene.extraupdate)
S_ExtraUpdate ();
+ if (r_shadows.integer > 0 && r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
+ {
+ R_DrawModelShadows();
+ R_ResetViewRendering3D();
+ // don't let sound skip if going slow
+ if (r_refdef.scene.extraupdate)
+ S_ExtraUpdate ();
+ }
+
if (cl.csqc_vidvars.drawworld)
{
R_DrawLightningBeams();
return (float)(parms[0] + parms[1] * f);
}
-texture_t *R_GetCurrentTexture(texture_t *t)
+void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
{
int w, h, idx;
+ float f;
+ float tcmat[12];
+ matrix4x4_t matrix, temp;
+ switch(tcmod->tcmod)
+ {
+ case Q3TCMOD_COUNT:
+ case Q3TCMOD_NONE:
+ if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
+ matrix = r_waterscrollmatrix;
+ else
+ matrix = identitymatrix;
+ break;
+ case Q3TCMOD_ENTITYTRANSLATE:
+ // this is used in Q3 to allow the gamecode to control texcoord
+ // scrolling on the entity, which is not supported in darkplaces yet.
+ Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
+ break;
+ case Q3TCMOD_ROTATE:
+ Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
+ Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1);
+ Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
+ break;
+ case Q3TCMOD_SCALE:
+ Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
+ break;
+ case Q3TCMOD_SCROLL:
+ Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0);
+ break;
+ case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
+ w = (int) tcmod->parms[0];
+ h = (int) tcmod->parms[1];
+ f = r_refdef.scene.time / (tcmod->parms[2] * w * h);
+ f = f - floor(f);
+ idx = (int) floor(f * w * h);
+ Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
+ break;
+ case Q3TCMOD_STRETCH:
+ f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
+ Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
+ break;
+ case Q3TCMOD_TRANSFORM:
+ VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
+ VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
+ VectorSet(tcmat + 6, 0 , 0 , 1);
+ VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
+ Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
+ break;
+ case Q3TCMOD_TURBULENT:
+ // this is handled in the RSurf_PrepareVertices function
+ matrix = identitymatrix;
+ break;
+ }
+ temp = *texmatrix;
+ Matrix4x4_Concat(texmatrix, &matrix, &temp);
+}
+
+texture_t *R_GetCurrentTexture(texture_t *t)
+{
int i;
const entity_render_t *ent = rsurface.entity;
dp_model_t *model = ent->model;
- float f;
- float tcmat[12];
q3shaderinfo_layer_tcmod_t *tcmod;
if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent)
// there is no tcmod
if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
+ {
t->currenttexmatrix = r_waterscrollmatrix;
-
- for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+ t->currentbackgroundtexmatrix = r_waterscrollmatrix;
+ }
+ else
{
- matrix4x4_t matrix;
- switch(tcmod->tcmod)
- {
- case Q3TCMOD_COUNT:
- case Q3TCMOD_NONE:
- if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
- matrix = r_waterscrollmatrix;
- else
- matrix = identitymatrix;
- break;
- case Q3TCMOD_ENTITYTRANSLATE:
- // this is used in Q3 to allow the gamecode to control texcoord
- // scrolling on the entity, which is not supported in darkplaces yet.
- Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
- break;
- case Q3TCMOD_ROTATE:
- Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
- Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1);
- Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
- break;
- case Q3TCMOD_SCALE:
- Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
- break;
- case Q3TCMOD_SCROLL:
- Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0);
- break;
- case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
- w = (int) tcmod->parms[0];
- h = (int) tcmod->parms[1];
- f = r_refdef.scene.time / (tcmod->parms[2] * w * h);
- f = f - floor(f);
- idx = (int) floor(f * w * h);
- Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
- break;
- case Q3TCMOD_STRETCH:
- f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
- Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
- break;
- case Q3TCMOD_TRANSFORM:
- VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
- VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
- VectorSet(tcmat + 6, 0 , 0 , 1);
- VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
- Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
- break;
- case Q3TCMOD_TURBULENT:
- // this is handled in the RSurf_PrepareVertices function
- matrix = identitymatrix;
- break;
- }
- // either replace or concatenate the transformation
- if (i < 1)
- t->currenttexmatrix = matrix;
- else
- {
- matrix4x4_t temp = t->currenttexmatrix;
- Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
- }
+ Matrix4x4_CreateIdentity(&t->currenttexmatrix);
+ Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
}
+ for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
+ for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
+ R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
+
t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
t->glosstexture = r_texture_black;
if (t->currentmaterialflags & MATERIALFLAG_WALL)
{
int layerflags = 0;
- int blendfunc1, blendfunc2, depthmask;
+ int blendfunc1, blendfunc2;
+ qboolean depthmask;
if (t->currentmaterialflags & MATERIALFLAG_ADD)
{
blendfunc1 = GL_SRC_ALPHA;
}
if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
{
- if (wanttangents)
+ if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
+ {
+ rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
+ rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
+ rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
+ rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
+ }
+ else if (wanttangents)
{
rsurface.modelvertex3f = rsurface.array_modelvertex3f;
rsurface.modelsvector3f = rsurface.array_modelsvector3f;
rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
- Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
+ Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
}
if (generatetangents && !rsurface.modelsvector3f)
{
rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
- Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer);
+ Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
}
}
rsurface.vertex3f = rsurface.modelvertex3f;
VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
}
}
- Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
- Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+ Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+ Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
}
rsurface.vertex3f = rsurface.array_deformedvertex3f;
rsurface.vertex3f_bufferobject = 0;
VectorSubtract(end, start, up);
VectorNormalize(up);
// calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
- //VectorSubtract(rsurface.modelorg, center, forward);
- Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
+ VectorSubtract(rsurface.modelorg, center, forward);
+ //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
VectorNegate(forward, forward);
VectorReflect(forward, 0, up, forward);
VectorNormalize(forward);
VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
}
}
- Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
- Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+ Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
+ Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
}
rsurface.vertex3f = rsurface.array_deformedvertex3f;
rsurface.vertex3f_bufferobject = 0;
normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
VectorNormalize(normal);
}
- Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
+ Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
}
rsurface.svector3f = rsurface.array_deformedsvector3f;
rsurface.svector3f_bufferobject = 0;
float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
{
- float l, d, eyedir[3];
- VectorSubtract(rsurface.modelorg, vertex, eyedir);
- l = 0.5f / VectorLength(eyedir);
- d = DotProduct(normal, eyedir)*2;
- out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
- out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
+ // identical to Q3A's method, but executed in worldspace so
+ // carried models can be shiny too
+
+ float viewer[3], d, reflected[3], worldreflected[3];
+
+ VectorSubtract(rsurface.modelorg, vertex, viewer);
+ // VectorNormalize(viewer);
+
+ d = DotProduct(normal, viewer);
+
+ reflected[0] = normal[0]*2*d - viewer[0];
+ reflected[1] = normal[1]*2*d - viewer[1];
+ reflected[2] = normal[2]*2*d - viewer[2];
+ // note: this is proportinal to viewer, so we can normalize later
+
+ Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
+ VectorNormalize(worldreflected);
+
+ // note: this sphere map only uses world x and z!
+ // so positive and negative y will LOOK THE SAME.
+ out_tc[0] = 0.5 + 0.5 * worldreflected[1];
+ out_tc[1] = 0.5 - 0.5 * worldreflected[2];
}
}
rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
return;
R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
+ R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
GL_Color(1, 1, 1, 1);
R_Mesh_ColorPointer(NULL, 0, 0);
- R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
+ R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
if (r_glsl_permutation)
{
RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
}
- R_SetupSurfaceShader(vec3_origin, rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
+ R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
if (!r_glsl_permutation)
return;
R_SetupGenericShader(false);
if(rsurface.texture && rsurface.texture->currentskinframe)
+ {
memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c));
+ c[3] *= rsurface.texture->currentalpha;
+ }
else
{
c[0] = 1;
// to a model, knowing that they are meaningless otherwise
if (ent == r_refdef.scene.worldentity)
RSurf_ActiveWorldEntity();
- else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
RSurf_ActiveModelEntity(ent, false, false);
else
RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
// to a model, knowing that they are meaningless otherwise
if (ent == r_refdef.scene.worldentity)
RSurf_ActiveWorldEntity();
- else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
RSurf_ActiveModelEntity(ent, false, false);
else
RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);