//
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%)"};
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"};
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)
" 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"
" 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"
" 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"
" // 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"
" // 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"
" // 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"
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;
{"#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"},
{
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");
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;
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)
{
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
}
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
int basepixels_height;
skinframe_t *skinframe;
+ *has_alpha = false;
+
if (cls.state == ca_dedicated)
return NULL;
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)
{
}
}
+ 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;
}
{
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);
}
{
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);
}
}
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;
}
}
+ 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;
}
{
int i;
unsigned char *temp1, *temp2;
+ unsigned int *palette;
skinframe_t *skinframe;
if (cls.state == ca_dedicated)
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;
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)
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;
}
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;
}
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
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)
{
// 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)
{
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);
}
// 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++)
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;
}
// 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))
{
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);
}
}
+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;
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;
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
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;
// 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++)
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);
}
}
+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);
// 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);
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;
}
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)
{
{
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;
}
}
}
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)
{
{
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;
}
}
}
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);
}