r_viewcache_t r_viewcache;
cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
-cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "shows surfaces as different colors"};
+cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
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_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_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
cvar_t r_q1bsp_skymasking = {0, "r_qb1sp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
-cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "1.5", "how bright the glow is"};
+cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
+cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
-cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "2", "how much to darken the image before blurring to make the bloom effect"};
+cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
+cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
-cvar_t r_hdr_bloomintensity = {CVAR_SAVE, "r_hdr_bloomintensity", "0.5", "amount of bloom"};
cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
+cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
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...)"};
-rtexture_t *r_bloom_texture_screen;
-rtexture_t *r_bloom_texture_bloom;
+typedef struct r_glsl_bloomshader_s
+{
+ int program;
+ int loc_Texture_Bloom;
+}
+r_glsl_bloomshader_t;
+
+static struct r_bloomstate_s
+{
+ qboolean enabled;
+ qboolean hdr;
+
+ int bloomwidth, bloomheight;
+
+ int screentexturewidth, screentextureheight;
+ rtexture_t *texture_screen;
+
+ int bloomtexturewidth, bloomtextureheight;
+ rtexture_t *texture_bloom;
+
+ r_glsl_bloomshader_t *shader;
+
+ // arrays for rendering the screen passes
+ float screentexcoord2f[8];
+ float bloomtexcoord2f[8];
+ float offsettexcoord2f[8];
+}
+r_bloomstate;
+
+// shadow volume bsp struct with automatically growing nodes buffer
+svbsp_t r_svbsp;
+
rtexture_t *r_texture_blanknormalmap;
rtexture_t *r_texture_white;
rtexture_t *r_texture_black;
// temporary variable used by a macro
int fogtableindex;
+// vertex coordinates for a quad that covers the screen exactly
+const static float r_screenvertex3f[12] =
+{
+ 0, 0, 0,
+ 1, 0, 0,
+ 1, 1, 0,
+ 0, 1, 0
+};
+
+extern void R_DrawModelShadows(void);
+
void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
{
int i;
" //\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(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"
{NULL, NULL}
};
-void R_GLSL_CompilePermutation(int permutation)
+void R_GLSL_CompilePermutation(const char *filename, int permutation)
{
int i;
- r_glsl_permutation_t *p = r_glsl_permutations + permutation;
+ qboolean shaderfound;
+ r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
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];
char permutationname[256];
if (p->compiled)
return;
p->compiled = true;
+ p->program = 0;
vertstrings_list[0] = "#define VERTEX_SHADER\n";
+ geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
vertstrings_count = 1;
+ geomstrings_count = 1;
fragstrings_count = 1;
permutationname[0] = 0;
for (i = 0;permutationinfo[i][0];i++)
if (permutation & (1<<i))
{
vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
+ geomstrings_list[geomstrings_count++] = permutationinfo[i][0];
fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
}
{
// keep line numbers correct
vertstrings_list[vertstrings_count++] = "\n";
+ geomstrings_list[geomstrings_count++] = "\n";
fragstrings_list[fragstrings_count++] = "\n";
}
}
- shaderstring = (char *)FS_LoadFile("glsl/default.glsl", r_main_mempool, false, NULL);
+ shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
+ shaderfound = false;
if (shaderstring)
{
- Con_DPrintf("GLSL shader text loaded from disk\n");
+ Con_DPrintf("GLSL shader text for \"%s\" loaded from disk\n", filename);
vertstrings_list[vertstrings_count++] = shaderstring;
+ geomstrings_list[geomstrings_count++] = shaderstring;
fragstrings_list[fragstrings_count++] = shaderstring;
+ shaderfound = true;
}
- else
+ else if (!strcmp(filename, "glsl/default.glsl"))
{
+ Con_DPrintf("GLSL shader text for \"%s\" loaded from engine\n", filename);
vertstrings_list[vertstrings_count++] = builtinshaderstring;
+ geomstrings_list[geomstrings_count++] = builtinshaderstring;
fragstrings_list[fragstrings_count++] = builtinshaderstring;
+ shaderfound = true;
}
- p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list);
+ // clear any lists that are not needed by this shader
+ if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER))
+ vertstrings_count = 0;
+ if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER))
+ geomstrings_count = 0;
+ if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER))
+ fragstrings_count = 0;
+ // compile the shader program
+ if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
+ p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
if (p->program)
{
CHECKGLERROR
qglUseProgramObjectARB(p->program);CHECKGLERROR
+ // look up all the uniform variable names we care about, so we don't
+ // have to look them up every time we set them
p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
+ // initialize the samplers to refer to the texture units we use
if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0);
if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1);
if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2);
// 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;
r_glsl_permutation = NULL;
+ // TODO: implement geometry-shader based shadow volumes someday
if (r_shadow_rtlight)
{
- permutation |= SHADERPERMUTATION_MODE_LIGHTSOURCE;
+ // 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 (specularscale > 0)
+ permutation |= SHADERPERMUTATION_SPECULAR;
+ if (r_refdef.fogenabled)
+ permutation |= SHADERPERMUTATION_FOG;
+ if (rsurface_texture->colormapping)
+ permutation |= SHADERPERMUTATION_COLORMAPPING;
+ if (r_glsl_offsetmapping.integer)
+ {
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+ if (r_glsl_offsetmapping_reliefmapping.integer)
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+ }
}
- else
+ else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
{
- if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+ // bright unshaded geometry
+ shaderfilename = "glsl/default.glsl";
+ permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
+ if (rsurface_texture->currentskinframe->glow)
+ permutation |= SHADERPERMUTATION_GLOW;
+ if (r_refdef.fogenabled)
+ permutation |= SHADERPERMUTATION_FOG;
+ if (rsurface_texture->colormapping)
+ permutation |= SHADERPERMUTATION_COLORMAPPING;
+ if (r_glsl_offsetmapping.integer)
{
- if (modellighting)
- permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
- else if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture)
- {
- if (r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
- {
- if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
- permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
- else
- permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
- }
- else if (r_glsl_deluxemapping.integer >= 2) // fake mode
- permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
- }
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+ if (r_glsl_offsetmapping_reliefmapping.integer)
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
}
+ }
+ else if (modellighting)
+ {
+ // directional model lighting
+ shaderfilename = "glsl/default.glsl";
+ permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
+ permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
if (rsurface_texture->currentskinframe->glow)
permutation |= SHADERPERMUTATION_GLOW;
+ if (specularscale > 0)
+ permutation |= SHADERPERMUTATION_SPECULAR;
+ if (r_refdef.fogenabled)
+ permutation |= SHADERPERMUTATION_FOG;
+ if (rsurface_texture->colormapping)
+ permutation |= SHADERPERMUTATION_COLORMAPPING;
+ if (r_glsl_offsetmapping.integer)
+ {
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+ if (r_glsl_offsetmapping_reliefmapping.integer)
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+ }
}
- if (specularscale > 0)
- permutation |= SHADERPERMUTATION_SPECULAR;
- if (r_refdef.fogenabled)
- permutation |= SHADERPERMUTATION_FOG;
- if (rsurface_texture->colormapping)
- permutation |= SHADERPERMUTATION_COLORMAPPING;
- if (r_glsl_offsetmapping.integer)
+ else
{
- permutation |= SHADERPERMUTATION_OFFSETMAPPING;
- if (r_glsl_offsetmapping_reliefmapping.integer)
- permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+ // lightmapped wall
+ shaderfilename = "glsl/default.glsl";
+ permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
+ if (r_glsl_deluxemapping.integer >= 1 && rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
+ {
+ // deluxemapping (light direction texture)
+ if (rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
+ permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
+ else
+ permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
+ if (specularscale > 0)
+ permutation |= SHADERPERMUTATION_SPECULAR;
+ }
+ else if (r_glsl_deluxemapping.integer >= 2)
+ {
+ // fake deluxemapping (uniform light direction in tangentspace)
+ permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
+ if (specularscale > 0)
+ permutation |= SHADERPERMUTATION_SPECULAR;
+ }
+ else
+ {
+ // ordinary lightmapping
+ permutation |= 0;
+ }
+ if (rsurface_texture->currentskinframe->glow)
+ permutation |= SHADERPERMUTATION_GLOW;
+ if (r_refdef.fogenabled)
+ permutation |= SHADERPERMUTATION_FOG;
+ if (rsurface_texture->colormapping)
+ permutation |= SHADERPERMUTATION_COLORMAPPING;
+ if (r_glsl_offsetmapping.integer)
+ {
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING;
+ if (r_glsl_offsetmapping_reliefmapping.integer)
+ permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
+ }
}
- if (!r_glsl_permutations[permutation].program)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
{
- if (!r_glsl_permutations[permutation].compiled)
- R_GLSL_CompilePermutation(permutation);
- if (!r_glsl_permutations[permutation].program)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
+ R_GLSL_CompilePermutation(shaderfilename, permutation);
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
{
// remove features until we find a valid permutation
int i;
if (permutation < i)
continue;
permutation &= i;
- if (!r_glsl_permutations[permutation].compiled)
- R_GLSL_CompilePermutation(permutation);
- if (r_glsl_permutations[permutation].program)
+ if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
+ R_GLSL_CompilePermutation(shaderfilename, permutation);
+ if (r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
break;
if (!i)
return 0; // utterly failed
}
}
}
- r_glsl_permutation = r_glsl_permutations + permutation;
+ r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
CHECKGLERROR
qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
R_Mesh_TexMatrix(0, &rsurface_texture->currenttexmatrix);
void R_SwitchSurfaceShader(int permutation)
{
- if (r_glsl_permutation != r_glsl_permutations + permutation)
+ if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK))
{
- r_glsl_permutation = r_glsl_permutations + permutation;
+ r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
CHECKGLERROR
qglUseProgramObjectARB(r_glsl_permutation->program);
CHECKGLERROR
void gl_main_start(void)
{
r_main_texturepool = R_AllocTexturePool();
- r_bloom_texture_screen = NULL;
- r_bloom_texture_bloom = NULL;
R_BuildBlankTextures();
R_BuildNoTexture();
if (gl_texturecubemap)
R_BuildNormalizationCube();
}
R_BuildFogTexture();
+ memset(&r_bloomstate, 0, sizeof(r_bloomstate));
memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
+ memset(&r_svbsp, 0, sizeof (r_svbsp));
}
void gl_main_shutdown(void)
{
+ if (r_svbsp.nodes)
+ Mem_Free(r_svbsp.nodes);
+ memset(&r_svbsp, 0, sizeof (r_svbsp));
R_FreeTexturePool(&r_main_texturepool);
- r_bloom_texture_screen = NULL;
- r_bloom_texture_bloom = NULL;
r_texture_blanknormalmap = NULL;
r_texture_white = NULL;
r_texture_black = NULL;
r_texture_whitecube = NULL;
r_texture_normalizationcube = NULL;
+ memset(&r_bloomstate, 0, sizeof(r_bloomstate));
R_GLSL_Restart_f();
}
{
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);
Cvar_RegisterVariable(&r_wateralpha);
Cvar_RegisterVariable(&r_dynamic);
Cvar_RegisterVariable(&r_fullbright);
+ Cvar_RegisterVariable(&r_shadows);
+ Cvar_RegisterVariable(&r_shadows_throwdistance);
Cvar_RegisterVariable(&r_q1bsp_skymasking);
Cvar_RegisterVariable(&r_textureunits);
Cvar_RegisterVariable(&r_glsl);
Cvar_RegisterVariable(&r_lerpmodels);
Cvar_RegisterVariable(&r_waterscroll);
Cvar_RegisterVariable(&r_bloom);
- Cvar_RegisterVariable(&r_bloom_intensity);
+ Cvar_RegisterVariable(&r_bloom_colorscale);
+ Cvar_RegisterVariable(&r_bloom_brighten);
Cvar_RegisterVariable(&r_bloom_blur);
Cvar_RegisterVariable(&r_bloom_resolution);
- Cvar_RegisterVariable(&r_bloom_power);
+ Cvar_RegisterVariable(&r_bloom_colorexponent);
+ Cvar_RegisterVariable(&r_bloom_colorsubtract);
Cvar_RegisterVariable(&r_hdr);
Cvar_RegisterVariable(&r_hdr_scenebrightness);
- Cvar_RegisterVariable(&r_hdr_bloomintensity);
Cvar_RegisterVariable(&r_hdr_glowintensity);
+ Cvar_RegisterVariable(&r_hdr_range);
Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
Cvar_RegisterVariable(&developer_texturelogging);
Cvar_RegisterVariable(&gl_lightmaps);
{
gl_backend_init();
R_Textures_Init();
- GL_Draw_Init();
GL_Main_Init();
+ GL_Draw_Init();
R_Shadow_Init();
R_Sky_Init();
GL_Surf_Init();
VID_CheckExtensions();
// LordHavoc: report supported extensions
- Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions );
+ Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
// clear to black (loading plaque will be seen over this)
CHECKGLERROR
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)
{
vec3_t tempdiffusenormal;
+
+ // fetch the lighting from the worldmodel data
VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
VectorClear(ent->modellight_diffuse);
- VectorClear(ent->modellight_lightdir);
+ VectorClear(tempdiffusenormal);
if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
{
vec3_t org;
}
else // highly rare
VectorSet(ent->modellight_ambient, 1, 1, 1);
+
+ // move the light direction into modelspace coordinates for lighting code
Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
VectorNormalize(ent->modellight_lightdir);
+
+ // scale ambient and directional light contributions according to rendering variables
ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
{
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_viewcache.entityvisible[i])
- R_UpdateEntityLighting(ent);
+ }
+ 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
{
ent = r_refdef.entities[i];
r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
- if (r_viewcache.entityvisible[i])
- R_UpdateEntityLighting(ent);
}
}
+
+ // update entity lighting (even on hidden entities for r_shadows)
+ for (i = 0;i < r_refdef.numentities;i++)
+ R_UpdateEntityLighting(r_refdef.entities[i]);
}
// only used if skyrendermasked, and normally returns false
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.
R_View_UpdateEntityVisible();
}
-void R_ResetViewRendering(void)
+void R_SetupView(const matrix4x4_t *matrix)
+{
+ if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
+ GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
+ else
+ GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
+
+ GL_SetupView_Orientation_FromEntity(matrix);
+}
+
+void R_ResetViewRendering2D(void)
{
if (gl_support_fragment_shader)
{
qglUseProgramObjectARB(0);CHECKGLERROR
}
+ DrawQ_Finish();
+
// GL is weird because it's bottom to top, r_view.y is top to bottom
qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+ GL_Color(1, 1, 1, 1);
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_AlphaTest(false);
+ GL_ScissorTest(false);
+ GL_DepthMask(false);
+ GL_DepthTest(false);
+ R_Mesh_Matrix(&identitymatrix);
+ R_Mesh_ResetTextureState();
+ qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+ qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
+ qglDepthFunc(GL_LEQUAL);CHECKGLERROR
+ qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+ GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
+}
+
+void R_ResetViewRendering3D(void)
+{
+ if (gl_support_fragment_shader)
+ {
+ qglUseProgramObjectARB(0);CHECKGLERROR
+ }
+
+ DrawQ_Finish();
+
+ // GL is weird because it's bottom to top, r_view.y is top to bottom
+ qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+ R_SetupView(&r_view.matrix);
+ GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
+ GL_Color(1, 1, 1, 1);
GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_AlphaTest(false);
GL_ScissorTest(true);
GL_DepthMask(true);
GL_DepthTest(true);
R_Mesh_Matrix(&identitymatrix);
R_Mesh_ResetTextureState();
+ qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
+ qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
+ qglDepthFunc(GL_LEQUAL);CHECKGLERROR
+ qglDisable(GL_STENCIL_TEST);CHECKGLERROR
+ qglStencilMask(~0);CHECKGLERROR
+ qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
+ qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
+ GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
}
+/*
+ R_Bloom_SetupShader(
+"// bloom shader\n"
+"// written by Forest 'LordHavoc' Hale\n"
+"\n"
+"// common definitions between vertex shader and fragment shader:\n"
+"\n"
+"#ifdef __GLSL_CG_DATA_TYPES\n"
+"#define myhalf half\n"
+"#define myhvec2 hvec2\n"
+"#define myhvec3 hvec3\n"
+"#define myhvec4 hvec4\n"
+"#else\n"
+"#define myhalf float\n"
+"#define myhvec2 vec2\n"
+"#define myhvec3 vec3\n"
+"#define myhvec4 vec4\n"
+"#endif\n"
+"\n"
+"varying vec2 ScreenTexCoord;\n"
+"varying vec2 BloomTexCoord;\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// vertex shader specific:\n"
+"#ifdef VERTEX_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
+" BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
+" // transform vertex to camera space, using ftransform to match non-VS\n"
+" // rendering\n"
+" gl_Position = ftransform();\n"
+"}\n"
+"\n"
+"#endif // VERTEX_SHADER\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"// fragment shader specific:\n"
+"#ifdef FRAGMENT_SHADER\n"
+"\n"
+"void main(void)\n"
+"{\n"
+" int x, y;
+" myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
+" for (x = -BLUR_X;x <= BLUR_X;x++)
+" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+" color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
+
+" gl_FragColor = vec4(color);\n"
+"}\n"
+"\n"
+"#endif // FRAGMENT_SHADER\n"
+*/
+
void R_RenderScene(void);
-void R_Bloom_MakeTexture(qboolean darken)
+void R_Bloom_StartFrame(void)
{
- int screenwidth, screenheight;
- int screentexturewidth, screentextureheight;
- int bloomtexturewidth, bloomtextureheight;
- int bloomwidth, bloomheight, x, range;
- float xoffset, yoffset, r;
- float vertex3f[12];
- float texcoord2f[3][8];
+ int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
// set bloomwidth and bloomheight to the bloom resolution that will be
// used (often less than the screen resolution for faster rendering)
- bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
- bloomheight = bound(1, bloomwidth * r_view.height / r_view.width, r_view.height);
+ r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
+ r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
+ r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
- // set the (poorly named) screenwidth and screenheight variables to
- // a power of 2 at least as large as the screen, these will define the
- // size of the texture to allocate
- for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
- for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
+ // calculate desired texture sizes
+ if (gl_support_arb_texture_non_power_of_two)
+ {
+ screentexturewidth = r_view.width;
+ screentextureheight = r_view.height;
+ bloomtexturewidth = r_bloomstate.bloomwidth;
+ bloomtextureheight = r_bloomstate.bloomheight;
+ }
+ else
+ {
+ for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
+ for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
+ for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
+ for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
+ }
- r_refdef.stats.bloom++;
+ if (r_hdr.integer)
+ {
+ screentexturewidth = screentextureheight = 0;
+ }
+ else if (r_bloom.integer)
+ {
+ }
+ else
+ {
+ screentexturewidth = screentextureheight = 0;
+ bloomtexturewidth = bloomtextureheight = 0;
+ }
+
+ if ((!bloomtexturewidth && !bloomtextureheight) || r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512 || screentexturewidth > gl_max_texture_size || screentextureheight > gl_max_texture_size || bloomtexturewidth > gl_max_texture_size || bloomtextureheight > gl_max_texture_size)
+ {
+ // can't use bloom if the parameters are too weird
+ // can't use bloom if the card does not support the texture size
+ if (r_bloomstate.texture_screen)
+ R_FreeTexture(r_bloomstate.texture_screen);
+ if (r_bloomstate.texture_bloom)
+ R_FreeTexture(r_bloomstate.texture_bloom);
+ memset(&r_bloomstate, 0, sizeof(r_bloomstate));
+ return;
+ }
+
+ r_bloomstate.enabled = true;
+ r_bloomstate.hdr = r_hdr.integer != 0;
// allocate textures as needed
- // TODO: reallocate these when size settings change
- if (!r_bloom_texture_screen)
- r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
- if (!r_bloom_texture_bloom)
- r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
-
- screentexturewidth = R_TextureWidth(r_bloom_texture_screen);
- screentextureheight = R_TextureHeight(r_bloom_texture_screen);
- bloomtexturewidth = R_TextureWidth(r_bloom_texture_bloom);
- bloomtextureheight = R_TextureHeight(r_bloom_texture_bloom);
-
- // vertex coordinates for a quad that covers the screen exactly
- vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
- vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
- vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
- vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
+ if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
+ {
+ if (r_bloomstate.texture_screen)
+ R_FreeTexture(r_bloomstate.texture_screen);
+ r_bloomstate.texture_screen = NULL;
+ r_bloomstate.screentexturewidth = screentexturewidth;
+ r_bloomstate.screentextureheight = screentextureheight;
+ if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
+ r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ }
+ if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
+ {
+ if (r_bloomstate.texture_bloom)
+ R_FreeTexture(r_bloomstate.texture_bloom);
+ r_bloomstate.texture_bloom = NULL;
+ r_bloomstate.bloomtexturewidth = bloomtexturewidth;
+ r_bloomstate.bloomtextureheight = bloomtextureheight;
+ if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
+ r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ }
// set up a texcoord array for the full resolution screen image
// (we have to keep this around to copy back during final render)
- texcoord2f[0][0] = 0;
- texcoord2f[0][1] = (float)r_view.height / (float)screentextureheight;
- texcoord2f[0][2] = (float)r_view.width / (float)screentexturewidth;
- texcoord2f[0][3] = (float)r_view.height / (float)screentextureheight;
- texcoord2f[0][4] = (float)r_view.width / (float)screentexturewidth;
- texcoord2f[0][5] = 0;
- texcoord2f[0][6] = 0;
- texcoord2f[0][7] = 0;
+ r_bloomstate.screentexcoord2f[0] = 0;
+ r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
+ r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
+ r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
+ r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
+ r_bloomstate.screentexcoord2f[5] = 0;
+ r_bloomstate.screentexcoord2f[6] = 0;
+ r_bloomstate.screentexcoord2f[7] = 0;
// set up a texcoord array for the reduced resolution bloom image
// (which will be additive blended over the screen image)
- texcoord2f[1][0] = 0;
- texcoord2f[1][1] = (float)bloomheight / (float)bloomtextureheight;
- texcoord2f[1][2] = (float)bloomwidth / (float)bloomtexturewidth;
- texcoord2f[1][3] = (float)bloomheight / (float)bloomtextureheight;
- texcoord2f[1][4] = (float)bloomwidth / (float)bloomtexturewidth;
- texcoord2f[1][5] = 0;
- texcoord2f[1][6] = 0;
- texcoord2f[1][7] = 0;
-
- R_ResetViewRendering();
- GL_DepthTest(false);
- R_Mesh_VertexPointer(vertex3f);
- R_Mesh_ColorPointer(NULL);
+ r_bloomstate.bloomtexcoord2f[0] = 0;
+ r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+ r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+ r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+ r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+ r_bloomstate.bloomtexcoord2f[5] = 0;
+ r_bloomstate.bloomtexcoord2f[6] = 0;
+ r_bloomstate.bloomtexcoord2f[7] = 0;
+}
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
+void R_Bloom_CopyScreenTexture(float colorscale)
+{
+ r_refdef.stats.bloom++;
+
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
// copy view into the screen texture
GL_ActiveTexture(0);
// now scale it down to the bloom texture size
CHECKGLERROR
- qglViewport(r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
+ qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
GL_BlendFunc(GL_ONE, GL_ZERO);
- GL_Color(1, 1, 1, 1);
+ GL_Color(colorscale, colorscale, colorscale, 1);
// TODO: optimize with multitexture or GLSL
R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
+ r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
- if (darken)
- {
- // raise to a power of itself to darken it (this leaves the really
- // bright stuff bright, and everything else becomes very dark)
- // render multiple times with a multiply blendfunc to raise to a power
- GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
- for (x = 1;x < r_bloom_power.integer;x++)
- {
- R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
- }
- }
+ // we now have a bloom image in the framebuffer
+ // copy it into the bloom image texture for later processing
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+}
- // we now have a darkened bloom image in the framebuffer
- // copy it into the bloom image texture for more processing
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[2]);
+void R_Bloom_CopyHDRTexture(void)
+{
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
GL_ActiveTexture(0);
CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
+}
- // blend on at multiple vertical offsets to achieve a vertical blur
- // TODO: do offset blends using GLSL
- range = r_bloom_blur.integer * bloomwidth / 320;
- GL_BlendFunc(GL_ONE, GL_ZERO);
- for (x = -range;x <= range;x++)
- {
- xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
- yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
- // compute a texcoord array with the specified x and y offset
- texcoord2f[2][0] = xoffset+0;
- texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][5] = yoffset+0;
- texcoord2f[2][6] = xoffset+0;
- texcoord2f[2][7] = yoffset+0;
- // this r value looks like a 'dot' particle, fading sharply to
- // black at the edges
- // (probably not realistic but looks good enough)
- r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
- if (r < 0.01f)
- continue;
- GL_Color(r, r, r, 1);
- R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
- GL_BlendFunc(GL_ONE, GL_ONE);
- }
+void R_Bloom_MakeTexture(void)
+{
+ int x, range, dir;
+ float xoffset, yoffset, r, brighten;
- // copy the vertically blurred bloom view to a texture
- GL_ActiveTexture(0);
+ r_refdef.stats.bloom++;
+
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f);
+ R_Mesh_ColorPointer(NULL);
+
+ // we have a bloom image in the framebuffer
CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+ qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
- // blend the vertically blurred image at multiple offsets horizontally
- // to finish the blur effect
- // TODO: do offset blends using GLSL
- range = r_bloom_blur.integer * bloomwidth / 320;
- GL_BlendFunc(GL_ONE, GL_ZERO);
- for (x = -range;x <= range;x++)
- {
- xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
- yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
- // compute a texcoord array with the specified x and y offset
- texcoord2f[2][0] = xoffset+0;
- texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
- texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
- texcoord2f[2][5] = yoffset+0;
- texcoord2f[2][6] = xoffset+0;
- texcoord2f[2][7] = yoffset+0;
- // this r value looks like a 'dot' particle, fading sharply to
- // black at the edges
- // (probably not realistic but looks good enough)
- r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
- if (r < 0.01f)
- continue;
+ for (x = 1;x < r_bloom_colorexponent.value;)
+ {
+ x *= 2;
+ r = bound(0, r_bloom_colorexponent.value / x, 1);
+ GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
GL_Color(r, r, r, 1);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
R_Mesh_Draw(0, 4, 2, polygonelements);
- r_refdef.stats.bloom_drawpixels += bloomwidth * bloomheight;
- GL_BlendFunc(GL_ONE, GL_ONE);
+ r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+
+ // copy the vertically blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
}
- // copy the blurred bloom view to a texture
- GL_ActiveTexture(0);
- CHECKGLERROR
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + bloomheight), bloomwidth, bloomheight);CHECKGLERROR
- r_refdef.stats.bloom_copypixels += bloomwidth * bloomheight;
+ range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
+ brighten = r_bloom_brighten.value;
+ if (r_hdr.integer)
+ brighten *= r_hdr_range.value;
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f);
+
+ for (dir = 0;dir < 2;dir++)
+ {
+ // blend on at multiple vertical offsets to achieve a vertical blur
+ // TODO: do offset blends using GLSL
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ if (!dir){xoffset = 0;yoffset = x;}
+ else {xoffset = x;yoffset = 0;}
+ xoffset /= (float)r_bloomstate.bloomtexturewidth;
+ yoffset /= (float)r_bloomstate.bloomtextureheight;
+ // compute a texcoord array with the specified x and y offset
+ r_bloomstate.offsettexcoord2f[0] = xoffset+0;
+ r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+ r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+ r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
+ r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
+ r_bloomstate.offsettexcoord2f[5] = yoffset+0;
+ r_bloomstate.offsettexcoord2f[6] = xoffset+0;
+ r_bloomstate.offsettexcoord2f[7] = yoffset+0;
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
+ //r = (dir ? 1.0f : brighten)/(range*2+1);
+ r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+
+ // copy the vertically blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+ }
+
+ // apply subtract last
+ // (just like it would be in a GLSL shader)
+ if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
+ {
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
+ R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
+ GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+ qglBlendEquationEXT(GL_FUNC_ADD_EXT);
+
+ // copy the darkened bloom view to a texture
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ GL_ActiveTexture(0);
+ CHECKGLERROR
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
+ r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
+ }
}
void R_HDR_RenderBloomTexture(void)
oldwidth = r_view.width;
oldheight = r_view.height;
- r_view.width = bound(1, r_bloom_resolution.integer, min(r_view.width, gl_max_texture_size));
- r_view.height = r_view.width * oldheight / oldwidth;
+ r_view.width = r_bloomstate.bloomwidth;
+ r_view.height = r_bloomstate.bloomheight;
// TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
- // FIXME: change global lightmapintensity and light intensity according to r_hdr_bloomintensity cvar
- // FIXME: change global lightmapintensity and light intensity according to r_hdr_scenebrightness cvar
// TODO: add exposure compensation features
+ // TODO: add fp16 framebuffer support
- r_view.colorscale = r_hdr_bloomintensity.value * r_hdr_scenebrightness.value;
+ r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
+ if (r_hdr.integer)
+ r_view.colorscale /= r_hdr_range.value;
R_RenderScene();
- R_ResetViewRendering();
+ R_ResetViewRendering2D();
- R_Bloom_MakeTexture(false);
+ R_Bloom_CopyHDRTexture();
+ R_Bloom_MakeTexture();
+
+ R_ResetViewRendering3D();
R_ClearScreen();
if (r_timereport_active)
R_TimeReport("clear");
+
// restore the view settings
r_view.width = oldwidth;
r_view.height = oldheight;
-
- // go back to full view area
- R_ResetViewRendering();
}
static void R_BlendView(void)
{
- int screenwidth, screenheight;
- int bloomwidth, bloomheight;
- qboolean dobloom;
- qboolean dohdr;
- qboolean doblend;
- float vertex3f[12];
- float texcoord2f[3][8];
-
- // set the (poorly named) screenwidth and screenheight variables to
- // a power of 2 at least as large as the screen, these will define the
- // size of the texture to allocate
- for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
- for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
-
- doblend = r_refdef.viewblend[3] >= 0.01f;
- dobloom = !r_hdr.integer && r_bloom.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
- dohdr = r_hdr.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
-
- if (!dobloom && !dohdr && !doblend)
- return;
-
- // vertex coordinates for a quad that covers the screen exactly
- vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
- vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
- vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
- vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
-
- // set bloomwidth and bloomheight to the bloom resolution that will be
- // used (often less than the screen resolution for faster rendering)
- bloomwidth = min(r_view.width, r_bloom_resolution.integer);
- bloomheight = min(r_view.height, bloomwidth * r_view.height / r_view.width);
- // set up a texcoord array for the full resolution screen image
- // (we have to keep this around to copy back during final render)
- texcoord2f[0][0] = 0;
- texcoord2f[0][1] = (float)r_view.height / (float)screenheight;
- texcoord2f[0][2] = (float)r_view.width / (float)screenwidth;
- texcoord2f[0][3] = (float)r_view.height / (float)screenheight;
- texcoord2f[0][4] = (float)r_view.width / (float)screenwidth;
- texcoord2f[0][5] = 0;
- texcoord2f[0][6] = 0;
- texcoord2f[0][7] = 0;
- // set up a texcoord array for the reduced resolution bloom image
- // (which will be additive blended over the screen image)
- texcoord2f[1][0] = 0;
- texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
- texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
- texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
- texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
- texcoord2f[1][5] = 0;
- texcoord2f[1][6] = 0;
- texcoord2f[1][7] = 0;
-
- if (dohdr)
+ if (r_bloomstate.enabled && r_bloomstate.hdr)
{
// render high dynamic range bloom effect
// the bloom texture was made earlier this render, so we just need to
// blend it onto the screen...
- R_ResetViewRendering();
- GL_DepthTest(false);
- R_Mesh_VertexPointer(vertex3f);
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f);
R_Mesh_ColorPointer(NULL);
GL_Color(1, 1, 1, 1);
GL_BlendFunc(GL_ONE, GL_ONE);
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
R_Mesh_Draw(0, 4, 2, polygonelements);
r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
}
- if (dobloom)
+ else if (r_bloomstate.enabled)
{
// render simple bloom effect
+ // copy the screen and shrink it and darken it for the bloom process
+ R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
// make the bloom texture
- R_Bloom_MakeTexture(true);
+ R_Bloom_MakeTexture();
// put the original screen image back in place and blend the bloom
// texture on it
- R_ResetViewRendering();
- GL_DepthTest(false);
- R_Mesh_VertexPointer(vertex3f);
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f);
R_Mesh_ColorPointer(NULL);
GL_Color(1, 1, 1, 1);
GL_BlendFunc(GL_ONE, GL_ZERO);
// do both in one pass if possible
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_screen));
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[0]);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
if (r_textureunits.integer >= 2 && gl_combine.integer)
{
R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
- R_Mesh_TexBind(1, R_GetTexture(r_bloom_texture_bloom));
- R_Mesh_TexCoordPointer(1, 2, texcoord2f[1]);
+ R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f);
}
else
{
r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
// now blend on the bloom texture
GL_BlendFunc(GL_ONE, GL_ONE);
- R_Mesh_TexBind(0, R_GetTexture(r_bloom_texture_bloom));
- R_Mesh_TexCoordPointer(0, 2, texcoord2f[1]);
+ R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
+ R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
}
R_Mesh_Draw(0, 4, 2, polygonelements);
r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
}
- if (doblend)
+ if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
{
// apply a color tint to the whole view
- R_ResetViewRendering();
- GL_DepthTest(false);
- R_Mesh_VertexPointer(vertex3f);
+ R_ResetViewRendering2D();
+ R_Mesh_VertexPointer(r_screenvertex3f);
R_Mesh_ColorPointer(NULL);
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
r_refdef.rtworld = r_shadow_realtime_world.integer;
r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
- r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
+ r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
r_refdef.rtdlightshadows = r_refdef.rtdlight && (r_refdef.rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
if (r_showsurfaces.integer)
if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
+ R_Shadow_UpdateWorldLightSelection();
+
CHECKGLERROR
- GL_ScissorTest(true);
- GL_DepthMask(true);
if (r_timereport_active)
R_TimeReport("setup");
if (r_timereport_active)
R_TimeReport("visibility");
- R_ResetViewRendering();
+ R_ResetViewRendering3D();
R_ClearScreen();
if (r_timereport_active)
R_TimeReport("clear");
+ R_Bloom_StartFrame();
+
// this produces a bloom texture to be used in R_BlendView() later
if (r_hdr.integer)
R_HDR_RenderBloomTexture();
}
extern void R_DrawLightningBeams (void);
-extern void VM_AddPolygonsToMeshQueue (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)
{
- DrawQ_Finish();
-
// don't let sound skip if going slow
if (r_refdef.extraupdate)
S_ExtraUpdate ();
- CHECKGLERROR
- if (gl_support_fragment_shader)
- {
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
- qglDepthFunc(GL_LEQUAL);CHECKGLERROR
- qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
- qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
-
- R_ResetViewRendering();
+ R_ResetViewRendering3D();
R_MeshQueue_BeginScene();
- if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
- GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
- else
- GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
-
- GL_SetupView_Orientation_FromEntity(&r_view.matrix);
-
- R_Shadow_UpdateWorldLightSelection();
-
R_SkyStartFrame();
Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
if (r_refdef.extraupdate)
S_ExtraUpdate ();
+ if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
+ {
+ R_DrawModelShadows();
+
+ R_ResetViewRendering3D();
+
+ // don't let sound skip if going slow
+ if (r_refdef.extraupdate)
+ S_ExtraUpdate ();
+ }
+
R_ShadowVolumeLighting(false);
if (r_timereport_active)
R_TimeReport("rtlights");
{
qglUseProgramObjectARB(0);CHECKGLERROR
}
- VM_AddPolygonsToMeshQueue();
+ VM_CL_AddPolygonsToMeshQueue();
+
+ if (cl_locs_show.integer)
+ {
+ R_DrawLocs();
+ if (r_timereport_active)
+ R_TimeReport("showlocs");
+ }
if (r_drawportals.integer)
{
if (r_refdef.extraupdate)
S_ExtraUpdate ();
- CHECKGLERROR
- if (gl_support_fragment_shader)
- {
- qglUseProgramObjectARB(0);CHECKGLERROR
- }
- qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
- qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
+ R_ResetViewRendering2D();
}
/*
GL_DepthMask(true);
}
GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
+ 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)
{
void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
{
- // FIXME: identify models using a better check than ent->model->brush.shadowmesh
- //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2;
+ model_t *model = ent->model;
// switch to an alternate material if this is a q1bsp animated material
{
texture_t *texture = t;
- model_t *model = ent->model;
int s = ent->skinnum;
if ((unsigned int)s >= (unsigned int)model->numskins)
s = 0;
// pick a new currentskinframe if the material is animated
if (t->numskinframes >= 2)
t->currentskinframe = t->skinframes + ((int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes);
+ if (t->backgroundnumskinframes >= 2)
+ t->backgroundcurrentskinframe = t->backgroundskinframes + ((int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes);
t->currentmaterialflags = t->basematerialflags;
t->currentalpha = ent->alpha;
- if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
+ if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
t->currentalpha *= r_wateralpha.value;
if (!(ent->flags & RENDER_LIGHT))
t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
if (ent->effects & EF_ADDITIVE)
- t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+ t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
else if (t->currentalpha < 1)
- t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+ t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ if (ent->effects & EF_DOUBLESIDED)
+ t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
if (ent->effects & EF_NODEPTHTEST)
- t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST;
+ t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW;
if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
t->currenttexmatrix = r_waterscrollmatrix;
else
t->currenttexmatrix = identitymatrix;
+ if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
t->glosstexture = r_texture_white;
- t->specularpower = 8;
+ 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;
t->specularscale = 0;
if (r_shadow_gloss.integer > 0)
{
- if (t->currentskinframe->gloss)
+ if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
{
if (r_shadow_glossintensity.value > 0)
{
- t->glosstexture = t->currentskinframe->gloss;
+ t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
+ t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
t->specularscale = r_shadow_glossintensity.value;
}
}
const entity_render_t *rsurface_entity;
const model_t *rsurface_model;
texture_t *rsurface_texture;
-rtexture_t *rsurface_lightmaptexture;
+qboolean rsurface_uselightmaptexture;
rsurfmode_t rsurface_mode;
-texture_t *rsurface_glsl_texture;
-qboolean rsurface_glsl_uselightmap;
+int rsurface_lightmode; // 0 = lightmap or fullbright, 1 = color array from q3bsp, 2 = vertex shaded model
void RSurf_CleanUp(void)
{
}
GL_AlphaTest(false);
rsurface_mode = RSURFMODE_NONE;
- rsurface_lightmaptexture = NULL;
+ rsurface_uselightmaptexture = false;
rsurface_texture = NULL;
- rsurface_glsl_texture = NULL;
- rsurface_glsl_uselightmap = false;
}
-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)
{
void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
- int texturesurfaceindex;
+ int i, j;
const msurface_t *surface = texturesurfacelist[0];
- int firstvertex = surface->num_firstvertex;
- int endvertex = surface->num_firstvertex + surface->num_vertices;
+ const msurface_t *surface2;
+ int firstvertex;
+ int endvertex;
+ int numvertices;
+ int numtriangles;
+ // TODO: lock all array ranges before render, rather than on each surface
if (texturenumsurfaces == 1)
{
GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
#define MAXBATCHTRIANGLES 4096
int batchtriangles = 0;
int batchelements[MAXBATCHTRIANGLES*3];
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ for (i = 0;i < texturenumsurfaces;i = j)
{
- surface = texturesurfacelist[texturesurfaceindex];
- if (surface->num_triangles >= 256 || (batchtriangles == 0 && texturesurfaceindex + 1 >= texturenumsurfaces))
+ surface = texturesurfacelist[i];
+ j = i + 1;
+ if (surface->num_triangles > MAXBATCHTRIANGLES)
{
R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
continue;
}
- if (batchtriangles + surface->num_triangles > MAXBATCHTRIANGLES)
+ memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
+ batchtriangles = surface->num_triangles;
+ firstvertex = surface->num_firstvertex;
+ endvertex = surface->num_firstvertex + surface->num_vertices;
+ for (;j < texturenumsurfaces;j++)
{
- R_Mesh_Draw(firstvertex, endvertex - firstvertex, batchtriangles, batchelements);
- batchtriangles = 0;
- firstvertex = surface->num_firstvertex;
- endvertex = surface->num_firstvertex + surface->num_vertices;
- }
- else
- {
- firstvertex = min(firstvertex, surface->num_firstvertex);
- endvertex = max(endvertex, surface->num_firstvertex + surface->num_vertices);
+ surface2 = texturesurfacelist[j];
+ if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+ break;
+ memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
+ batchtriangles += surface2->num_triangles;
+ firstvertex = min(firstvertex, surface2->num_firstvertex);
+ endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
}
- memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
- batchtriangles += surface->num_triangles;
+ surface2 = texturesurfacelist[j-1];
+ numvertices = endvertex - firstvertex;
+ R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
}
- if (batchtriangles)
- R_Mesh_Draw(firstvertex, endvertex - firstvertex, batchtriangles, batchelements);
}
else if (r_batchmode.integer == 1)
{
- int firsttriangle = 0;
- int endtriangle = -1;
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ for (i = 0;i < texturenumsurfaces;i = j)
{
- surface = texturesurfacelist[texturesurfaceindex];
- if (surface->num_firsttriangle != endtriangle)
+ surface = texturesurfacelist[i];
+ for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+ if (texturesurfacelist[j] != surface2)
+ break;
+ surface2 = texturesurfacelist[j-1];
+ numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
+ numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
+ GL_LockArrays(surface->num_firstvertex, numvertices);
+ R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+ }
+ else
+ {
+ for (i = 0;i < texturenumsurfaces;i++)
+ {
+ surface = texturesurfacelist[i];
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+ }
+}
+
+static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
+{
+ int i;
+ int j;
+ const msurface_t *surface = texturesurfacelist[0];
+ const msurface_t *surface2;
+ int firstvertex;
+ int endvertex;
+ int numvertices;
+ int numtriangles;
+ // TODO: lock all array ranges before render, rather than on each surface
+ if (texturenumsurfaces == 1)
+ {
+ R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+ if (deluxemaptexunit >= 0)
+ R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+ else if (r_batchmode.integer == 2)
+ {
+ #define MAXBATCHTRIANGLES 4096
+ int batchtriangles = 0;
+ int batchelements[MAXBATCHTRIANGLES*3];
+ for (i = 0;i < texturenumsurfaces;i = j)
+ {
+ surface = texturesurfacelist[i];
+ R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+ if (deluxemaptexunit >= 0)
+ R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+ j = i + 1;
+ if (surface->num_triangles > MAXBATCHTRIANGLES)
{
- if (endtriangle > firsttriangle)
- {
- GL_LockArrays(firstvertex, endvertex - firstvertex);
- R_Mesh_Draw(firstvertex, endvertex - firstvertex, endtriangle - firsttriangle, (rsurface_model->surfmesh.data_element3i + 3 * firsttriangle));
- }
- firstvertex = surface->num_firstvertex;
- endvertex = surface->num_firstvertex + surface->num_vertices;
- firsttriangle = surface->num_firsttriangle;
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ continue;
}
- else
+ memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
+ batchtriangles = surface->num_triangles;
+ firstvertex = surface->num_firstvertex;
+ endvertex = surface->num_firstvertex + surface->num_vertices;
+ for (;j < texturenumsurfaces;j++)
{
- firstvertex = min(firstvertex, surface->num_firstvertex);
- endvertex = max(endvertex, surface->num_firstvertex + surface->num_vertices);
+ surface2 = texturesurfacelist[j];
+ if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
+ break;
+ memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
+ batchtriangles += surface2->num_triangles;
+ firstvertex = min(firstvertex, surface2->num_firstvertex);
+ endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
}
- endtriangle = surface->num_firsttriangle + surface->num_triangles;
+ surface2 = texturesurfacelist[j-1];
+ numvertices = endvertex - firstvertex;
+ R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
}
- if (endtriangle > firsttriangle)
+ }
+ else if (r_batchmode.integer == 1)
+ {
+#if 0
+ Con_Printf("%s batch sizes ignoring lightmap:", rsurface_texture->name);
+ for (i = 0;i < texturenumsurfaces;i = j)
{
- GL_LockArrays(firstvertex, endvertex - firstvertex);
- R_Mesh_Draw(firstvertex, endvertex - firstvertex, endtriangle - firsttriangle, (rsurface_model->surfmesh.data_element3i + 3 * firsttriangle));
+ surface = texturesurfacelist[i];
+ for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+ if (texturesurfacelist[j] != surface2)
+ break;
+ Con_Printf(" %i", j - i);
}
+ Con_Printf("\n");
+ Con_Printf("%s batch sizes honoring lightmap:", rsurface_texture->name);
+#endif
+ for (i = 0;i < texturenumsurfaces;i = j)
+ {
+ surface = texturesurfacelist[i];
+ R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+ if (deluxemaptexunit >= 0)
+ R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
+ for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
+ if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
+ break;
+#if 0
+ Con_Printf(" %i", j - i);
+#endif
+ surface2 = texturesurfacelist[j-1];
+ numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
+ numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
+ GL_LockArrays(surface->num_firstvertex, numvertices);
+ R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+#if 0
+ Con_Printf("\n");
+#endif
}
else
{
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ for (i = 0;i < texturenumsurfaces;i++)
{
- surface = texturesurfacelist[texturesurfaceindex];
+ surface = texturesurfacelist[i];
+ R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
+ if (deluxemaptexunit >= 0)
+ R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
}
static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
+ int j;
int texturesurfaceindex;
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ if (r_showsurfaces.integer == 2)
{
- const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
- int k = (int)(((size_t)surface) / sizeof(msurface_t));
- GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 0.2f);
- GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
- R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (j = 0;j < surface->num_triangles;j++)
+ {
+ float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
+ GL_Color(f, f, f, 1);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface_model->surfmesh.data_element3i + 3 * (j + surface->num_firsttriangle)));
+ }
+ }
+ }
+ else
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ int k = (int)(((size_t)surface) / sizeof(msurface_t));
+ GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 1);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
}
}
-static void RSurf_DrawBatch_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, int lightmode, qboolean applycolor, qboolean applyfog)
+static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
int texturesurfaceindex;
int i;
float f;
float *v, *c, *c2;
- // TODO: optimize
- if (lightmode >= 2)
- {
- // model lighting
- vec3_t ambientcolor;
- vec3_t diffusecolor;
- vec3_t lightdir;
- VectorCopy(rsurface_entity->modellight_lightdir, lightdir);
- ambientcolor[0] = rsurface_entity->modellight_ambient[0] * r * 0.5f;
- ambientcolor[1] = rsurface_entity->modellight_ambient[1] * g * 0.5f;
- ambientcolor[2] = rsurface_entity->modellight_ambient[2] * b * 0.5f;
- diffusecolor[0] = rsurface_entity->modellight_diffuse[0] * r * 0.5f;
- diffusecolor[1] = rsurface_entity->modellight_diffuse[1] * g * 0.5f;
- diffusecolor[2] = rsurface_entity->modellight_diffuse[2] * b * 0.5f;
- if (VectorLength2(diffusecolor) > 0)
- {
- // generate color arrays for the surfaces in this list
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ if (rsurface_lightmapcolor4f)
+ {
+ // 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)
{
- const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
- int numverts = surface->num_vertices;
- v = rsurface_vertex3f + 3 * surface->num_firstvertex;
- c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
- c = rsurface_array_color4f + 4 * surface->num_firstvertex;
- // q3-style directional shading
- for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
- {
- if ((f = DotProduct(c2, lightdir)) > 0)
- VectorMA(ambientcolor, f, diffusecolor, c);
- else
- VectorCopy(ambientcolor, c);
- c[3] = a;
- }
+ f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+ c2[0] = c[0] * f;
+ c2[1] = c[1] * f;
+ c2[2] = c[2] * f;
+ c2[3] = c[3];
}
- r = 1;
- g = 1;
- b = 1;
- a = 1;
- applycolor = false;
- rsurface_lightmapcolor4f = rsurface_array_color4f;
}
- else
+ }
+ else
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
- r = ambientcolor[0];
- g = ambientcolor[1];
- b = ambientcolor[2];
- rsurface_lightmapcolor4f = NULL;
+ 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)
+ {
+ f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
+ c2[0] = f;
+ c2[1] = f;
+ c2[2] = f;
+ c2[3] = 1;
+ }
}
}
- else if (lightmode >= 1 || !rsurface_lightmaptexture)
+ rsurface_lightmapcolor4f = rsurface_array_color4f;
+}
+
+static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
+{
+ int texturesurfaceindex;
+ int i;
+ float *c, *c2;
+ if (!rsurface_lightmapcolor4f)
+ return;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
{
- if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
+ 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)
{
- // generate color arrays for the surfaces in this list
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ c2[0] = c[0] * r;
+ c2[1] = c[1] * g;
+ c2[2] = c[2] * b;
+ c2[3] = c[3] * a;
+ }
+ }
+ rsurface_lightmapcolor4f = rsurface_array_color4f;
+}
+
+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
+ rsurface_lightmapcolor4f = NULL;
+ 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);
+ GL_Color(r, g, b, a);
+ RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
+}
+
+static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+ // TODO: optimize applyfog && applycolor case
+ // just apply fog if necessary, and tint the fog color array if necessary
+ rsurface_lightmapcolor4f = NULL;
+ 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);
+ GL_Color(r, g, b, a);
+ RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+}
+
+static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
+{
+ int texturesurfaceindex;
+ int i;
+ float *c;
+ // TODO: optimize
+ if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
+ {
+ // generate color arrays for the surfaces in this list
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
{
- const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
- for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+ if (surface->lightmapinfo->samples)
{
- if (surface->lightmapinfo->samples)
+ const unsigned char *lm = surface->lightmapinfo->samples + (rsurface_model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
+ float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
+ VectorScale(lm, scale, c);
+ if (surface->lightmapinfo->styles[1] != 255)
{
- const unsigned char *lm = surface->lightmapinfo->samples + (rsurface_model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
- float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
- VectorScale(lm, scale, c);
- if (surface->lightmapinfo->styles[1] != 255)
+ int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
+ lm += size3;
+ scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+ VectorMA(c, scale, lm, c);
+ if (surface->lightmapinfo->styles[2] != 255)
{
- int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
lm += size3;
- scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+ scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
VectorMA(c, scale, lm, c);
- if (surface->lightmapinfo->styles[2] != 255)
+ if (surface->lightmapinfo->styles[3] != 255)
{
lm += size3;
- scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
+ scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
VectorMA(c, scale, lm, c);
- if (surface->lightmapinfo->styles[3] != 255)
- {
- lm += size3;
- scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
- VectorMA(c, scale, lm, c);
- }
}
}
}
- else
- VectorClear(c);
- c[3] = 1;
- }
- }
- rsurface_lightmapcolor4f = rsurface_array_color4f;
- }
- else
- rsurface_lightmapcolor4f = rsurface_model->surfmesh.data_lightmapcolor4f;
- }
- else
- {
- // just lightmap it
- rsurface_lightmapcolor4f = NULL;
- }
- if (applyfog)
- {
- if (rsurface_lightmapcolor4f)
- {
- // 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 = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
- c2[0] = c[0] * f;
- c2[1] = c[1] * f;
- c2[2] = c[2] * f;
- c2[3] = c[3];
- }
- }
- }
- else
- {
- 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)
- {
- f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
- c2[0] = f;
- c2[1] = f;
- c2[2] = f;
- c2[3] = 1;
}
+ else
+ VectorClear(c);
+ c[3] = 1;
}
}
rsurface_lightmapcolor4f = rsurface_array_color4f;
}
- if (applycolor && rsurface_lightmapcolor4f)
+ else
+ rsurface_lightmapcolor4f = rsurface_model->surfmesh.data_lightmapcolor4f;
+ 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);
+ GL_Color(r, g, b, a);
+ 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)
+{
+ int texturesurfaceindex;
+ int i;
+ float f;
+ float *v, *c, *c2;
+ vec3_t ambientcolor;
+ vec3_t diffusecolor;
+ vec3_t lightdir;
+ // TODO: optimize
+ // model lighting
+ VectorCopy(rsurface_entity->modellight_lightdir, lightdir);
+ ambientcolor[0] = rsurface_entity->modellight_ambient[0] * r * 0.5f;
+ ambientcolor[1] = rsurface_entity->modellight_ambient[1] * g * 0.5f;
+ ambientcolor[2] = rsurface_entity->modellight_ambient[2] * b * 0.5f;
+ diffusecolor[0] = rsurface_entity->modellight_diffuse[0] * r * 0.5f;
+ diffusecolor[1] = rsurface_entity->modellight_diffuse[1] * g * 0.5f;
+ diffusecolor[2] = rsurface_entity->modellight_diffuse[2] * b * 0.5f;
+ if (VectorLength2(diffusecolor) > 0)
{
+ // generate color arrays for the surfaces in this list
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)
+ int numverts = surface->num_vertices;
+ v = rsurface_vertex3f + 3 * surface->num_firstvertex;
+ c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
+ c = rsurface_array_color4f + 4 * surface->num_firstvertex;
+ // q3-style directional shading
+ for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
{
- c2[0] = c[0] * r;
- c2[1] = c[1] * g;
- c2[2] = c[2] * b;
- c2[3] = c[3] * a;
+ if ((f = DotProduct(c2, lightdir)) > 0)
+ VectorMA(ambientcolor, f, diffusecolor, c);
+ else
+ VectorCopy(ambientcolor, c);
+ c[3] = a;
}
}
+ r = 1;
+ g = 1;
+ b = 1;
+ a = 1;
+ applycolor = false;
rsurface_lightmapcolor4f = rsurface_array_color4f;
}
+ else
+ {
+ r = ambientcolor[0];
+ g = ambientcolor[1];
+ b = ambientcolor[2];
+ rsurface_lightmapcolor4f = NULL;
+ }
+ 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);
GL_Color(r, g, b, a);
RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
+ GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ 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;
// restore entity matrix
R_Mesh_Matrix(&rsurface_entity->matrix);
}
+ GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ 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
static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
- int lightmode;
- // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
- lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
if (rsurface_mode != RSURFMODE_GLSL)
{
rsurface_mode = RSURFMODE_GLSL;
- rsurface_glsl_texture = NULL;
- rsurface_glsl_uselightmap = false;
R_Mesh_ResetTextureState();
}
- if (rsurface_glsl_texture != rsurface_texture || rsurface_glsl_uselightmap != (rsurface_lightmaptexture != NULL))
- {
- rsurface_glsl_texture = rsurface_texture;
- rsurface_glsl_uselightmap = rsurface_lightmaptexture != NULL;
- 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);
- R_SetupSurfaceShader(vec3_origin, lightmode == 2);
- //permutation_deluxemapping = permutation_lightmapping = R_SetupSurfaceShader(vec3_origin, lightmode == 2, false);
- //if (r_glsl_deluxemapping.integer)
- // permutation_deluxemapping = R_SetupSurfaceShader(vec3_origin, lightmode == 2, true);
- R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
- R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f);
- GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
- }
+
+ R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2);
if (!r_glsl_permutation)
return;
- RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
+
+ if (rsurface_lightmode == 2)
+ RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
+ else
+ RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
+ R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
+ R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f);
+
if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
{
R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
R_Mesh_ColorPointer(NULL);
}
- else if (rsurface_lightmaptexture)
+ else if (rsurface_uselightmaptexture)
{
- R_Mesh_TexBind(7, R_GetTexture(rsurface_lightmaptexture));
+ R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
R_Mesh_ColorPointer(NULL);
R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f);
}
- RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+
+ if (rsurface_uselightmaptexture && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
+ RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
+ else
+ RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+ if (rsurface_texture->backgroundnumskinframes && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ {
+ }
}
static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
{
// OpenGL 1.3 path - anything not completely ancient
int texturesurfaceindex;
- int lightmode;
qboolean applycolor;
qboolean applyfog;
rmeshstate_t m;
int layerindex;
const texturelayer_t *layer;
- CHECKGLERROR
- // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
- lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
if (rsurface_mode != RSURFMODE_MULTIPASS)
rsurface_mode = RSURFMODE_MULTIPASS;
RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
{
case TEXTURELAYERTYPE_LITTEXTURE:
memset(&m, 0, sizeof(m));
- if (lightmode >= 1 || !rsurface_lightmaptexture)
- m.tex[0] = R_GetTexture(r_texture_white);
- else
- m.tex[0] = R_GetTexture(rsurface_lightmaptexture);
+ m.tex[0] = R_GetTexture(r_texture_white);
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
m.tex[1] = R_GetTexture(layer->texture);
m.texmatrix[1] = layer->texmatrix;
m.texrgbscale[1] = layertexrgbscale;
m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], lightmode, applycolor, applyfog);
+ if (rsurface_lightmode == 2)
+ RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+ else if (rsurface_uselightmaptexture)
+ RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
+ else
+ RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
break;
case TEXTURELAYERTYPE_TEXTURE:
memset(&m, 0, sizeof(m));
m.texrgbscale[0] = layertexrgbscale;
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], 0, applycolor, applyfog);
+ RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
break;
case TEXTURELAYERTYPE_FOG:
memset(&m, 0, sizeof(m));
{
// OpenGL 1.1 - crusty old voodoo path
int texturesurfaceindex;
- int lightmode;
qboolean applyfog;
rmeshstate_t m;
int layerindex;
const texturelayer_t *layer;
- CHECKGLERROR
- // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
- lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
if (rsurface_mode != RSURFMODE_MULTIPASS)
rsurface_mode = RSURFMODE_MULTIPASS;
RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
// two-pass lit texture with 2x rgbscale
// first the lightmap pass
memset(&m, 0, sizeof(m));
- if (lightmode >= 1 || !rsurface_lightmaptexture)
- m.tex[0] = R_GetTexture(r_texture_white);
- else
- m.tex[0] = R_GetTexture(rsurface_lightmaptexture);
+ m.tex[0] = R_GetTexture(r_texture_white);
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, lightmode, false, false);
+ if (rsurface_lightmode == 2)
+ RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
+ else if (rsurface_uselightmaptexture)
+ RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
+ else
+ RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
GL_LockArrays(0, 0);
// then apply the texture to it
GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
m.texmatrix[0] = layer->texmatrix;
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], 0, layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
+ RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
}
else
{
m.texmatrix[0] = layer->texmatrix;
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], lightmode == 2 ? 2 : 1, layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+ if (rsurface_lightmode == 2)
+ RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+ else
+ RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
}
break;
case TEXTURELAYERTYPE_TEXTURE:
m.texmatrix[0] = layer->texmatrix;
m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
R_Mesh_TextureState(&m);
- RSurf_DrawBatch_Lightmap(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], 0, layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
+ RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
break;
case TEXTURELAYERTYPE_FOG:
// singletexture fogging
r_shadow_rtlight = NULL;
r_refdef.stats.entities_surfaces += texturenumsurfaces;
CHECKGLERROR
- 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
if (r_showsurfaces.integer)
R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)
R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
else if (rsurface_texture->currentnumlayers)
{
+ GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ 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);
+ GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
+ // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
+ rsurface_lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
if (r_glsl.integer && gl_support_fragment_shader)
R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
else if (gl_combine.integer && r_textureunits.integer >= 2)
GL_LockArrays(0, 0);
}
-#define BATCHSIZE 256
static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- int surfacelistindex;
- int batchcount;
- texture_t *t;
- msurface_t *texturesurfacelist[BATCHSIZE];
+ 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);
- batchcount = 0;
- t = NULL;
- for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
- {
- msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
+ RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
- if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
+ for (i = 0;i < numsurfaces;i = j)
+ {
+ j = i + 1;
+ surface = rsurface_model->data_surfaces + surfacelist[i];
+ texture = surface->texture;
+ rsurface_texture = texture->currentframe;
+ rsurface_uselightmaptexture = surface->lightmaptexture != NULL;
+ // scan ahead until we find a different texture
+ endsurface = min(i + 1024, numsurfaces);
+ texturenumsurfaces = 0;
+ texturesurfacelist[texturenumsurfaces++] = surface;
+ for (;j < endsurface;j++)
{
- if (batchcount > 0)
- if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult
- R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
- batchcount = 0;
- t = surface->texture;
- rsurface_lightmaptexture = surface->lightmaptexture;
- R_UpdateTextureInfo(ent, t);
- rsurface_texture = t->currentframe;
+ surface = rsurface_model->data_surfaces + surfacelist[j];
+ if (texture != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
+ break;
+ texturesurfacelist[texturenumsurfaces++] = surface;
}
-
- texturesurfacelist[batchcount++] = surface;
+ // render the range of surfaces
+ R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
}
- if (batchcount > 0)
- if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) // transparent sky is too difficult
- R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
+
RSurf_CleanUp();
}
-void R_QueueTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist)
+void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask)
{
- int texturesurfaceindex;
+ int i, j;
vec3_t tempcenter, center;
- if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
+ texture_t *texture;
+ // break the surface list down into batches by texture and use of lightmapping
+ for (i = 0;i < numsurfaces;i = j)
{
- // drawing sky transparently would be too difficult
- if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY))
+ j = i + 1;
+ // 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))
{
- for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ // 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
+ const msurface_t *surface = surfacelist[i];
+ tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
+ tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
+ tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
+ Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
+ R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, rsurface_entity, surface - rsurface_model->data_surfaces, r_shadow_rtlight);
+ }
+ else
+ {
+ // 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);
+ }
+ }
+}
+
+float locboxvertex3f[6*4*3] =
+{
+ 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)
{
- const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
- tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
- tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
- tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
- Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
- R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, rsurface_entity, surface - rsurface_model->data_surfaces, r_shadow_rtlight);
+ 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
}
}
}
- else
- R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
+ rsurface_texture = NULL;
}
extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
-void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
+void R_DrawWorldSurfaces(qboolean skysurfaces)
{
- int i, j, f, flagsmask;
+ int i, j, endj, f, flagsmask;
int counttriangles = 0;
+ msurface_t *surface, **surfacechain;
texture_t *t;
- model_t *model = ent->model;
+ model_t *model = r_refdef.worldmodel;
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->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)
{
- msurface_t *surface, **surfacechain;
for (i = 0;i < model->brushq1.light_styles;i++)
{
if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
}
}
- R_UpdateAllTextureInfo(ent);
+ R_UpdateAllTextureInfo(r_refdef.worldentity);
flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
f = 0;
t = NULL;
- rsurface_lightmaptexture = NULL;
+ rsurface_uselightmaptexture = false;
rsurface_texture = NULL;
numsurfacelist = 0;
- if (ent == r_refdef.worldentity)
+ j = model->firstmodelsurface;
+ endj = j + model->nummodelsurfaces;
+ while (j < endj)
{
- msurface_t *surface;
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, 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++)
{
- if (!r_viewcache.world_surfacevisible[j])
- continue;
- if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
- {
- if (numsurfacelist)
- {
- R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
- numsurfacelist = 0;
- }
- t = surface->texture;
- rsurface_lightmaptexture = surface->lightmaptexture;
- rsurface_texture = t->currentframe;
- f = rsurface_texture->currentmaterialflags & flagsmask;
- }
- if (f && surface->num_triangles)
+ // process this surface
+ surface = model->data_surfaces + j;
+ // 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);
+ R_BuildLightMap(r_refdef.worldentity, surface);
// add face to draw list
surfacelist[numsurfacelist++] = surface;
counttriangles += surface->num_triangles;
if (numsurfacelist >= maxsurfacelist)
{
- R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
numsurfacelist = 0;
}
}
}
}
+ if (numsurfacelist)
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ r_refdef.stats.entities_triangles += counttriangles;
+ RSurf_CleanUp();
+
+ 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)
{
- msurface_t *surface;
- for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ for (i = 0;i < model->brushq1.light_styles;i++)
{
- if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
+ if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
{
- if (numsurfacelist)
- {
- R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
- numsurfacelist = 0;
- }
- t = surface->texture;
- rsurface_lightmaptexture = surface->lightmaptexture;
- rsurface_texture = t->currentframe;
- f = rsurface_texture->currentmaterialflags & flagsmask;
+ 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 (f && surface->num_triangles)
+ }
+ }
+
+ 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++)
+ {
+ // 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;
+ counttriangles += surface->num_triangles;
+ if (numsurfacelist >= maxsurfacelist)
{
- // 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_QueueTextureSurfaceList(numsurfacelist, surfacelist);
- numsurfacelist = 0;
- }
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
+ numsurfacelist = 0;
}
}
}
if (numsurfacelist)
- R_QueueTextureSurfaceList(numsurfacelist, surfacelist);
+ R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
r_refdef.stats.entities_triangles += counttriangles;
RSurf_CleanUp();
- if (r_showcollisionbrushes.integer && model->brush.num_brushes && !skysurfaces)
- {
- int i;
- const msurface_t *surface;
- q3mbrush_t *brush;
- 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
- }
+ if (r_showcollisionbrushes.integer && !skysurfaces)
+ R_DrawCollisionBrushes(ent);
if (r_showtris.integer || r_shownormals.integer)
- {
- int k, l;
- msurface_t *surface;
- const int *elements;
- vec3_t v;
- CHECKGLERROR
- GL_DepthTest(true);
- GL_DepthMask(true);
- if (r_showdisabledepthtest.integer)
- {
- qglDepthFunc(GL_ALWAYS);CHECKGLERROR
- }
- 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 (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
- }
- }
- }
- rsurface_texture = NULL;
- if (r_showdisabledepthtest.integer)
- {
- qglDepthFunc(GL_LEQUAL);CHECKGLERROR
- }
- }
+ R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);
}