X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=3ad23498fb0dfa84d5c67573614109a46b68a0d4;hb=9e10334c3d85c0ff3630fe015f40b5c5a227668a;hp=8de08afd56826e6e915c1e40cf838cc101cd04dd;hpb=bc7a1ad5e8d89168a23166038ea2c5e3c5fb9604;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 8de08afd..3ad23498 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -28,6 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. mempool_t *r_main_mempool; rtexturepool_t *r_main_texturepool; +static int r_frame = 0; // used only by R_GetCurrentTexture + // // screen size info // @@ -96,7 +98,7 @@ cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier" cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"}; cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"}; -cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"}; +cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites"}; cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"}; cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"}; cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"}; @@ -168,6 +170,10 @@ rtexture_t *r_texture_gammaramps; unsigned int r_texture_gammaramps_serial; //rtexture_t *r_texture_fogintensity; +unsigned int r_queries[R_MAX_OCCLUSION_QUERIES]; +unsigned int r_numqueries; +unsigned int r_maxqueries; + char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH]; skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD]; @@ -478,12 +484,12 @@ static const char *builtinshaderstring = "uniform vec3 Gamma;\n" "#endif\n" "//uncomment these if you want to use them:\n" -"// uniform vec4 UserVec1;\n" +"uniform vec4 UserVec1;\n" "// uniform vec4 UserVec2;\n" "// uniform vec4 UserVec3;\n" "// uniform vec4 UserVec4;\n" "// uniform float ClientTime;\n" -"// uniform vec2 PixelSize;\n" +"uniform vec2 PixelSize;\n" "void main(void)\n" "{\n" " gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n" @@ -495,7 +501,14 @@ static const char *builtinshaderstring = "#endif\n" "\n" "#ifdef USEPOSTPROCESSING\n" -"// add your own postprocessing here or make your own ifdef for it\n" +"// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n" +"// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107, 0.707107)) * UserVec1.y;\n" +" gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990, 0.891007)) * UserVec1.y;\n" +" gl_FragColor /= (1 + 5 * UserVec1.y);\n" "#endif\n" "\n" "#ifdef USEGAMMARAMPS\n" @@ -1236,13 +1249,13 @@ static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice) } else if (!strcmp(filename, "glsl/default.glsl")) { - shaderstring = Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1); + shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1); memcpy(shaderstring, builtinshaderstring, strlen(builtinshaderstring) + 1); } return shaderstring; } -static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t permutation) +static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutation) { int i; shadermodeinfo_t *modeinfo = shadermodeinfo + mode; @@ -1413,8 +1426,8 @@ static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t per void R_GLSL_Restart_f(void) { - shadermode_t mode; - shaderpermutation_t permutation; + unsigned int mode; + unsigned int permutation; for (mode = 0;mode < SHADERMODE_COUNT;mode++) for (permutation = 0;permutation < SHADERPERMUTATION_LIMIT;permutation++) if (r_glsl_permutations[mode][permutation].program) @@ -1446,7 +1459,7 @@ void R_GLSL_DumpShader_f(void) Con_Printf("glsl/default.glsl written\n"); } -void R_SetupShader_SetPermutation(shadermode_t mode, unsigned int permutation) +void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation) { r_glsl_permutation_t *perm = &r_glsl_permutations[mode][permutation]; if (r_glsl_permutation != perm) @@ -1545,7 +1558,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f // minimum features necessary to avoid wasting rendering time in the // fragment shader on features that are not being used unsigned int permutation = 0; - shadermode_t mode = 0; + unsigned int mode = 0; // TODO: implement geometry-shader based shadow volumes someday if (r_glsl_offsetmapping.integer) { @@ -1727,7 +1740,7 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale); } if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]); - if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value); + if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value); // additive passes are only darkened by fog, not tinted if (r_glsl_permutation->loc_FogColor >= 0) { @@ -1787,13 +1800,14 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f #define SKINFRAME_HASH 1024 -struct +typedef struct { int loadsequence; // incremented each level change memexpandablearray_t array; skinframe_t *hash[SKINFRAME_HASH]; } -r_skinframe; +r_skinframe_t; +r_skinframe_t r_skinframe; void R_SkinFrame_PrepareForPurge(void) { @@ -1905,6 +1919,41 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid return item; } +#define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \ + { \ + unsigned long long avgcolor[5], wsum; \ + int pix, comp, w; \ + avgcolor[0] = 0; \ + avgcolor[1] = 0; \ + avgcolor[2] = 0; \ + avgcolor[3] = 0; \ + avgcolor[4] = 0; \ + wsum = 0; \ + for(pix = 0; pix < cnt; ++pix) \ + { \ + w = 0; \ + for(comp = 0; comp < 3; ++comp) \ + w += getpixel; \ + if(w) /* ignore perfectly black pixels because that is better for model skins */ \ + { \ + ++wsum; \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + w = getpixel; \ + for(comp = 0; comp < 3; ++comp) \ + avgcolor[comp] += getpixel * w; \ + avgcolor[3] += w; \ + } \ + /* comp = 3; -- not needed, comp is always 3 when we get here */ \ + avgcolor[4] += getpixel; \ + } \ + if(avgcolor[3] == 0) /* no pixels seen? even worse */ \ + avgcolor[3] = 1; \ + skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \ + skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \ + } + skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha) { // FIXME: it should be possible to disable loading various layers using @@ -1921,7 +1970,6 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl int basepixels_width; int basepixels_height; skinframe_t *skinframe; - double avgcolor[5], w, wsum; *has_alpha = false; @@ -1981,34 +2029,8 @@ skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int texturefl } } - avgcolor[0] = 0; - avgcolor[1] = 0; - avgcolor[2] = 0; - avgcolor[3] = 0; - avgcolor[4] = 0; - wsum = 0; - for(j = 0; j < basepixels_width * basepixels_height * 4; j += 4) - { - w = (int)basepixels[j + 0] + (int)basepixels[j + 1] + (int)basepixels[j + 2]; // use this weight, so black pixels don't contribute (needed for model skins) - avgcolor[2] += basepixels[j + 0] * w; - avgcolor[1] += basepixels[j + 1] * w; - avgcolor[0] += basepixels[j + 2] * w; - avgcolor[3] += basepixels[j + 3] * w; - avgcolor[4] += basepixels[j + 3]; - wsum += w; - } - if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck... - avgcolor[3] = 255.0 * wsum; - if(avgcolor[3] == 0) // no pixels seen? even worse - avgcolor[3] = 1; - avgcolor[0] /= avgcolor[3]; - avgcolor[1] /= avgcolor[3]; - avgcolor[2] /= avgcolor[3]; - avgcolor[3] /= 255.0 * wsum; // to 0..1 range - skinframe->avgcolor[0] = avgcolor[0]; - skinframe->avgcolor[1] = avgcolor[1]; - skinframe->avgcolor[2] = avgcolor[2]; - skinframe->avgcolor[3] = avgcolor[4] / (basepixels_width * 255.0 * basepixels_height); + R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); // _norm is the name used by tenebrae and has been adopted as standard if (loadnormalmap) @@ -2075,8 +2097,6 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co int i; unsigned char *temp1, *temp2; skinframe_t *skinframe; - double avgcolor[5], w, wsum; - int j; if (cls.state == ca_dedicated) return NULL; @@ -2128,34 +2148,8 @@ skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, co } } - avgcolor[0] = 0; - avgcolor[1] = 0; - avgcolor[2] = 0; - avgcolor[3] = 0; - avgcolor[4] = 0; - wsum = 0; - for(j = 0; j < width * height * 4; j += 4) - { - w = (int)skindata[j + 0] + (int)skindata[j + 1] + (int)skindata[j + 2]; - avgcolor[2] += skindata[j + 0] * w; - avgcolor[1] += skindata[j + 1] * w; - avgcolor[0] += skindata[j + 2] * w; - avgcolor[3] += skindata[j + 3] * w; - avgcolor[4] += skindata[j + 3]; - wsum += w; - } - if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck... - avgcolor[3] = 255.0 * wsum; - if(avgcolor[3] == 0) // no pixels seen? even worse - avgcolor[3] = 1; - avgcolor[0] /= avgcolor[3]; - avgcolor[1] /= avgcolor[3]; - avgcolor[2] /= avgcolor[3]; - avgcolor[3] /= 255.0 * wsum; // to 0..1 range - skinframe->avgcolor[0] = avgcolor[0]; - skinframe->avgcolor[1] = avgcolor[1]; - skinframe->avgcolor[2] = avgcolor[2]; - skinframe->avgcolor[3] = avgcolor[4] / (width * 255.0 * height); + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); return skinframe; } @@ -2164,9 +2158,8 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i { int i; unsigned char *temp1, *temp2; + unsigned int *palette; skinframe_t *skinframe; - double avgcolor[5], w, wsum; - int j; if (cls.state == ca_dedicated) return NULL; @@ -2176,6 +2169,8 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i if (skinframe && skinframe->base) return skinframe; + palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)); + skinframe->stain = NULL; skinframe->merged = NULL; skinframe->base = r_texture_notexture; @@ -2204,7 +2199,7 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i Mem_Free(temp1); } // use either a custom palette, or the quake palette - skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete)), skinframe->textureflags, true); // all + skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all if (loadglowtexture) skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow if (loadpantsandshirt) @@ -2223,35 +2218,8 @@ skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, i skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask } - avgcolor[0] = 0; - avgcolor[1] = 0; - avgcolor[2] = 0; - avgcolor[3] = 0; - avgcolor[4] = 0; - wsum = 0; - for(j = 0; j < width * height; ++j) - { - temp1 = ((unsigned char *)palette_bgra_alpha) + (skindata[j]*4); - w = (int)temp1[0] + (int)temp1[1] + (int)temp1[2]; - avgcolor[2] += temp1[0] * w; - avgcolor[1] += temp1[1] * w; - avgcolor[0] += temp1[2] * w; - avgcolor[3] += temp1[3] * w; - avgcolor[4] += temp1[3]; - wsum += w; - } - if(avgcolor[3] == 0) // just fully transparent pixels seen? bad luck... - avgcolor[3] = 255.0 * wsum; - if(avgcolor[3] == 0) // no pixels seen? even worse - avgcolor[3] = 1; - avgcolor[0] /= avgcolor[3]; - avgcolor[1] /= avgcolor[3]; - avgcolor[2] /= avgcolor[3]; - avgcolor[3] /= 255.0 * wsum; // to 0..1 range - skinframe->avgcolor[0] = avgcolor[0]; - skinframe->avgcolor[1] = avgcolor[1]; - skinframe->avgcolor[2] = avgcolor[2]; - skinframe->avgcolor[3] = avgcolor[4] / (width * 255.0 * height); + R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]); + //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]); return skinframe; } @@ -2263,7 +2231,7 @@ skinframe_t *R_SkinFrame_LoadMissing(void) if (cls.state == ca_dedicated) return NULL; - skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true); + skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE | TEXF_FORCENEAREST, 0, 0, 0, true); skinframe->stain = NULL; skinframe->merged = NULL; skinframe->base = r_texture_notexture; @@ -2284,6 +2252,10 @@ skinframe_t *R_SkinFrame_LoadMissing(void) void gl_main_start(void) { + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + memset(r_qwskincache, 0, sizeof(r_qwskincache)); memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); @@ -2313,6 +2285,13 @@ void gl_main_start(void) void gl_main_shutdown(void) { + if (r_maxqueries) + qglDeleteQueriesARB(r_maxqueries, r_queries); + + r_numqueries = 0; + r_maxqueries = 0; + memset(r_queries, 0, sizeof(r_queries)); + memset(r_qwskincache, 0, sizeof(r_qwskincache)); memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe)); @@ -2511,8 +2490,8 @@ void GL_Init (void) Con_Printf("GL_VENDOR: %s\n", gl_vendor); Con_Printf("GL_RENDERER: %s\n", gl_renderer); Con_Printf("GL_VERSION: %s\n", gl_version); - Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions); - Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); + Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions); + Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions); VID_CheckExtensions(); @@ -2624,6 +2603,51 @@ int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, c //================================================================================== +static void R_View_UpdateEntityLighting (void) +{ + int i; + entity_render_t *ent; + vec3_t tempdiffusenormal; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + ent = r_refdef.scene.entities[i]; + + // skip unseen models + if (!r_refdef.viewcache.entityvisible[i] && r_shadows.integer != 1) + continue; + + // skip bsp models + if (ent->model && ent->model->brush.num_leafs) + { + // TODO: use modellight for r_ambient settings on world? + VectorSet(ent->modellight_ambient, 0, 0, 0); + VectorSet(ent->modellight_diffuse, 0, 0, 0); + VectorSet(ent->modellight_lightdir, 0, 0, 1); + continue; + } + + // fetch the lighting from the worldmodel data + VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f)); + VectorClear(ent->modellight_diffuse); + VectorClear(tempdiffusenormal); + if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint) + { + vec3_t org; + Matrix4x4_OriginFromMatrix(&ent->matrix, org); + r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal); + } + 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); + if(VectorLength2(ent->modellight_lightdir) == 0) + VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here + VectorNormalize(ent->modellight_lightdir); + } +} + static void R_View_UpdateEntityVisible (void) { int i, renderimask; @@ -2930,6 +2954,7 @@ void R_View_Update(void) R_View_SetFrustum(); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); } void R_SetupView(qboolean allowwaterclippingplane) @@ -3012,7 +3037,8 @@ void R_ResetViewRendering3D(void) R_SetupGenericShader(true); } -void R_RenderScene(qboolean addwaterplanes); +void R_RenderScene(void); +void R_RenderWaterPlanes(void); static void R_Water_StartFrame(void) { @@ -3075,7 +3101,7 @@ static void R_Water_StartFrame(void) r_waterstate.numwaterplanes = 0; } -static void R_Water_AddWaterPlane(msurface_t *surface) +void R_Water_AddWaterPlane(msurface_t *surface) { int triangleindex, planeindex; const int *e; @@ -3084,6 +3110,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) vec3_t center; mplane_t plane; r_waterstate_waterplane_t *p; + texture_t *t = R_GetCurrentTexture(surface->texture); // just use the first triangle with a valid normal for any decisions VectorClear(normal); for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3) @@ -3103,7 +3130,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) if (PlaneDiff(r_refdef.view.origin, &plane) < 0) { // skip backfaces (except if nocullface is set) - if (!(surface->texture->currentframe->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) + if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE)) return; VectorNegate(plane.normal, plane.normal); plane.dist *= -1; @@ -3129,7 +3156,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) p->pvsvalid = false; } // merge this surface's materialflags into the waterplane - p->materialflags |= surface->texture->currentframe->currentmaterialflags; + p->materialflags |= t->currentmaterialflags; // merge this surface's PVS into the waterplane VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center); if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS @@ -3143,6 +3170,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) static void R_Water_ProcessPlanes(void) { r_refdef_view_t originalview; + r_refdef_view_t myview; int planeindex; r_waterstate_waterplane_t *p; @@ -3169,24 +3197,29 @@ static void R_Water_ProcessPlanes(void) } // render views + r_refdef.view = originalview; + r_refdef.view.showdebug = false; + r_refdef.view.width = r_waterstate.waterwidth; + r_refdef.view.height = r_waterstate.waterheight; + r_refdef.view.useclipplane = true; + myview = r_refdef.view; + r_waterstate.renderingscene = true; for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) { - r_refdef.view.showdebug = false; - r_refdef.view.width = r_waterstate.waterwidth; - r_refdef.view.height = r_waterstate.waterheight; - r_refdef.view.useclipplane = true; - r_waterstate.renderingscene = true; - // render the normal view scene and copy into texture // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { + r_refdef.view = myview; r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist; PlaneClassify(&r_refdef.view.clipplane); - R_RenderScene(false); + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); + R_RenderScene(); // copy view into the screen texture R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction)); @@ -3197,6 +3230,7 @@ static void R_Water_ProcessPlanes(void) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { + r_refdef.view = myview; // render reflected scene and copy into texture Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2); // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems) @@ -3216,26 +3250,20 @@ static void R_Water_ProcessPlanes(void) R_ResetViewRendering3D(); R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); - - R_RenderScene(false); + R_View_Update(); + R_RenderScene(); R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection)); GL_ActiveTexture(0); CHECKGLERROR qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR - - R_ResetViewRendering3D(); - R_ClearScreen(r_refdef.fogenabled); - if (r_timereport_active) - R_TimeReport("viewclear"); } - - r_refdef.view = originalview; - r_refdef.view.clear = true; - r_waterstate.renderingscene = false; } + r_waterstate.renderingscene = false; + r_refdef.view = originalview; + R_ResetViewRendering3D(); + R_ClearScreen(r_refdef.fogenabled); + R_View_Update(); return; error: r_refdef.view = originalview; @@ -3500,9 +3528,17 @@ void R_HDR_RenderBloomTexture(void) if (r_timereport_active) R_TimeReport("HDRclear"); + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + r_refdef.view.showdebug = true; + R_RenderScene(); + r_waterstate.numwaterplanes = 0; R_ResetViewRendering2D(); @@ -3669,8 +3705,6 @@ static void R_BlendView(void) } } -void R_RenderScene(qboolean addwaterplanes); - matrix4x4_t r_waterscrollmatrix; void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale! @@ -3792,7 +3826,7 @@ void R_UpdateVariables(void) // build GLSL gamma texture #define RAMPWIDTH 256 unsigned short ramp[RAMPWIDTH * 3]; - unsigned char ramprgb[RAMPWIDTH][4]; + unsigned char rampbgr[RAMPWIDTH][4]; int i; r_texture_gammaramps_serial = vid_gammatables_serial; @@ -3800,18 +3834,18 @@ void R_UpdateVariables(void) VID_BuildGammaTables(&ramp[0], RAMPWIDTH); for(i = 0; i < RAMPWIDTH; ++i) { - ramprgb[i][0] = ramp[i] >> 8; - ramprgb[i][1] = ramp[i + RAMPWIDTH] >> 8; - ramprgb[i][2] = ramp[i + 2 * RAMPWIDTH] >> 8; - ramprgb[i][3] = 0; + rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5); + rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5); + rampbgr[i][3] = 0; } if (r_texture_gammaramps) { - R_UpdateTexture(r_texture_gammaramps, &ramprgb[0][0], 0, 0, RAMPWIDTH, 1); + R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1); } else { - r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &ramprgb[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL); + r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL); } } } @@ -3860,6 +3894,9 @@ R_RenderView */ void R_RenderView(void) { + r_frame++; // used only by R_GetCurrentTexture + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity + if (r_refdef.view.isoverlay) { // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas] @@ -3871,7 +3908,7 @@ void R_RenderView(void) r_waterstate.enabled = false; r_waterstate.numwaterplanes = 0; - R_RenderScene(false); + R_RenderScene(); CHECKGLERROR return; @@ -3909,14 +3946,22 @@ void R_RenderView(void) } r_refdef.view.clear = true; - r_refdef.view.showdebug = true; - // this produces a bloom texture to be used in R_BlendView() later if (r_hdr.integer) R_HDR_RenderBloomTexture(); + r_refdef.view.showdebug = true; + + R_View_Update(); + if (r_timereport_active) + R_TimeReport("visibility"); + + r_waterstate.numwaterplanes = 0; + if (r_waterstate.enabled) + R_RenderWaterPlanes(); + + R_RenderScene(); r_waterstate.numwaterplanes = 0; - R_RenderScene(r_waterstate.enabled); R_BlendView(); if (r_timereport_active) @@ -3927,47 +3972,42 @@ void R_RenderView(void) CHECKGLERROR } -extern void R_DrawLightningBeams (void); -extern void VM_CL_AddPolygonsToMeshQueue (void); -extern void R_DrawPortals (void); -extern cvar_t cl_locs_show; -static void R_DrawLocs(void); -static void R_DrawEntityBBoxes(void); -void R_RenderScene(qboolean addwaterplanes) +void R_RenderWaterPlanes(void) { - r_refdef.stats.renders++; - - R_UpdateFogColor(); - - if (addwaterplanes) + if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) { - R_ResetViewRendering3D(); - - R_View_Update(); + r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); if (r_timereport_active) - R_TimeReport("watervis"); - - if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes) - { - r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity); - if (r_timereport_active) - R_TimeReport("waterworld"); - } + R_TimeReport("waterworld"); + } - // don't let sound skip if going slow - if (r_refdef.scene.extraupdate) - S_ExtraUpdate (); + // don't let sound skip if going slow + if (r_refdef.scene.extraupdate) + S_ExtraUpdate (); - R_DrawModelsAddWaterPlanes(); - if (r_timereport_active) - R_TimeReport("watermodels"); + R_DrawModelsAddWaterPlanes(); + if (r_timereport_active) + R_TimeReport("watermodels"); + if (r_waterstate.numwaterplanes) + { R_Water_ProcessPlanes(); if (r_timereport_active) R_TimeReport("waterscenes"); } +} - R_ResetViewRendering3D(); +extern void R_DrawLightningBeams (void); +extern void VM_CL_AddPolygonsToMeshQueue (void); +extern void R_DrawPortals (void); +extern cvar_t cl_locs_show; +static void R_DrawLocs(void); +static void R_DrawEntityBBoxes(void); +void R_RenderScene(void) +{ + r_refdef.stats.renders++; + + R_UpdateFogColor(); // don't let sound skip if going slow if (r_refdef.scene.extraupdate) @@ -3977,10 +4017,6 @@ void R_RenderScene(qboolean addwaterplanes) R_SkyStartFrame(); - R_View_Update(); - if (r_timereport_active) - R_TimeReport("visibility"); - Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0); if (cl.csqc_vidvars.drawworld) @@ -4104,7 +4140,7 @@ void R_RenderScene(qboolean addwaterplanes) R_SetupGenericShader(true); - if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value > 0 || r_showcollisionbrushes.value > 0)) + if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0)) { r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity); if (r_timereport_active) @@ -4381,6 +4417,7 @@ float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1}; void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, qboolean depthdisable, qboolean depthshort, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca) { + // NOTE: this must not call qglDepthFunc (see r_shadow.c, R_BeginCoronaQuery) thanks to ATI float fog = 1.0f; float vertex3f[12]; @@ -4390,14 +4427,6 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_ R_Mesh_Matrix(&identitymatrix); GL_BlendFunc(blendfunc1, blendfunc2); - if(v_flipped_state) - { - scalex1 = -scalex1; - scalex2 = -scalex2; - GL_CullFace(r_refdef.view.cullface_front); - } - else - GL_CullFace(r_refdef.view.cullface_back); GL_CullFace(GL_NONE); GL_DepthMask(false); @@ -4585,20 +4614,20 @@ static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms) return (float)(parms[0] + parms[1] * f); } -void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) +texture_t *R_GetCurrentTexture(texture_t *t) { int w, h, idx; int i; + const entity_render_t *ent = rsurface.entity; dp_model_t *model = ent->model; float f; float tcmat[12]; q3shaderinfo_layer_tcmod_t *tcmod; - if (t->basematerialflags & MATERIALFLAG_NODRAW) - { - t->currentmaterialflags = MATERIALFLAG_NODRAW; - return; - } + if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent) + return t->currentframe; + t->update_lastrenderframe = r_frame; + t->update_lastrenderentity = (void *)ent; // switch to an alternate material if this is a q1bsp animated material { @@ -4619,7 +4648,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { // use an alternate animation if the entity's frame is not 0, // and only if the texture has an alternate animation - if (ent->frame2 != 0 && t->anim_total[1]) + if (ent->framegroupblend[0].frame != 0 && t->anim_total[1]) t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[1]) : 0]; else t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[0]) : 0]; @@ -4639,12 +4668,12 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) } t->currentskinframe = r_qwskincache_skinframe[i]; if (t->currentskinframe == NULL) - t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes]; + t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes]; } else if (t->numskinframes >= 2) - t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes]; + t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes]; if (t->backgroundnumskinframes >= 2) - t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes]; + t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->shadertime)) % t->backgroundnumskinframes]; t->currentmaterialflags = t->basematerialflags; t->currentalpha = ent->alpha; @@ -4717,11 +4746,11 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0); break; case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures) - w = tcmod->parms[0]; - h = tcmod->parms[1]; + w = (int) tcmod->parms[0]; + h = (int) tcmod->parms[1]; f = r_refdef.scene.time / (tcmod->parms[2] * w * h); f = f - floor(f); - idx = floor(f * w * h); + idx = (int) floor(f * w * h); Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0); break; case Q3TCMOD_STRETCH: @@ -4878,14 +4907,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0] / r_refdef.view.colorscale, r_refdef.fogcolor[1] / r_refdef.view.colorscale, r_refdef.fogcolor[2] / r_refdef.view.colorscale, t->lightmapcolor[3]); } } -} -void R_UpdateAllTextureInfo(entity_render_t *ent) -{ - int i; - if (ent->model) - for (i = 0;i < ent->model->num_texturesperskin;i++) - R_UpdateTextureInfo(ent, ent->model->data_textures + i); + return t->currentframe; } rsurfacestate_t rsurface; @@ -4915,6 +4938,9 @@ void R_Mesh_ResizeArrays(int newvertices) void RSurf_ActiveWorldEntity(void) { dp_model_t *model = r_refdef.scene.worldmodel; + //if (rsurface.entity == r_refdef.scene.worldentity) + // return; + rsurface.entity = r_refdef.scene.worldentity; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = identitymatrix; @@ -4926,14 +4952,8 @@ void RSurf_ActiveWorldEntity(void) VectorSet(rsurface.modellight_lightdir, 0, 0, 1); VectorSet(rsurface.colormap_pantscolor, 0, 0, 0); VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0); - rsurface.frameblend[0].frame = 0; + memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend)); rsurface.frameblend[0].lerp = 1; - rsurface.frameblend[1].frame = 0; - rsurface.frameblend[1].lerp = 0; - rsurface.frameblend[2].frame = 0; - rsurface.frameblend[2].lerp = 0; - rsurface.frameblend[3].frame = 0; - rsurface.frameblend[3].lerp = 0; rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; rsurface.modelvertex3f = model->surfmesh.data_vertex3f; @@ -4984,6 +5004,9 @@ void RSurf_ActiveWorldEntity(void) void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents) { dp_model_t *model = ent->model; + //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents))) + // return; + rsurface.entity = (entity_render_t *)ent; if (rsurface.array_size < model->surfmesh.num_vertices) R_Mesh_ResizeArrays(model->surfmesh.num_vertices); rsurface.matrix = ent->matrix; @@ -5000,10 +5023,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir); VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor); VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor); - rsurface.frameblend[0] = ent->frameblend[0]; - rsurface.frameblend[1] = ent->frameblend[1]; - rsurface.frameblend[2] = ent->frameblend[2]; - rsurface.frameblend[3] = ent->frameblend[3]; + memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend)); rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; if (ent->model->brush.submodel) @@ -5011,7 +5031,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value; rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value; } - if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0)) + if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0)) { if (wanttangents) { @@ -5783,17 +5803,15 @@ static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenum { int texturesurfaceindex; int i; - float f; float *v, *c2; for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4) { - f = FogPoint_Model(v); - c2[0] = 1; - c2[1] = 1; - c2[2] = 1; + c2[0] = 0.5; + c2[1] = 0.5; + c2[2] = 0.5; c2[3] = 1; } } @@ -5905,9 +5923,9 @@ static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, msurface_t const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4) { - c2[0] = c[0] + r_refdef.scene.ambient / 64.0; - c2[1] = c[1] + r_refdef.scene.ambient / 64.0; - c2[2] = c[2] + r_refdef.scene.ambient / 64.0; + c2[0] = c[0] + r_refdef.scene.ambient / 128.0; + c2[1] = c[1] + r_refdef.scene.ambient / 128.0; + c2[2] = c[2] + r_refdef.scene.ambient / 128.0; c2[3] = c[3]; } } @@ -6512,9 +6530,9 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt) { - c[0] = rsurface.colormap_pantscolor[0] * 0.2 + rsurface.colormap_shirtcolor[0] * 0.3; - c[1] = rsurface.colormap_pantscolor[1] * 0.2 + rsurface.colormap_shirtcolor[1] * 0.3; - c[2] = rsurface.colormap_pantscolor[2] * 0.2 + rsurface.colormap_shirtcolor[2] * 0.3; + c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7); + c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7); + c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7); } // brighten it up (as texture value 127 means "unlit") @@ -6551,23 +6569,36 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf GL_DepthMask(writedepth); } - rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f; - rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject; - rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + rsurface.lightmapcolor4f = NULL; + + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + rsurface.lightmapcolor4f = NULL; + rsurface.lightmapcolor4f_bufferobject = 0; + rsurface.lightmapcolor4f_bufferoffset = 0; + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) { qboolean applycolor = true; float one = 1.0; RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist); + r_refdef.lightmapintensity = 1; RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor); r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all } else + { RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f; + rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject; + rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + } + if(!rsurface.lightmapcolor4f) RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist); @@ -6580,7 +6611,22 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurf RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } -static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) +{ + CHECKGLERROR + RSurf_SetupDepthAndCulling(); + if (r_showsurfaces.integer == 3) + R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + else if (r_glsl.integer && gl_support_fragment_shader) + R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth); + else if (gl_combine.integer && r_textureunits.integer >= 2) + R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth); + else + R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth); + CHECKGLERROR +} + +static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth) { CHECKGLERROR RSurf_SetupDepthAndCulling(); @@ -6618,8 +6664,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const j = i + 1; surface = rsurface.modelsurfaces + surfacelist[i]; texture = surface->texture; - R_UpdateTextureInfo(ent, texture); - rsurface.texture = texture->currentframe; + rsurface.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surface->lightmaptexture != NULL; // scan ahead until we find a different texture endsurface = min(i + 1024, numsurfaces); @@ -6633,13 +6678,18 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const texturesurfacelist[texturenumsurfaces++] = surface; } // render the range of surfaces - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + if (ent == r_refdef.scene.worldentity) + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); + else + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false); } + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity GL_AlphaTest(false); } -static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly) { + const entity_render_t *queueentity = r_refdef.scene.worldentity; CHECKGLERROR if (depthonly) { @@ -6701,23 +6751,113 @@ static void R_ProcessTextureSurfaceList(int texturenumsurfaces, msurface_t **tex else { // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); + R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); } CHECKGLERROR } -void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes) +void R_QueueWorldSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) { int i, j; texture_t *texture; - // if we're rendering water textures (extra scene renders), use a separate loop to avoid burdening the main one - if (addwaterplanes) + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) + { + 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 = R_GetCurrentTexture(texture); + rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) + { + // if this texture is not the kind we want, skip ahead to the next one + for (;j < numsurfaces && texture == surfacelist[j]->texture;j++) + ; + continue; + } + // 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_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly); + } +} + +static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity) +{ + CHECKGLERROR + if (depthonly) + { + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) + return; + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + return; + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && !r_refdef.view.showdebug) + { + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(0, 0, 0, 1); + GL_DepthTest(writedepth); + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + } + else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) { - for (i = 0;i < numsurfaces;i++) - if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) - R_Water_AddWaterPlane(surfacelist[i]); + RSurf_SetupDepthAndCulling(); + GL_AlphaTest(false); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + GL_DepthMask(true); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthTest(true); + RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) + R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); + else if (!rsurface.texture->currentnumlayers) return; + else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity) + { + // transparent surfaces get pushed off into the transparent queue + int surfacelistindex; + const msurface_t *surface; + vec3_t tempcenter, center; + for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++) + { + surface = texturesurfacelist[surfacelistindex]; + 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.matrix, tempcenter, center); + R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight); + } + } + else + { + // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier + R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)); } + CHECKGLERROR +} + +void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly) +{ + int i, j; + texture_t *texture; // break the surface list down into batches by texture and use of lightmapping for (i = 0;i < numsurfaces;i = j) { @@ -6727,7 +6867,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf // 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.texture = R_GetCurrentTexture(texture); rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) { @@ -6740,7 +6880,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) ; // render the range of surfaces - R_ProcessTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); + R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent); } } @@ -6881,7 +7021,7 @@ void R_DrawDebugModel(entity_render_t *ent) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; - rsurface.texture = surface->texture->currentframe; + rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { RSurf_PrepareVerticesForBatch(true, true, 1, &surface); @@ -6894,14 +7034,26 @@ void R_DrawDebugModel(entity_render_t *ent) else GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value); elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle); + R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0); + R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0); + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + //R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, ent->model->surfmesh.data_element3i, NULL, 0, 0); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); CHECKGLERROR + } + if (r_shownormals.value < 0) + { qglBegin(GL_LINES); - for (k = 0;k < surface->num_triangles;k++, elements += 3) + for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { -#define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2]) - GLVERTEXELEMENT(0);GLVERTEXELEMENT(1); - GLVERTEXELEMENT(1);GLVERTEXELEMENT(2); - GLVERTEXELEMENT(2);GLVERTEXELEMENT(0); + VectorCopy(rsurface.vertex3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, 0, 0, 1); + qglVertex3f(v[0], v[1], v[2]); + VectorMA(v, -r_shownormals.value, rsurface.svector3f + l * 3, v); + GL_Color(r_refdef.view.colorscale, 1, 1, 1); + qglVertex3f(v[0], v[1], v[2]); } qglEnd(); CHECKGLERROR @@ -6954,7 +7106,7 @@ void R_DrawDebugModel(entity_render_t *ent) extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); int r_maxsurfacelist = 0; msurface_t **r_surfacelist = NULL; -void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -6970,7 +7122,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep r_maxsurfacelist = model->num_surfaces; if (r_surfacelist) Mem_Free(r_surfacelist); - r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); } RSurf_ActiveWorldEntity(); @@ -6979,7 +7131,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep update = model->brushq1.lightmapupdateflags; // update light styles on this submodel - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -6994,8 +7146,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } } - R_UpdateAllTextureInfo(r_refdef.scene.worldentity); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { @@ -7010,33 +7161,26 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - if (update) + for (i = 0;i < model->nummodelsurfaces;i++) { - for (;j < endj;j++) - { + j = model->sortedmodelsurfaces[i]; + if (r_refdef.viewcache.world_surfacevisible[j]) + r_surfacelist[numsurfacelist++] = surfaces + j; + } + // update lightmaps if needed + if (update) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (r_refdef.viewcache.world_surfacevisible[j]) - { - r_surfacelist[numsurfacelist++] = surfaces + j; - // update lightmap if needed if (update[j]) R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j); - } - } - } - else - for (;j < endj;j++) - if (r_refdef.viewcache.world_surfacevisible[j]) - r_surfacelist[numsurfacelist++] = surfaces + j; // don't do anything if there were no surfaces if (!numsurfacelist) return; - R_QueueSurfaceList(r_refdef.scene.worldentity, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { r_refdef.stats.world_surfaces += numsurfacelist; for (j = 0;j < numsurfacelist;j++) @@ -7044,7 +7188,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } } -void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug) +void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug) { int i, j, endj, f, flagsmask; texture_t *t; @@ -7060,7 +7204,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr r_maxsurfacelist = model->num_surfaces; if (r_surfacelist) Mem_Free(r_surfacelist); - r_surfacelist = Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); + r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist)); } // if the model is static it doesn't matter what value we give for @@ -7077,7 +7221,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr update = model->brushq1.lightmapupdateflags; // update light styles - if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) + if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0) { model_brush_lightstyleinfo_t *style; for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) @@ -7092,8 +7236,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } } - R_UpdateAllTextureInfo(ent); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL); + flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) { @@ -7108,23 +7251,21 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr rsurface.rtlight = NULL; numsurfacelist = 0; // add visible surfaces to draw list - j = model->firstmodelsurface; - endj = j + model->nummodelsurfaces; - for (;j < endj;j++) - r_surfacelist[numsurfacelist++] = surfaces + j; + for (i = 0;i < model->nummodelsurfaces;i++) + r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i]; // don't do anything if there were no surfaces if (!numsurfacelist) return; // update lightmaps if needed if (update) - for (j = model->firstmodelsurface;j < endj;j++) + for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) if (update[j]) R_BuildLightMap(ent, surfaces + j); - R_QueueSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, addwaterplanes); + R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly); GL_AlphaTest(false); // add to stats if desired - if (r_speeds.integer && !skysurfaces && !depthonly && !addwaterplanes) + if (r_speeds.integer && !skysurfaces && !depthonly) { r_refdef.stats.entities++; r_refdef.stats.entities_surfaces += numsurfacelist;