X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=eb72ccb4b8fbe8b7c574599b55de9ab268dfec74;hb=7ef262a7368c32d0e0bf7eb8bf4bbf7c79338bff;hp=bcccfd44bf483be9956fe538711fd94693bc18c6;hpb=7bc9f2f55d1385f7019fbd6503522ac05b828124;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index bcccfd44..eb72ccb4 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -916,10 +916,10 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) // lightmapped wall shaderfilename = "glsl/default.glsl"; permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; - if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) + if (r_glsl_deluxemapping.integer >= 1 && rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) { // deluxemapping (light direction texture) - if (rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace) + 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; @@ -1212,7 +1212,7 @@ void GL_Init (void) 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 @@ -2010,7 +2010,7 @@ void R_UpdateVariables(void) 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) @@ -2107,7 +2107,7 @@ void R_RenderView(void) } extern void R_DrawLightningBeams (void); -extern void VM_AddPolygonsToMeshQueue (void); +extern void VM_CL_AddPolygonsToMeshQueue (void); extern void R_DrawPortals (void); void R_RenderScene(void) { @@ -2197,7 +2197,7 @@ void R_RenderScene(void) { qglUseProgramObjectARB(0);CHECKGLERROR } - VM_AddPolygonsToMeshQueue(); + VM_CL_AddPolygonsToMeshQueue(); if (r_drawportals.integer) { @@ -2587,9 +2587,6 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { model_t *model = ent->model; - // FIXME: identify models using a better check than ent->model->brush.shadowmesh - //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2; - // switch to an alternate material if this is a q1bsp animated material { texture_t *texture = t; @@ -2620,6 +2617,8 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) // 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; @@ -2639,19 +2638,24 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) 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->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; } } @@ -2807,10 +2811,9 @@ qboolean rsurface_generatedvertex; 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) { @@ -2821,10 +2824,8 @@ 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) @@ -2960,10 +2961,14 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta 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); @@ -2974,68 +2979,160 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacel #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) - { - R_Mesh_Draw(firstvertex, endvertex - firstvertex, batchtriangles, batchelements); - batchtriangles = 0; - firstvertex = surface->num_firstvertex; - endvertex = surface->num_firstvertex + surface->num_vertices; - } - 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 (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)); } @@ -3072,161 +3169,199 @@ static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **te } } -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); @@ -3307,83 +3442,63 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t 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)) - { - int lightmode; - rsurface_glsl_texture = rsurface_texture; - rsurface_glsl_uselightmap = rsurface_lightmaptexture != NULL && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT); - GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); - GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces - GL_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); - // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh - lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2; - 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); - RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); - R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f); - R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f); - R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f); - if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) - { - R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) - R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); - R_Mesh_ColorPointer(NULL); - } - else if (rsurface_lightmaptexture) - { - R_Mesh_TexBind(7, R_GetTexture(rsurface_lightmaptexture)); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) - R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture)); - R_Mesh_ColorPointer(NULL); - } - else - { - R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) - R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); - R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f); - } - } - else - RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); + + R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2); if (!r_glsl_permutation) return; - if (rsurface_glsl_uselightmap) + + 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(rsurface_lightmaptexture)); + R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) + R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); + R_Mesh_ColorPointer(NULL); + } + else if (rsurface_uselightmaptexture) + { + 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); + } + else + { + R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) + R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); + R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f); + } + + 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)) + { } - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } 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 - 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 - // 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); @@ -3426,17 +3541,19 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t { 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)); @@ -3445,7 +3562,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t 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)); @@ -3492,16 +3609,10 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t { // OpenGL 1.1 - crusty old voodoo path int texturesurfaceindex; - int lightmode; qboolean applyfog; rmeshstate_t m; int layerindex; const texturelayer_t *layer; - 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 - // 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); @@ -3529,13 +3640,15 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t // 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); @@ -3544,7 +3657,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t 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 { @@ -3554,7 +3667,10 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t 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: @@ -3564,7 +3680,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t 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 @@ -3622,6 +3738,14 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (rsurface_texture->currentnumlayers) { + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces + GL_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) @@ -3633,13 +3757,13 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur 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; + 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 @@ -3647,54 +3771,59 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const RSurf_ActiveEntity(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]; - 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]; + rsurface_texture = surface->texture; + 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 (rsurface_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 texturesurfaceindex; + int i, j; vec3_t tempcenter, center; - if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED) - { - // drawing sky transparently would be too difficult - if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)) + // break the surface list down into batches by texture and use of lightmapping + for (i = 0;i < numsurfaces;i = j) + { + j = i + 1; + rsurface_texture = surfacelist[i]->texture; + rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL; + 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 { - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - 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); - } + // simply scan ahead until we find a different texture + for (;j < numsurfaces && rsurface_texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++); + // render the range of surfaces + R_DrawTextureSurfaceList(j - i, surfacelist + i); } } - else - R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist); } extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); @@ -3741,7 +3870,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) 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) @@ -3758,21 +3887,8 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) { // process this surface surface = model->data_surfaces + j; - // if texture or lightmap has changed, start a new batch - 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 this surface fits the criteria, add it to the list - if (f && surface->num_triangles) + if (surface->texture->currentmaterialflags & flagsmask && surface->num_triangles) { // if lightmap parameters changed, rebuild lightmap texture if (surface->cached_dlight) @@ -3782,7 +3898,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) counttriangles += surface->num_triangles; if (numsurfacelist >= maxsurfacelist) { - R_QueueTextureSurfaceList(numsurfacelist, surfacelist); + R_QueueSurfaceList(numsurfacelist, surfacelist); numsurfacelist = 0; } } @@ -3795,21 +3911,8 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) endsurface = surface + model->nummodelsurfaces; for (;surface < endsurface;surface++) { - // if texture or lightmap has changed, start a new batch - 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 this surface fits the criteria, add it to the list - if (f && surface->num_triangles) + if (surface->texture->currentmaterialflags & flagsmask && surface->num_triangles) { // if lightmap parameters changed, rebuild lightmap texture if (surface->cached_dlight) @@ -3819,14 +3922,14 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) counttriangles += surface->num_triangles; if (numsurfacelist >= maxsurfacelist) { - R_QueueTextureSurfaceList(numsurfacelist, surfacelist); + R_QueueSurfaceList(numsurfacelist, surfacelist); numsurfacelist = 0; } } } } if (numsurfacelist) - R_QueueTextureSurfaceList(numsurfacelist, surfacelist); + R_QueueSurfaceList(numsurfacelist, surfacelist); r_refdef.stats.entities_triangles += counttriangles; RSurf_CleanUp();