X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=5aa039e08de154240f9ca3dad4a3c301a5f66319;hb=2cda7ccb571b41372e2ee91edf1bf59ad6452c07;hp=aff2a60bb831345f09f0c8c51b861679859b6883;hpb=7a96ec58916ceea50684acf4c00eaef551199fef;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index aff2a60b..5aa039e0 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -33,7 +33,7 @@ rtexturepool_t *r_main_texturepool; // r_refdef_t r_refdef; -cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "1", "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_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_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; @@ -58,7 +58,7 @@ cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders 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)"}; +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_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"}; 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"}; @@ -242,7 +242,7 @@ float FogPoint_World(const vec3_t p) float FogPoint_Model(const vec3_t p) { - return FogForDistance(VectorDistance((p), rsurface.modelorg)); + return FogForDistance(VectorDistance((p), rsurface.modelorg) * Matrix4x4_ScaleFromMatrix(&rsurface.matrix)); } static void R_BuildBlankTextures(void) @@ -847,7 +847,8 @@ 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 = mix(myhalf4(texture2D(Texture_SecondaryColor, TexCoord)), color, terrainblend);\n" +" color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord)), color.rgb, terrainblend);\n" +" color.a = 1.0;\n" " //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n" "#endif\n" "\n" @@ -859,7 +860,7 @@ static const char *builtinshaderstring = " myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n" "# endif\n" "# else\n" -" myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5));\n" +" myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n" "# ifdef USESPECULAR\n" " myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n" "# endif\n" @@ -880,10 +881,16 @@ static const char *builtinshaderstring = " myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n" "# endif\n" "# ifdef USESPECULAR\n" +"# ifndef USEEXACTSPECULARMATH\n" " myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n" "\n" +"# endif\n" " // calculate directional shading\n" +"# ifdef USEEXACTSPECULARMATH\n" +" color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower)) * glosscolor);\n" +"# else\n" " color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * glosscolor);\n" +"# endif\n" "# else\n" "# ifdef USEDIFFUSE\n" " // calculate directional shading\n" @@ -908,13 +915,17 @@ static const char *builtinshaderstring = " // directional model lighting\n" "# ifdef USEDIFFUSE\n" " // get the light normal\n" -" myhalf3 diffusenormal = myhalf3(LightVector);\n" +" myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n" "# endif\n" "# ifdef USESPECULAR\n" " // calculate directional shading\n" " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n" +"# ifdef USEEXACTSPECULARMATH\n" +" color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n" +"# else\n" " myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n" " color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n" +"# endif\n" "# else\n" "# ifdef USEDIFFUSE\n" "\n" @@ -933,13 +944,29 @@ static const char *builtinshaderstring = " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n" "\n" " // get the light normal\n" -" myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhalf3(0.5);\n" -" myhalf3 diffusenormal = normalize(myhalf3(dot(diffusenormal_modelspace, myhalf3(VectorS)), dot(diffusenormal_modelspace, myhalf3(VectorT)), dot(diffusenormal_modelspace, myhalf3(VectorR))));\n" -" // calculate directional shading\n" -" myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n" +" myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n" +" myhalf3 diffusenormal;\n" +" diffusenormal.x = dot(diffusenormal_modelspace, myhalf3(VectorS));\n" +" diffusenormal.y = dot(diffusenormal_modelspace, myhalf3(VectorT));\n" +" diffusenormal.z = dot(diffusenormal_modelspace, myhalf3(VectorR));\n" +" // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n" +" // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n" +" // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n" +" // on that luxel, and NOT to its center, because recursive triangle subdivision is used\n" +" // to map the luxels to coordinates on the draw surfaces), which also causes\n" +" // deluxemaps to be wrong because light contributions from the wrong side of the surface\n" +" // are added up. To prevent divisions by zero or strong exaggerations, a max()\n" +" // nudge is done here at expense of some additional fps. This is ONLY needed for\n" +" // deluxemaps, tangentspace deluxemap avoid this problem by design.\n" +" myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / max(0.25, diffusenormal.z)), 0.0)));\n" +" // 0.25 supports up to 75.5 degrees normal/deluxe angle\n" "# ifdef USESPECULAR\n" +"# ifdef USEEXACTSPECULARMATH\n" +" tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n" +"# else\n" " myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n" " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n" +"# endif\n" "# endif\n" "\n" " // apply lightmap color\n" @@ -953,12 +980,16 @@ static const char *builtinshaderstring = " // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n" "\n" " // get the light normal\n" -" myhalf3 diffusenormal = normalize(myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhalf3(0.5));\n" -" // calculate directional shading\n" -" myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n" +" myhalf3 diffusenormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n" +" // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n" +" myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / diffusenormal.z), 0.0)));\n" "# ifdef USESPECULAR\n" +"# ifdef USEEXACTSPECULARMATH\n" +" tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n" +"# else\n" " myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n" " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n" +"# endif\n" "# endif\n" "\n" " // apply lightmap color\n" @@ -1057,13 +1088,14 @@ typedef enum shaderpermutation_e 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_REFLECTION = 1<<8, // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface - SHADERPERMUTATION_OFFSETMAPPING = 1<<9, // adjust texcoords to roughly simulate a displacement mapped surface - SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) - SHADERPERMUTATION_GAMMARAMPS = 1<<11, // gamma (postprocessing only) - SHADERPERMUTATION_POSTPROCESSING = 1<<12, // user defined postprocessing - SHADERPERMUTATION_LIMIT = 1<<13, // size of permutations array - SHADERPERMUTATION_COUNT = 13 // size of shaderpermutationinfo array + 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_t; @@ -1078,6 +1110,7 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] = {"#define USECUBEFILTER\n", " cubefilter"}, {"#define USEGLOW\n", " glow"}, {"#define USESPECULAR\n", " specular"}, + {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"}, {"#define USEREFLECTION\n", " reflection"}, {"#define USEOFFSETMAPPING\n", " offsetmapping"}, {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"}, @@ -1393,7 +1426,7 @@ void R_GLSL_DumpShader_f(void) { int i; - qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false); + qfile_t *file = FS_OpenRealFile("glsl/default.glsl", "w", false); if(!file) { Con_Printf("failed to write to glsl/default.glsl\n"); @@ -1473,7 +1506,7 @@ void R_SetupGenericTwoTextureShader(int texturemode) if (gl_support_fragment_shader) { if (r_glsl.integer && r_glsl_usegeneric.integer) - R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)))); + R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)))); else if (r_glsl_permutation) { r_glsl_permutation = NULL; @@ -1652,6 +1685,9 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; } + if(permutation & SHADERPERMUTATION_SPECULAR) + if(r_shadow_glossexact.integer) + permutation |= SHADERPERMUTATION_EXACTSPECULARMATH; R_SetupShader_SetPermutation(mode, permutation); if (mode == SHADERMODE_LIGHTSOURCE) { @@ -1736,8 +1772,15 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f else qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0); } - if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip); - if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower); + if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip * Matrix4x4_ScaleFromMatrix(&rsurface.matrix)); + if(permutation & SHADERPERMUTATION_EXACTSPECULARMATH) + { + if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * 0.25); + } + else + { + if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower); + } if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value); CHECKGLERROR } @@ -1862,7 +1905,42 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid return item; } -skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) +#define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \ + { \ + unsigned long long avgcolor[5], wsum; \ + int pix, comp, w; \ + avgcolor[0] = 0; \ + avgcolor[1] = 0; \ + avgcolor[2] = 0; \ + avgcolor[3] = 0; \ + avgcolor[4] = 0; \ + wsum = 0; \ + for(pix = 0; pix < cnt; ++pix) \ + { \ + w = 0; \ + for(comp = 0; comp < 3; ++comp) \ + w += getpixel; \ + if(w) /* ignore perfectly black pixels because that is better for model skins */ \ + { \ + ++wsum; \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + w = getpixel; \ + for(comp = 0; comp < 3; ++comp) \ + avgcolor[comp] += getpixel * w; \ + avgcolor[3] += w; \ + } \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + avgcolor[4] += getpixel; \ + } \ + if(avgcolor[3] == 0) /* no pixels seen? even worse */ \ + avgcolor[3] = 1; \ + skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \ + } + +skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha) { // FIXME: it should be possible to disable loading various layers using // cvars, to prevent wasted loading time and memory usage if the user does @@ -1879,6 +1957,8 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole int basepixels_height; skinframe_t *skinframe; + *has_alpha = false; + if (cls.state == ca_dedicated) return NULL; @@ -1921,6 +2001,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole if (j < basepixels_width * basepixels_height * 4) { // has transparent pixels + *has_alpha = true; pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); for (j = 0;j < image_width * image_height * 4;j += 4) { @@ -1934,12 +2015,15 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole } } + R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + // _norm is the name used by tenebrae and has been adopted as standard if (loadnormalmap) { if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL) { - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); Mem_Free(pixels); pixels = NULL; } @@ -1947,7 +2031,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value); - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); Mem_Free(pixels); Mem_Free(bumppixels); } @@ -1955,7 +2039,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole { pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4); Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value); - skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); + skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL); Mem_Free(pixels); } } @@ -1973,6 +2057,12 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole return skinframe; } +skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain) +{ + qboolean has_alpha; + return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, &has_alpha); +} + static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force) { int i; @@ -2044,6 +2134,9 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co } } + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + return skinframe; } @@ -2051,6 +2144,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i { int i; unsigned char *temp1, *temp2; + unsigned int *palette; skinframe_t *skinframe; if (cls.state == ca_dedicated) @@ -2061,6 +2155,8 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i if (skinframe && skinframe->base) return skinframe; + palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)); + skinframe->stain = NULL; skinframe->merged = NULL; skinframe->base = r_texture_notexture; @@ -2089,7 +2185,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i Mem_Free(temp1); } // use either a custom palette, or the quake palette - skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)), skinframe->textureflags, true); // all + skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all if (loadglowtexture) skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow if (loadpantsandshirt) @@ -2108,6 +2204,9 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask } + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); + return skinframe; } @@ -2129,6 +2228,11 @@ skinframe_t *R_SkinFrame_LoadMissing(void) skinframe->glow = NULL; skinframe->fog = NULL; + skinframe->avgcolor[0] = rand() / RAND_MAX; + skinframe->avgcolor[1] = rand() / RAND_MAX; + skinframe->avgcolor[2] = rand() / RAND_MAX; + skinframe->avgcolor[3] = 1; + return skinframe; } @@ -2348,6 +2452,22 @@ GL_Init extern char *ENGINE_EXTENSIONS; void GL_Init (void) { + gl_renderer = (const char *)qglGetString(GL_RENDERER); + gl_vendor = (const char *)qglGetString(GL_VENDOR); + gl_version = (const char *)qglGetString(GL_VERSION); + gl_extensions = (const char *)qglGetString(GL_EXTENSIONS); + + if (!gl_extensions) + gl_extensions = ""; + if (!gl_platformextensions) + gl_platformextensions = ""; + + Con_Printf("GL_VENDOR: %s\n", gl_vendor); + Con_Printf("GL_RENDERER: %s\n", gl_renderer); + Con_Printf("GL_VERSION: %s\n", gl_version); + Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions); + Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); + VID_CheckExtensions(); // LordHavoc: report supported extensions @@ -2470,11 +2590,14 @@ static void R_View_UpdateEntityVisible (void) if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs) { // worldmodel can check visibility + memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities); for (i = 0;i < r_refdef.scene.numentities;i++) { ent = r_refdef.scene.entities[i]; - r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs)) && ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs)); - + if (!(ent->flags & renderimask)) + if (!R_CullBox(ent->mins, ent->maxs) || (ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) + if ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs)) + r_refdef.viewcache.entityvisible[i] = true; } if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight) { @@ -2858,7 +2981,7 @@ static void R_Water_StartFrame(void) // calculate desired texture sizes // can't use water if the card does not support the texture size - if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size) + if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size || r_showsurfaces.integer) texturewidth = textureheight = waterwidth = waterheight = 0; else if (gl_support_arb_texture_non_power_of_two) { @@ -3404,6 +3527,9 @@ static void R_BlendView(void) if (r_glsl_permutation->loc_UserVec1 >= 0) { float a=0, b=0, c=0, d=0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &a, &b, &c, &d); qglUniform4fARB(r_glsl_permutation->loc_UserVec1, a, b, c, d); } @@ -4011,11 +4137,16 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh int i; float color[4]; prvm_edict_t *edict; + prvm_prog_t *prog_save = prog; + // this function draws bounding boxes of server entities if (!sv.active) return; + GL_CullFace(GL_NONE); R_SetupGenericShader(false); + + prog = 0; SV_VM_Begin(); for (i = 0;i < numsurfaces;i++) { @@ -4036,6 +4167,7 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]); } SV_VM_End(); + prog = prog_save; } static void R_DrawEntityBBoxes(void) @@ -4043,19 +4175,29 @@ static void R_DrawEntityBBoxes(void) int i; prvm_edict_t *edict; vec3_t center; + prvm_prog_t *prog_save = prog; + // this function draws bounding boxes of server entities if (!sv.active) return; + + prog = 0; SV_VM_Begin(); for (i = 0;i < prog->num_edicts;i++) { edict = PRVM_EDICT_NUM(i); if (edict->priv.server->free) continue; + // exclude the following for now, as they don't live in world coordinate space and can't be solid: + if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.tag_entity)->edict != 0) + continue; + if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.viewmodelforclient)->edict != 0) + continue; VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center); R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL); } SV_VM_End(); + prog = prog_save; } unsigned short nomodelelements[24] = @@ -4399,6 +4541,7 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { + int w, h, idx; int i; dp_model_t *model = ent->model; float f; @@ -4439,7 +4582,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) } // update currentskinframe to be a qw skin or animation frame - if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients) + if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[i].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) { if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin)) { @@ -4527,6 +4670,14 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) 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 = tcmod->parms[0]; + h = tcmod->parms[1]; + f = r_refdef.scene.time / (tcmod->parms[2] * w * h); + f = f - floor(f); + idx = 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); @@ -5582,6 +5733,27 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **te } } +static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, msurface_t **texturesurfacelist) +{ + int texturesurfaceindex; + int i; + float *v, *c2; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4) + { + c2[0] = 0.5; + c2[1] = 0.5; + c2[2] = 0.5; + c2[3] = 1; + } + } + rsurface.lightmapcolor4f = rsurface.array_color4f; + rsurface.lightmapcolor4f_bufferobject = 0; + rsurface.lightmapcolor4f_bufferoffset = 0; +} + static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist) { int texturesurfaceindex; @@ -5624,6 +5796,32 @@ static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **t rsurface.lightmapcolor4f_bufferoffset = 0; } +static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, msurface_t **texturesurfacelist) +{ + int texturesurfaceindex; + int i; + float f; + float *v, *c, *c2; + if (!rsurface.lightmapcolor4f) + return; + // generate color arrays for the surfaces in this list + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4) + { + f = FogPoint_Model(v); + c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f); + c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f); + c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f); + c2[3] = c[3]; + } + } + rsurface.lightmapcolor4f = rsurface.array_color4f; + rsurface.lightmapcolor4f_bufferobject = 0; + rsurface.lightmapcolor4f_bufferoffset = 0; +} + static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a) { int texturesurfaceindex; @@ -5647,6 +5845,29 @@ static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t * rsurface.lightmapcolor4f_bufferoffset = 0; } +static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, msurface_t **texturesurfacelist) +{ + int texturesurfaceindex; + int i; + float *c, *c2; + if (!rsurface.lightmapcolor4f) + return; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4) + { + c2[0] = c[0] + r_refdef.scene.ambient / 128.0; + c2[1] = c[1] + r_refdef.scene.ambient / 128.0; + c2[2] = c[2] + r_refdef.scene.ambient / 128.0; + c2[3] = c[3]; + } + } + rsurface.lightmapcolor4f = rsurface.array_color4f; + rsurface.lightmapcolor4f_bufferobject = 0; + rsurface.lightmapcolor4f_bufferoffset = 0; +} + static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) { // TODO: optimize @@ -5735,12 +5956,12 @@ static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } -static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor) { int texturesurfaceindex; int i; float f; - float *v, *c, *c2; + float *v, *c, *c2, alpha; vec3_t ambientcolor; vec3_t diffusecolor; vec3_t lightdir; @@ -5748,13 +5969,14 @@ static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t // model lighting VectorCopy(rsurface.modellight_lightdir, lightdir); f = 0.5f * r_refdef.lightmapintensity; - ambientcolor[0] = rsurface.modellight_ambient[0] * r * f; - ambientcolor[1] = rsurface.modellight_ambient[1] * g * f; - ambientcolor[2] = rsurface.modellight_ambient[2] * b * f; - diffusecolor[0] = rsurface.modellight_diffuse[0] * r * f; - diffusecolor[1] = rsurface.modellight_diffuse[1] * g * f; - diffusecolor[2] = rsurface.modellight_diffuse[2] * b * f; - if (VectorLength2(diffusecolor) > 0) + ambientcolor[0] = rsurface.modellight_ambient[0] * *r * f; + ambientcolor[1] = rsurface.modellight_ambient[1] * *g * f; + ambientcolor[2] = rsurface.modellight_ambient[2] * *b * f; + diffusecolor[0] = rsurface.modellight_diffuse[0] * *r * f; + diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f; + diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f; + alpha = *a; + if (VectorLength2(diffusecolor) > 0 && rsurface.normal3f) { // generate color arrays for the surfaces in this list for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) @@ -5771,27 +5993,32 @@ static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t VectorMA(ambientcolor, f, diffusecolor, c); else VectorCopy(ambientcolor, c); - c[3] = a; + c[3] = alpha; } } - r = 1; - g = 1; - b = 1; - a = 1; - applycolor = false; + *r = 1; + *g = 1; + *b = 1; + *a = 1; rsurface.lightmapcolor4f = rsurface.array_color4f; rsurface.lightmapcolor4f_bufferobject = 0; rsurface.lightmapcolor4f_bufferoffset = 0; + *applycolor = false; } else { - r = ambientcolor[0]; - g = ambientcolor[1]; - b = ambientcolor[2]; + *r = ambientcolor[0]; + *g = ambientcolor[1]; + *b = ambientcolor[2]; rsurface.lightmapcolor4f = NULL; rsurface.lightmapcolor4f_bufferobject = 0; rsurface.lightmapcolor4f_bufferoffset = 0; } +} + +static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +{ + RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor); if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist); if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a); R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); @@ -6216,11 +6443,115 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t } } +static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +{ + float c[4]; + + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + + if(rsurface.texture && rsurface.texture->currentskinframe) + memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c)); + else + { + c[0] = 1; + c[1] = 0; + c[2] = 1; + c[3] = 1; + } + + if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt) + { + c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7); + c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7); + c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7); + } + + // brighten it up (as texture value 127 means "unlit") + c[0] *= 2 * r_refdef.view.colorscale; + c[1] *= 2 * r_refdef.view.colorscale; + c[2] *= 2 * r_refdef.view.colorscale; + + if(rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA) + c[3] *= r_wateralpha.value; + + if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD) + { + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead + GL_DepthMask(false); + } + else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND) + { + GL_BlendFunc(rsurface.texture->customblendfunc[0], rsurface.texture->customblendfunc[1]); + GL_DepthMask(false); + } + else + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(writedepth); + } + + rsurface.lightmapcolor4f = NULL; + + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + + rsurface.lightmapcolor4f = NULL; + rsurface.lightmapcolor4f_bufferobject = 0; + rsurface.lightmapcolor4f_bufferoffset = 0; + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + { + qboolean applycolor = true; + float one = 1.0; + + RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist); + + r_refdef.lightmapintensity = 1; + RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor); + r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all + } + else + { + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + + rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f; + rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject; + rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + } + + if(!rsurface.lightmapcolor4f) + RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist); + + RSurf_DrawBatch_GL11_ApplyAmbient(texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, c[0], c[1], c[2], c[3]); + if(r_refdef.fogenabled) + RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(texturenumsurfaces, texturesurfacelist); + + R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); +} + static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) { CHECKGLERROR RSurf_SetupDepthAndCulling(); - if (r_glsl.integer && gl_support_fragment_shader) + if (r_showsurfaces.integer == 3) + R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + else if (r_glsl.integer && gl_support_fragment_shader) R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth); else if (gl_combine.integer && r_textureunits.integer >= 2) R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); @@ -6242,7 +6573,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const // 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 || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) + else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) RSurf_ActiveModelEntity(ent, false, false); else RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader); @@ -6285,30 +6616,38 @@ static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **tex RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } - else if (r_showsurfaces.integer) + else if (r_showsurfaces.integer && !r_refdef.view.showdebug) { RSurf_SetupDepthAndCulling(); - GL_DepthTest(true); - GL_BlendFunc(GL_ONE, GL_ZERO); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(0, 0, 0, 1); + GL_DepthTest(writedepth); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) + { + RSurf_SetupDepthAndCulling(); GL_AlphaTest(false); R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupGenericShader(false); RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - if (!r_refdef.view.showdebug) - { - GL_Color(0, 0, 0, 1); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); - } - else - RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthTest(true); + RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); } else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (!rsurface.texture->currentnumlayers) return; - else if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) && queueentity) + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) { // transparent surfaces get pushed off into the transparent queue int surfacelistindex; @@ -6578,20 +6917,32 @@ void R_DrawDebugModel(entity_render_t *ent) } extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); +int r_maxsurfacelist = 0; +msurface_t **r_surfacelist = NULL; void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) { int i, j, endj, f, flagsmask; - msurface_t *surface; texture_t *t; dp_model_t *model = r_refdef.scene.worldmodel; - const int maxsurfacelist = 1024; + msurface_t *surfaces; + unsigned char *update; int numsurfacelist = 0; - msurface_t *surfacelist[1024]; if (model == NULL) return; + if (r_maxsurfacelist < model->num_surfaces) + { + r_maxsurfacelist = model->num_surfaces; + if (r_surfacelist) + Mem_Free(r_surfacelist); + r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + } + RSurf_ActiveWorldEntity(); + surfaces = model->data_surfaces; + update = model->brushq1.lightmapupdateflags; + // update light styles on this submodel if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { @@ -6600,11 +6951,10 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep { if (style->value != r_refdef.scene.lightstylevalue[style->style]) { - msurface_t *surfaces = model->data_surfaces; int *list = style->surfacelist; style->value = r_refdef.scene.lightstylevalue[style->style]; for (j = 0;j < style->numsurfaces;j++) - surfaces[list[j]].cached_dlight = true; + update[list[j]] = true; } } } @@ -6624,64 +6974,73 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep rsurface.texture = NULL; rsurface.rtlight = NULL; numsurfacelist = 0; + // add visible surfaces to draw list j = model->firstmodelsurface; endj = j + model->nummodelsurfaces; - while (j < endj) + if (update) { - // quickly skip over non-visible surfaces - for (;j < endj && !r_refdef.viewcache.world_surfacevisible[j];j++) - ; - // quickly iterate over visible surfaces - for (;j < endj && r_refdef.viewcache.world_surfacevisible[j];j++) + for (;j < endj;j++) { - // process this surface - surface = model->data_surfaces + j; - // if this surface fits the criteria, add it to the list - if (surface->num_triangles) + if (r_refdef.viewcache.world_surfacevisible[j]) { - // if lightmap parameters changed, rebuild lightmap texture - if (surface->cached_dlight) - R_BuildLightMap(r_refdef.scene.worldentity, surface); - // add face to draw list - surfacelist[numsurfacelist++] = surface; - r_refdef.stats.world_triangles += surface->num_triangles; - if (numsurfacelist >= maxsurfacelist) - { - r_refdef.stats.world_surfaces += numsurfacelist; - R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); - numsurfacelist = 0; - } + r_surfacelist[numsurfacelist++] = surfaces + j; + // update lightmap if needed + if (update[j]) + R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); } } } - r_refdef.stats.world_surfaces += numsurfacelist; - if (numsurfacelist) - R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + else + for (;j < endj;j++) + if (r_refdef.viewcache.world_surfacevisible[j]) + r_surfacelist[numsurfacelist++] = surfaces + j; + // don't do anything if there were no surfaces + if (!numsurfacelist) + return; + R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); GL_AlphaTest(false); + + // add to stats if desired + if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + { + r_refdef.stats.world_surfaces += numsurfacelist; + for (j = 0;j < numsurfacelist;j++) + r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles; + } } void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) { - int i, j, f, flagsmask; - msurface_t *surface, *endsurface; + int i, j, endj, f, flagsmask; texture_t *t; dp_model_t *model = ent->model; - const int maxsurfacelist = 1024; + msurface_t *surfaces; + unsigned char *update; int numsurfacelist = 0; - msurface_t *surfacelist[1024]; if (model == NULL) return; + if (r_maxsurfacelist < model->num_surfaces) + { + r_maxsurfacelist = model->num_surfaces; + if (r_surfacelist) + Mem_Free(r_surfacelist); + r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + } + // if the model is static it doesn't matter what value we give for // wantnormals and wanttangents, so this logic uses only rules applicable // 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 || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) + else if ((ent->effects & EF_FULLBRIGHT) || (r_showsurfaces.integer && r_showsurfaces.integer != 3) || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f)) RSurf_ActiveModelEntity(ent, false, false); else RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly); + surfaces = model->data_surfaces; + update = model->brushq1.lightmapupdateflags; + // update light styles if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { @@ -6690,11 +7049,10 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr { if (style->value != r_refdef.scene.lightstylevalue[style->style]) { - msurface_t *surfaces = model->data_surfaces; int *list = style->surfacelist; style->value = r_refdef.scene.lightstylevalue[style->style]; for (j = 0;j < style->numsurfaces;j++) - surfaces[list[j]].cached_dlight = true; + update[list[j]] = true; } } } @@ -6714,29 +7072,28 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr rsurface.texture = NULL; rsurface.rtlight = NULL; numsurfacelist = 0; - surface = model->data_surfaces + model->firstmodelsurface; - endsurface = surface + model->nummodelsurfaces; - for (;surface < endsurface;surface++) + // add visible surfaces to draw list + j = model->firstmodelsurface; + endj = j + model->nummodelsurfaces; + for (;j < endj;j++) + r_surfacelist[numsurfacelist++] = surfaces + j; + // don't do anything if there were no surfaces + if (!numsurfacelist) + return; + // update lightmaps if needed + if (update) + for (j = model->firstmodelsurface;j < endj;j++) + if (update[j]) + R_BuildLightMap(ent, surfaces + j); + R_QueueSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + GL_AlphaTest(false); + + // add to stats if desired + if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) { - // if this surface fits the criteria, add it to the list - if (surface->num_triangles) - { - // if lightmap parameters changed, rebuild lightmap texture - if (surface->cached_dlight) - R_BuildLightMap(ent, surface); - // add face to draw list - surfacelist[numsurfacelist++] = surface; - r_refdef.stats.entities_triangles += surface->num_triangles; - if (numsurfacelist >= maxsurfacelist) - { - r_refdef.stats.entities_surfaces += numsurfacelist; - R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); - numsurfacelist = 0; - } - } + r_refdef.stats.entities++; + r_refdef.stats.entities_surfaces += numsurfacelist; + for (j = 0;j < numsurfacelist;j++) + r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles; } - r_refdef.stats.entities_surfaces += numsurfacelist; - if (numsurfacelist) - R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); - GL_AlphaTest(false); }