]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
fix motionblur cvar descriptions, also: First commit! :D
[xonotic/darkplaces.git] / gl_rmain.c
index cd72658e7d9b429b3c237eda5aece3b2d8ca4d0b..c61abfcf04e2d341de170be6118998a242101eb1 100644 (file)
@@ -28,21 +28,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 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 frame-by-frame alpha control {0 to 1} - 0.7 recommended"};
-cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage; requires r_motionblur to have a value"};
-cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "velocity at which there is minimum blur"};
-cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "velocity at which there is full blur"};
+cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "motionblur value scale - 0.7 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_vtime = {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 the alpha level of the motion blur variable"};
-cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.01", "randomizing coefficient to fix ghosting"};
+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_motionblur_debug = {0, "r_motionblur_debug", "0", "outputs current motionblur alpha value"};
 
 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"};
@@ -152,7 +152,7 @@ static struct r_bloomstate_s
        int bloomwidth, bloomheight;
 
        int screentexturewidth, screentextureheight;
-       rtexture_t *texture_screen; // also used for motion blur if enabled!
+       rtexture_t *texture_screen; /// \note also used for motion blur if enabled!
 
        int bloomtexturewidth, bloomtextureheight;
        rtexture_t *texture_bloom;
@@ -166,7 +166,7 @@ r_bloomstate;
 
 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;
@@ -188,7 +188,7 @@ unsigned int r_maxqueries;
 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,
@@ -590,6 +590,9 @@ static const char *builtinshaderstring =
 "#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"
@@ -640,6 +643,9 @@ static const char *builtinshaderstring =
 "      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"
@@ -881,7 +887,7 @@ static const char *builtinshaderstring =
 "      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"
@@ -889,9 +895,9 @@ static const char *builtinshaderstring =
 "#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"
@@ -1061,8 +1067,12 @@ static const char *builtinshaderstring =
 "      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"
@@ -1114,23 +1124,23 @@ shadermodeinfo_t;
 
 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_SATURATION = 1<<14, // user defined postprocessing
-       SHADERPERMUTATION_LIMIT = 1<<15, // size of permutations array
-       SHADERPERMUTATION_COUNT = 15 // 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;
 
@@ -1154,21 +1164,21 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#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;
@@ -1192,11 +1202,11 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
 
 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;
@@ -1235,8 +1245,8 @@ typedef struct r_glsl_permutation_s
        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;
@@ -1254,9 +1264,9 @@ typedef struct r_glsl_permutation_s
 }
 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)
@@ -1411,6 +1421,7 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                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);
@@ -2391,7 +2402,7 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_motionblur_bmin);
        Cvar_RegisterVariable(&r_motionblur_vmin);
        Cvar_RegisterVariable(&r_motionblur_vmax);
-       Cvar_RegisterVariable(&r_motionblur_vtime);
+       Cvar_RegisterVariable(&r_motionblur_vcoeff);
        Cvar_RegisterVariable(&r_motionblur_randomize);
        Cvar_RegisterVariable(&r_damageblur);
        Cvar_RegisterVariable(&r_motionblur_debug);
@@ -2731,7 +2742,7 @@ static void R_View_UpdateEntityVisible (void)
        }
 }
 
-// only used if skyrendermasked, and normally returns false
+/// only used if skyrendermasked, and normally returns false
 int R_DrawBrushModelsSky (void)
 {
        int i, sky;
@@ -3337,14 +3348,15 @@ void R_Bloom_StartFrame(void)
                for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
        }
 
-       if ((r_hdr.integer || r_bloom.integer || r_motionblur.value) && ((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_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_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_motionblur.value)
+       if (!(r_glsl.integer && (r_glsl_postprocess.integer || r_glsl_saturation.value != 1 || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && r_motionblur.value <= 0 && r_damageblur.value <= 0)
                screentexturewidth = screentextureheight = 0;
        if (!r_hdr.integer && !r_bloom.integer)
                bloomtexturewidth = bloomtextureheight = 0;
@@ -3618,7 +3630,7 @@ static void R_BlendView(void)
 
                        speed = VectorLength(cl.movement_velocity);
 
-                       a = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vtime.value), 1);
+                       a = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
                        avgspeed = avgspeed * (1 - a) + speed * a;
 
                        speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
@@ -4706,14 +4718,70 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
        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)
@@ -4807,70 +4875,21 @@ texture_t *R_GetCurrentTexture(texture_t *t)
 
        // 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;
@@ -5406,8 +5425,8 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta
                                        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);
@@ -6270,6 +6289,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t
                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));
@@ -6627,7 +6647,10 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf
        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;