cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
+cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
+cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
+cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
+cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
cvar_t r_fullbright = {0, "r_fullbright","0", "make everything bright cheat (not allowed in multiplayer)"};
cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
-cvar_t r_glsl = {0, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
-cvar_t r_glsl_offsetmapping = {0, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
-cvar_t r_glsl_offsetmapping_reliefmapping = {0, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
-cvar_t r_glsl_offsetmapping_scale = {0, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
-cvar_t r_glsl_deluxemapping = {0, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
+cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
+cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
+cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
+cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
+cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
-cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing
+cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
typedef struct r_glsl_bloomshader_s
//rtexture_t *r_texture_fogintensity;
// information about each possible shader permutation
-r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_COUNT];
+r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_MAX];
// currently selected permutation
r_glsl_permutation_t *r_glsl_permutation;
"// fragment shader specific:\n"
"#ifdef FRAGMENT_SHADER\n"
"\n"
+"// 11 textures, we can only use up to 16 on DX9-class hardware\n"
"uniform sampler2D Texture_Normal;\n"
"uniform sampler2D Texture_Color;\n"
"uniform sampler2D Texture_Gloss;\n"
"uniform samplerCube Texture_Cube;\n"
+"uniform sampler2D Texture_Attenuation;\n"
"uniform sampler2D Texture_FogMask;\n"
"uniform sampler2D Texture_Pants;\n"
"uniform sampler2D Texture_Shirt;\n"
"uniform myhalf SpecularScale;\n"
"uniform myhalf SpecularPower;\n"
"\n"
-"void main(void)\n"
+"vec2 OffsetMapping(vec2 TexCoord)\n"
"{\n"
-" // apply offsetmapping\n"
-"#ifdef USEOFFSETMAPPING\n"
-" vec2 TexCoordOffset = TexCoord;\n"
-"#define TexCoord TexCoordOffset\n"
-"\n"
" vec3 eyedir = vec3(normalize(EyeVector));\n"
" float depthbias = 1.0 - eyedir.z; // should this be a -?\n"
" depthbias = 1.0 - depthbias * depthbias;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
" if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
" TexCoord = RT.xy;\n"
-"#elif 1\n"
+"#else\n"
" // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
" //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
" //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-"#elif 0\n"
-" // 10 sample offset mapping\n"
-" //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
-" //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
-" vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1);\n"
-" //TexCoord += OffsetVector * 3.0;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-" TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
-"#elif 1\n"
-" // parallax mapping as described in the paper\n"
-" // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
-" // The paper provides code in the ARB fragment program assembly language\n"
-" // I translated it to GLSL but may have done something wrong - SavageX\n"
-" // LordHavoc: removed bias and simplified to one line\n"
-" // LordHavoc: this is just a single sample offsetmapping...\n"
-" TexCoordOffset += vec2(eyedir.x, -1.0 * eyedir.y) * OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).a;\n"
-"#else\n"
-" // parallax mapping as described in the paper\n"
-" // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
-" // The paper provides code in the ARB fragment program assembly language\n"
-" // I translated it to GLSL but may have done something wrong - SavageX\n"
-" float height = texture2D(Texture_Normal, TexCoord).a;\n"
-" height = (height - 0.5) * OffsetMapping_Scale; // bias and scale\n"
-" TexCoordOffset += height * vec2(eyedir.x, -1.0 * eyedir.y);\n"
"#endif\n"
+" return TexCoord;\n"
+"}\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" // apply offsetmapping\n"
+"#ifdef USEOFFSETMAPPING\n"
+" vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
+"#define TexCoord TexCoordOffset\n"
"#endif\n"
"\n"
" // combine the diffuse textures (base, pants, shirt)\n"
"#ifdef MODE_LIGHTSOURCE\n"
" // light source\n"
"\n"
-" // get the surface normal and light normal\n"
+" // calculate surface normal, light normal, and specular normal\n"
+" // compute color intensity for the two textures (colormap and glossmap)\n"
+" // scale by light color and attenuation as efficiently as possible\n"
+" // (do as much scalar math as possible rather than vector math)\n"
+"#ifdef USESPECULAR\n"
" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
" myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
+" myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
"\n"
" // calculate directional shading\n"
-" color.rgb *= AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
-"#ifdef USESPECULAR\n"
-" myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
-" color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
+" color.rgb = LightColor * myhalf(texture2D(Texture_Attenuation, length(CubeVector))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * myhvec3(texture2D(Texture_Gloss, TexCoord)));\n"
+"#else\n"
+"#ifdef USEDIFFUSE\n"
+" myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
+" myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
+"\n"
+" // calculate directional shading\n"
+" color.rgb = LightColor * myhalf(texture2D(Texture_Attenuation, length(CubeVector))) * color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
+"#else\n"
+" // calculate directionless shading\n"
+" color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, length(CubeVector)));\n"
+"#endif\n"
"#endif\n"
"\n"
"#ifdef USECUBEFILTER\n"
" color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
"#endif\n"
"\n"
-" // apply light color\n"
-" color.rgb *= LightColor;\n"
-"\n"
-" // apply attenuation\n"
-" //\n"
-" // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
-" // center and sharp falloff at the edge, this is about the most efficient\n"
-" // we can get away with as far as providing illumination.\n"
-" //\n"
-" // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
-" // provide significant illumination, large = slow = pain.\n"
-"// color.rgb *= myhalf(max(1.0 - dot(CubeVector, CubeVector), 0.0));\n"
-" color.rgb *= myhalf(max(2.0 - 2.0 * length(CubeVector), 0.0) / (1 + dot(CubeVector, CubeVector)));\n"
-"\n"
"\n"
"\n"
"\n"
{"#define USEGLOW\n", " glow"},
{"#define USEFOG\n", " fog"},
{"#define USECOLORMAPPING\n", " colormapping"},
+ {"#define USEDIFFUSE\n", " diffuse"},
{"#define USESPECULAR\n", " specular"},
{"#define USECUBEFILTER\n", " cubefilter"},
{"#define USEOFFSETMAPPING\n", " offsetmapping"},
{
int i;
qboolean shaderfound;
- r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
+ r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
int vertstrings_count;
int geomstrings_count;
int fragstrings_count;
char *shaderstring;
- const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
- const char *geomstrings_list[SHADERPERMUTATION_COUNT+1];
- const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
+ const char *vertstrings_list[32+1];
+ const char *geomstrings_list[32+1];
+ const char *fragstrings_list[32+1];
char permutationname[256];
if (p->compiled)
return;
p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
+ p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap, 7);
if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow, 9);
+ if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
CHECKGLERROR
qglUseProgramObjectARB(0);CHECKGLERROR
}
void R_GLSL_Restart_f(void)
{
int i;
- for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
+ for (i = 0;i < SHADERPERMUTATION_MAX;i++)
if (r_glsl_permutations[i].program)
GL_Backend_FreeProgram(r_glsl_permutations[i].program);
memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
}
-int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting)
+extern rtexture_t *r_shadow_attenuationgradienttexture;
+extern rtexture_t *r_shadow_attenuation2dtexture;
+extern rtexture_t *r_shadow_attenuation3dtexture;
+int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale)
{
// select a permutation of the lighting shader appropriate to this
// combination of texture, entity, light source, and fogging, only use the
// minimum features necessary to avoid wasting rendering time in the
// fragment shader on features that are not being used
const char *shaderfilename = NULL;
- int permutation = 0;
- float specularscale = rsurface_texture->specularscale;
+ unsigned int permutation = 0;
r_glsl_permutation = NULL;
// TODO: implement geometry-shader based shadow volumes someday
if (r_shadow_rtlight)
// light source
shaderfilename = "glsl/default.glsl";
permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
- specularscale *= r_shadow_rtlight->specularscale;
if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
permutation |= SHADERPERMUTATION_CUBEFILTER;
+ if (diffusescale > 0)
+ permutation |= SHADERPERMUTATION_DIFFUSE;
if (specularscale > 0)
- permutation |= SHADERPERMUTATION_SPECULAR;
+ permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
if (r_refdef.fogenabled)
permutation |= SHADERPERMUTATION_FOG;
if (rsurface_texture->colormapping)
permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
}
}
- if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
{
- if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
R_GLSL_CompilePermutation(shaderfilename, permutation);
- if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
{
// remove features until we find a valid permutation
- int i;
- for (i = SHADERPERMUTATION_COUNT-1;;i>>=1)
+ unsigned int i;
+ for (i = SHADERPERMUTATION_MASK;;i>>=1)
{
+ if (!i)
+ return 0; // utterly failed
// reduce i more quickly whenever it would not remove any bits
if (permutation < i)
continue;
permutation &= i;
- if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
R_GLSL_CompilePermutation(shaderfilename, permutation);
- if (r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
+ if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
break;
- if (!i)
- return 0; // utterly failed
}
}
}
- r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
+ r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
CHECKGLERROR
qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
R_Mesh_TexMatrix(0, &rsurface_texture->currenttexmatrix);
{
if (r_glsl_permutation->loc_Texture_Cube >= 0 && r_shadow_rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);
- if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
- if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_shadow_rtlight->ambientscale);
- if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_shadow_rtlight->diffusescale);
- if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
+ if (permutation & SHADERPERMUTATION_DIFFUSE)
+ {
+ if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
+ if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
+ if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
+ if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
+ }
+ else
+ {
+ // ambient only is simpler
+ if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
+ if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
+ if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
+ if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
+ }
}
else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
{
if (r_glsl_permutation->loc_AmbientColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface_entity->modellight_ambient[0], rsurface_entity->modellight_ambient[1], rsurface_entity->modellight_ambient[2]);
+ qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface_entity->modellight_ambient[0] * ambientscale, rsurface_entity->modellight_ambient[1] * ambientscale, rsurface_entity->modellight_ambient[2] * ambientscale);
if (r_glsl_permutation->loc_DiffuseColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface_entity->modellight_diffuse[0], rsurface_entity->modellight_diffuse[1], rsurface_entity->modellight_diffuse[2]);
+ qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface_entity->modellight_diffuse[0] * diffusescale, rsurface_entity->modellight_diffuse[1] * diffusescale, rsurface_entity->modellight_diffuse[2] * diffusescale);
if (r_glsl_permutation->loc_SpecularColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface_entity->modellight_diffuse[0] * rsurface_texture->specularscale, rsurface_entity->modellight_diffuse[1] * rsurface_texture->specularscale, rsurface_entity->modellight_diffuse[2] * rsurface_texture->specularscale);
+ qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface_entity->modellight_diffuse[0] * specularscale, rsurface_entity->modellight_diffuse[1] * specularscale, rsurface_entity->modellight_diffuse[2] * specularscale);
if (r_glsl_permutation->loc_LightDir >= 0)
qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface_entity->modellight_lightdir[0], rsurface_entity->modellight_lightdir[1], rsurface_entity->modellight_lightdir[2]);
}
if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface_texture->basetexture));
if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface_texture->glosstexture));
//if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
+ if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface_texture->currentskinframe->pants));
if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface_texture->currentskinframe->shirt));
void R_SwitchSurfaceShader(int permutation)
{
- if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK))
+ if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK))
{
- r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
+ r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
CHECKGLERROR
qglUseProgramObjectARB(r_glsl_permutation->program);
CHECKGLERROR
{
r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
- Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed\n");
+ Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
FOG_registercvars(); // FIXME: move this fog stuff to client?
Cvar_RegisterVariable(&r_nearclip);
Cvar_RegisterVariable(&r_showsurfaces);
Cvar_RegisterVariable(&r_showdisabledepthtest);
Cvar_RegisterVariable(&r_drawportals);
Cvar_RegisterVariable(&r_drawentities);
+ Cvar_RegisterVariable(&r_cullentities_trace);
+ Cvar_RegisterVariable(&r_cullentities_trace_samples);
+ Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
+ Cvar_RegisterVariable(&r_cullentities_trace_delay);
Cvar_RegisterVariable(&r_drawviewmodel);
Cvar_RegisterVariable(&r_speeds);
Cvar_RegisterVariable(&r_fullbrights);
return false;
}
+int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
+{
+ int i;
+ const mplane_t *p;
+ for (i = 0;i < numplanes;i++)
+ {
+ p = planes + i;
+ switch(p->signbits)
+ {
+ default:
+ case 0:
+ if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 1:
+ if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 2:
+ if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 3:
+ if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
+ return true;
+ break;
+ case 4:
+ if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 5:
+ if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 6:
+ if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ case 7:
+ if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
//==================================================================================
static void R_UpdateEntityLighting(entity_render_t *ent)
ent = r_refdef.entities[i];
r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
}
+ if(r_cullentities_trace.integer)
+ {
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->model && (ent->model->name[0] == '*')))
+ {
+ if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
+ ent->last_trace_visibility = realtime;
+ if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
+ r_viewcache.entityvisible[i] = 0;
+ }
+ }
+ }
}
else
{
static void R_View_SetFrustum(void)
{
+ double slopex, slopey;
+
// break apart the view matrix into vectors for various purposes
Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
VectorNegate(r_view.left, r_view.right);
- VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_x, r_view.left, r_view.frustum[0].normal);
- VectorMAM(1, r_view.forward, 1.0 / r_view.frustum_x, r_view.left, r_view.frustum[1].normal);
- VectorMAM(1, r_view.forward, 1.0 / -r_view.frustum_y, r_view.up, r_view.frustum[2].normal);
- VectorMAM(1, r_view.forward, 1.0 / r_view.frustum_y, r_view.up, r_view.frustum[3].normal);
+ slopex = 1.0 / r_view.frustum_x;
+ slopey = 1.0 / r_view.frustum_y;
+ VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
+ VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
+ VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
+ VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
VectorCopy(r_view.forward, r_view.frustum[4].normal);
VectorNormalize(r_view.frustum[0].normal);
VectorNormalize(r_view.frustum[1].normal);
PlaneClassify(&r_view.frustum[3]);
PlaneClassify(&r_view.frustum[4]);
+ // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
+ VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
+
// LordHavoc: note to all quake engine coders, Quake had a special case
// for 90 degrees which assumed a square view (wrong), so I removed it,
// Quake2 has it disabled as well.
extern void R_DrawLightningBeams (void);
extern void VM_CL_AddPolygonsToMeshQueue (void);
extern void R_DrawPortals (void);
+extern cvar_t cl_locs_show;
+static void R_DrawLocs(void);
void R_RenderScene(void)
{
// don't let sound skip if going slow
}
VM_CL_AddPolygonsToMeshQueue();
+ if (cl_locs_show.integer)
+ {
+ R_DrawLocs();
+ if (r_timereport_active)
+ R_TimeReport("showlocs");
+ }
+
if (r_drawportals.integer)
{
R_DrawPortals();
GL_DepthMask(true);
}
GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
- GL_CullFace((ent->flags & RENDER_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
R_Mesh_VertexPointer(nomodelvertex3f);
if (r_refdef.fogenabled)
{
t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
else if (t->currentalpha < 1)
t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
- if (ent->flags & RENDER_NOCULLFACE)
- t->currentmaterialflags |= MATERIALFLAG_NOSHADOW;
+ if (ent->effects & EF_DOUBLESIDED)
+ t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
if (ent->effects & EF_NODEPTHTEST)
t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW;
if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
t->backgroundglosstexture = r_texture_white;
t->specularpower = r_shadow_glossexponent.value;
+ // TODO: store reference values for these in the texture?
t->specularscale = 0;
if (r_shadow_gloss.integer > 0)
{
rsurface_texture = NULL;
}
-void RSurf_ActiveEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
+void RSurf_ActiveWorldEntity(void)
+{
+ RSurf_CleanUp();
+ rsurface_entity = r_refdef.worldentity;
+ rsurface_model = r_refdef.worldmodel;
+ if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
+ R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
+ R_Mesh_Matrix(&identitymatrix);
+ VectorCopy(r_view.origin, rsurface_modelorg);
+ rsurface_modelvertex3f = rsurface_model->surfmesh.data_vertex3f;
+ rsurface_modelsvector3f = rsurface_model->surfmesh.data_svector3f;
+ rsurface_modeltvector3f = rsurface_model->surfmesh.data_tvector3f;
+ rsurface_modelnormal3f = rsurface_model->surfmesh.data_normal3f;
+ rsurface_generatedvertex = false;
+ rsurface_vertex3f = rsurface_modelvertex3f;
+ rsurface_svector3f = rsurface_modelsvector3f;
+ rsurface_tvector3f = rsurface_modeltvector3f;
+ rsurface_normal3f = rsurface_modelnormal3f;
+}
+
+void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
{
RSurf_CleanUp();
- Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
rsurface_entity = ent;
rsurface_model = ent->model;
if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
R_Mesh_Matrix(&ent->matrix);
Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
- if ((rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0) && rsurface_model->surfmesh.isanimated)
+ if (rsurface_model->surfmesh.isanimated && (rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0))
{
if (wanttangents)
{
static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
if (rsurface_mode != RSURFMODE_SHOWSURFACES)
{
rsurface_mode = RSURFMODE_SHOWSURFACES;
R_Mesh_Matrix(&rsurface_entity->matrix);
}
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
GL_DepthMask(true);
// LordHavoc: HalfLife maps have freaky skypolys so don't use
// skymasking on them, and Quake3 never did sky masking (unlike
R_Mesh_ResetTextureState();
}
- R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2);
+ R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2, 1, 1, rsurface_texture->specularscale);
if (!r_glsl_permutation)
return;
else if (rsurface_texture->currentnumlayers)
{
GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
- GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2);
GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED));
GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha);
{
int i, j;
int texturenumsurfaces, endsurface;
+ texture_t *texture;
msurface_t *surface;
msurface_t *texturesurfacelist[1024];
// 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->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
- RSurf_ActiveEntity(ent, false, false);
+ if (ent == r_refdef.worldentity)
+ RSurf_ActiveWorldEntity();
+ else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
+ RSurf_ActiveModelEntity(ent, false, false);
else
- RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+ RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
for (i = 0;i < numsurfaces;i = j)
{
j = i + 1;
surface = rsurface_model->data_surfaces + surfacelist[i];
- rsurface_texture = surface->texture;
+ texture = surface->texture;
+ R_UpdateTextureInfo(ent, texture);
+ rsurface_texture = texture->currentframe;
rsurface_uselightmaptexture = surface->lightmaptexture != NULL;
// scan ahead until we find a different texture
endsurface = min(i + 1024, numsurfaces);
for (;j < endsurface;j++)
{
surface = rsurface_model->data_surfaces + surfacelist[j];
- if (rsurface_texture != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
+ if (texture != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
break;
texturesurfacelist[texturenumsurfaces++] = surface;
}
RSurf_CleanUp();
}
-void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist)
+void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask)
{
int i, j;
vec3_t tempcenter, center;
+ texture_t *texture;
// break the surface list down into batches by texture and use of lightmapping
for (i = 0;i < numsurfaces;i = j)
{
j = i + 1;
- rsurface_texture = surfacelist[i]->texture;
+ // texture is the base texture pointer, rsurface_texture is the
+ // current frame/skin the texture is directing us to use (for example
+ // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
+ // use skin 1 instead)
+ texture = surfacelist[i]->texture;
+ rsurface_texture = texture->currentframe;
rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
+ if (!(rsurface_texture->currentmaterialflags & flagsmask))
+ {
+ // if this texture is not the kind we want, skip ahead to the next one
+ for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
+ ;
+ continue;
+ }
if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
{
// transparent surfaces get pushed off into the transparent queue
}
else
{
- // simply scan ahead until we find a different texture
- for (;j < numsurfaces && rsurface_texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++);
+ // simply scan ahead until we find a different texture or lightmap state
+ for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
+ ;
// render the range of surfaces
R_DrawTextureSurfaceList(j - i, surfacelist + i);
}
}
}
-extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
-void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
+float locboxvertex3f[6*4*3] =
{
- int i, j, k, l, endj, f, flagsmask;
- int counttriangles = 0;
- msurface_t *surface, *endsurface, **surfacechain;
- texture_t *t;
+ 1,0,1, 1,0,0, 1,1,0, 1,1,1,
+ 0,1,1, 0,1,0, 0,0,0, 0,0,1,
+ 1,1,1, 1,1,0, 0,1,0, 0,1,1,
+ 0,0,1, 0,0,0, 1,0,0, 1,0,1,
+ 0,0,1, 1,0,1, 1,1,1, 0,1,1,
+ 1,0,0, 0,0,0, 0,1,0, 1,1,0
+};
+
+int locboxelement3i[6*2*3] =
+{
+ 0, 1, 2, 0, 2, 3,
+ 4, 5, 6, 4, 6, 7,
+ 8, 9,10, 8,10,11,
+ 12,13,14, 12,14,15,
+ 16,17,18, 16,18,19,
+ 20,21,22, 20,22,23
+};
+
+void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
+{
+ int i, j;
+ cl_locnode_t *loc = (cl_locnode_t *)ent;
+ vec3_t mins, size;
+ float vertex3f[6*4*3];
+ CHECKGLERROR
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthMask(false);
+ GL_DepthTest(true);
+ GL_CullFace(GL_NONE);
+ R_Mesh_Matrix(&identitymatrix);
+
+ R_Mesh_VertexPointer(vertex3f);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+
+ i = surfacelist[0];
+ GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
+ ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
+ ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
+ surfacelist[0] < 0 ? 0.5f : 0.125f);
+
+ if (VectorCompare(loc->mins, loc->maxs))
+ {
+ VectorSet(size, 2, 2, 2);
+ VectorMA(loc->mins, -0.5f, size, mins);
+ }
+ else
+ {
+ VectorCopy(loc->mins, mins);
+ VectorSubtract(loc->maxs, loc->mins, size);
+ }
+
+ for (i = 0;i < 6*4*3;)
+ for (j = 0;j < 3;j++, i++)
+ vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
+
+ R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i);
+}
+
+void R_DrawLocs(void)
+{
+ int index;
+ cl_locnode_t *loc, *nearestloc;
+ vec3_t center;
+ nearestloc = CL_Locs_FindNearest(cl.movement_origin);
+ for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
+ {
+ VectorLerp(loc->mins, 0.5f, loc->maxs, center);
+ R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
+ }
+}
+
+void R_DrawCollisionBrushes(entity_render_t *ent)
+{
+ int i;
q3mbrush_t *brush;
+ msurface_t *surface;
model_t *model = ent->model;
+ if (!model->brush.num_brushes)
+ return;
+ CHECKGLERROR
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(false);
+ GL_DepthTest(!r_showdisabledepthtest.integer);
+ qglPolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);CHECKGLERROR
+ for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
+ if (brush->colbrushf && brush->colbrushf->numtriangles)
+ R_DrawCollisionBrush(brush->colbrushf);
+ for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
+ if (surface->num_collisiontriangles)
+ R_DrawCollisionSurface(ent, surface);
+ qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+}
+
+void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
+{
+ int i, j, k, l;
const int *elements;
+ msurface_t *surface;
+ model_t *model = ent->model;
+ vec3_t v;
+ CHECKGLERROR
+ GL_DepthTest(!r_showdisabledepthtest.integer);
+ GL_DepthMask(true);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+ for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ {
+ if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
+ continue;
+ rsurface_texture = surface->texture->currentframe;
+ if ((rsurface_texture->currentmaterialflags & flagsmask) && surface->num_triangles)
+ {
+ RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
+ if (drawtris)
+ {
+ if (!rsurface_texture->currentlayers->depthmask)
+ GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
+ else if (ent == r_refdef.worldentity)
+ GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
+ else
+ GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
+ elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
+ CHECKGLERROR
+ qglBegin(GL_LINES);
+ for (k = 0;k < surface->num_triangles;k++, elements += 3)
+ {
+ qglArrayElement(elements[0]);qglArrayElement(elements[1]);
+ qglArrayElement(elements[1]);qglArrayElement(elements[2]);
+ qglArrayElement(elements[2]);qglArrayElement(elements[0]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ if (drawnormals)
+ {
+ GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
+ qglBegin(GL_LINES);
+ for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ {
+ VectorCopy(rsurface_vertex3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ VectorMA(v, 8, rsurface_svector3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
+ qglBegin(GL_LINES);
+ for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ {
+ VectorCopy(rsurface_vertex3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
+ qglBegin(GL_LINES);
+ for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
+ {
+ VectorCopy(rsurface_vertex3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ VectorMA(v, 8, rsurface_normal3f + l * 3, v);
+ qglVertex3f(v[0], v[1], v[2]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ }
+ }
+ rsurface_texture = NULL;
+}
+
+extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
+void R_DrawWorldSurfaces(qboolean skysurfaces)
+{
+ int i, j, endj, f, flagsmask;
+ int counttriangles = 0;
+ msurface_t *surface, **surfacechain;
+ texture_t *t;
+ model_t *model = r_refdef.worldmodel;
const int maxsurfacelist = 1024;
int numsurfacelist = 0;
msurface_t *surfacelist[1024];
- vec3_t v;
if (model == NULL)
return;
- // 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->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
- RSurf_ActiveEntity(ent, false, false);
- else
- RSurf_ActiveEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
+ RSurf_ActiveWorldEntity();
// update light styles
if (!skysurfaces && model->brushq1.light_styleupdatechains)
}
}
- R_UpdateAllTextureInfo(ent);
+ R_UpdateAllTextureInfo(r_refdef.worldentity);
flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
f = 0;
t = NULL;
rsurface_uselightmaptexture = false;
rsurface_texture = NULL;
numsurfacelist = 0;
- if (ent == r_refdef.worldentity)
+ j = model->firstmodelsurface;
+ endj = j + model->nummodelsurfaces;
+ while (j < endj)
{
- j = model->firstmodelsurface;
- endj = j + model->nummodelsurfaces;
- while (j < endj)
- {
- // quickly skip over non-visible surfaces
- for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
- ;
- // quickly iterate over visible surfaces
- for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
- {
- // process this surface
- surface = model->data_surfaces + j;
- // if this surface fits the criteria, add it to the list
- if (surface->texture->currentmaterialflags & flagsmask && 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;
- counttriangles += surface->num_triangles;
- if (numsurfacelist >= maxsurfacelist)
- {
- R_QueueSurfaceList(numsurfacelist, surfacelist);
- numsurfacelist = 0;
- }
- }
- }
- }
- }
- else
- {
- surface = model->data_surfaces + model->firstmodelsurface;
- endsurface = surface + model->nummodelsurfaces;
- for (;surface < endsurface;surface++)
+ // quickly skip over non-visible surfaces
+ for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
+ ;
+ // quickly iterate over visible surfaces
+ for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
{
+ // process this surface
+ surface = model->data_surfaces + j;
// if this surface fits the criteria, add it to the list
- if (surface->texture->currentmaterialflags & flagsmask && surface->num_triangles)
+ if (surface->num_triangles)
{
// if lightmap parameters changed, rebuild lightmap texture
if (surface->cached_dlight)
- R_BuildLightMap(ent, surface);
+ R_BuildLightMap(r_refdef.worldentity, surface);
// add face to draw list
surfacelist[numsurfacelist++] = surface;
counttriangles += surface->num_triangles;
if (numsurfacelist >= maxsurfacelist)
{
- R_QueueSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
numsurfacelist = 0;
}
}
}
}
if (numsurfacelist)
- R_QueueSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
r_refdef.stats.entities_triangles += counttriangles;
RSurf_CleanUp();
- if (r_showcollisionbrushes.integer && model->brush.num_brushes && !skysurfaces)
+ if (r_showcollisionbrushes.integer && !skysurfaces)
+ R_DrawCollisionBrushes(r_refdef.worldentity);
+
+ if (r_showtris.integer || r_shownormals.integer)
+ R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
+}
+
+void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces)
+{
+ int i, f, flagsmask;
+ int counttriangles = 0;
+ msurface_t *surface, *endsurface, **surfacechain;
+ texture_t *t;
+ model_t *model = ent->model;
+ const int maxsurfacelist = 1024;
+ int numsurfacelist = 0;
+ msurface_t *surfacelist[1024];
+ if (model == NULL)
+ return;
+
+ // 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.worldentity)
+ RSurf_ActiveWorldEntity();
+ else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || 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);
+
+ // update light styles
+ if (!skysurfaces && model->brushq1.light_styleupdatechains)
{
- CHECKGLERROR
- R_Mesh_Matrix(&ent->matrix);
- R_Mesh_ColorPointer(NULL);
- R_Mesh_ResetTextureState();
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
- GL_DepthMask(false);
- GL_DepthTest(!r_showdisabledepthtest.integer);
- qglPolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);CHECKGLERROR
- for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
- if (brush->colbrushf && brush->colbrushf->numtriangles)
- R_DrawCollisionBrush(brush->colbrushf);
- for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
- if (surface->num_collisiontriangles)
- R_DrawCollisionSurface(ent, surface);
- qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+ for (i = 0;i < model->brushq1.light_styles;i++)
+ {
+ if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
+ {
+ model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
+ if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
+ for (;(surface = *surfacechain);surfacechain++)
+ surface->cached_dlight = true;
+ }
+ }
}
- if (r_showtris.integer || r_shownormals.integer)
+ R_UpdateAllTextureInfo(ent);
+ flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
+ f = 0;
+ t = NULL;
+ rsurface_uselightmaptexture = false;
+ rsurface_texture = NULL;
+ numsurfacelist = 0;
+ surface = model->data_surfaces + model->firstmodelsurface;
+ endsurface = surface + model->nummodelsurfaces;
+ for (;surface < endsurface;surface++)
{
- CHECKGLERROR
- GL_DepthTest(!r_showdisabledepthtest.integer);
- GL_DepthMask(true);
- GL_BlendFunc(GL_ONE, GL_ZERO);
- R_Mesh_ColorPointer(NULL);
- R_Mesh_ResetTextureState();
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ // if this surface fits the criteria, add it to the list
+ if (surface->num_triangles)
{
- if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
- continue;
- rsurface_texture = surface->texture->currentframe;
- if ((rsurface_texture->currentmaterialflags & flagsmask) && 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;
+ counttriangles += surface->num_triangles;
+ if (numsurfacelist >= maxsurfacelist)
{
- RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
- if (r_showtris.integer)
- {
- if (!rsurface_texture->currentlayers->depthmask)
- GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
- else if (ent == r_refdef.worldentity)
- GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
- else
- GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
- elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
- CHECKGLERROR
- qglBegin(GL_LINES);
- for (k = 0;k < surface->num_triangles;k++, elements += 3)
- {
- qglArrayElement(elements[0]);qglArrayElement(elements[1]);
- qglArrayElement(elements[1]);qglArrayElement(elements[2]);
- qglArrayElement(elements[2]);qglArrayElement(elements[0]);
- }
- qglEnd();
- CHECKGLERROR
- }
- if (r_shownormals.integer)
- {
- GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
- qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
- {
- VectorCopy(rsurface_vertex3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- VectorMA(v, 8, rsurface_svector3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- }
- qglEnd();
- CHECKGLERROR
- GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
- qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
- {
- VectorCopy(rsurface_vertex3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- }
- qglEnd();
- CHECKGLERROR
- GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
- qglBegin(GL_LINES);
- for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
- {
- VectorCopy(rsurface_vertex3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- VectorMA(v, 8, rsurface_normal3f + l * 3, v);
- qglVertex3f(v[0], v[1], v[2]);
- }
- qglEnd();
- CHECKGLERROR
- }
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ numsurfacelist = 0;
}
}
- rsurface_texture = NULL;
}
+ if (numsurfacelist)
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ r_refdef.stats.entities_triangles += counttriangles;
+ RSurf_CleanUp();
+
+ if (r_showcollisionbrushes.integer && !skysurfaces)
+ R_DrawCollisionBrushes(ent);
+
+ if (r_showtris.integer || r_shownormals.integer)
+ R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);
}