+ {
+ firstvertex = min(firstvertex, surface->num_firstvertex);
+ endvertex = max(endvertex, surface->num_firstvertex + surface->num_vertices);
+ }
+ endtriangle = surface->num_firsttriangle + surface->num_triangles;
+ }
+ if (endtriangle > firsttriangle)
+ {
+ GL_LockArrays(firstvertex, endvertex - firstvertex);
+ R_Mesh_Draw(firstvertex, endvertex - firstvertex, endtriangle - firsttriangle, (rsurface_model->surfmesh.data_element3i + 3 * firsttriangle));
+ }
+ }
+ else
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+ }
+}
+
+static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ int j;
+ int texturesurfaceindex;
+ if (r_showsurfaces.integer == 2)
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (j = 0;j < surface->num_triangles;j++)
+ {
+ float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
+ GL_Color(f, f, f, 1);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface_model->surfmesh.data_element3i + 3 * (j + surface->num_firsttriangle)));
+ }
+ }
+ }
+ else
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ int k = (int)(((size_t)surface) / sizeof(msurface_t));
+ GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 1);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+ }
+ }
+}
+
+static void RSurf_DrawBatch_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, int lightmode, qboolean applycolor, qboolean applyfog)
+{
+ 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++)
+ {
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ else if (lightmode >= 1 || !rsurface_lightmaptexture)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ lm += size3;
+ scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (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;
+ }
+ }
+ }
+ rsurface_lightmapcolor4f = rsurface_array_color4f;
+ }
+ if (applycolor && rsurface_lightmapcolor4f)
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
+ for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
+ {
+ c2[0] = c[0] * r;
+ c2[1] = c[1] * g;
+ c2[2] = c[2] * b;
+ c2[3] = c[3] * a;
+ }
+ }
+ rsurface_lightmapcolor4f = rsurface_array_color4f;
+ }
+ R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
+ GL_Color(r, g, b, a);
+ RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+}
+
+static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ if (rsurface_mode != RSURFMODE_SHOWSURFACES)
+ {
+ rsurface_mode = RSURFMODE_SHOWSURFACES;
+ GL_DepthMask(true);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+ }
+ RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+ RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
+}
+
+static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ // transparent sky would be ridiculous
+ if ((rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ return;
+ if (rsurface_mode != RSURFMODE_SKY)
+ {
+ if (rsurface_mode == RSURFMODE_GLSL)
+ {
+ qglUseProgramObjectARB(0);CHECKGLERROR
+ }
+ rsurface_mode = RSURFMODE_SKY;
+ }
+ if (skyrendernow)
+ {
+ skyrendernow = false;
+ R_Sky();
+ // restore entity matrix
+ R_Mesh_Matrix(&rsurface_entity->matrix);
+ }
+ GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
+ GL_DepthMask(true);
+ // LordHavoc: HalfLife maps have freaky skypolys so don't use
+ // skymasking on them, and Quake3 never did sky masking (unlike
+ // software Quake and software Quake2), so disable the sky masking
+ // in Quake3 maps as it causes problems with q3map2 sky tricks,
+ // and skymasking also looks very bad when noclipping outside the
+ // level, so don't use it then either.
+ if (rsurface_model->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
+ {
+ GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
+ R_Mesh_ColorPointer(NULL);
+ R_Mesh_ResetTextureState();
+ if (skyrendermasked)
+ {
+ // depth-only (masking)
+ GL_ColorMask(0,0,0,0);
+ // just to make sure that braindead drivers don't draw
+ // anything despite that colormask...
+ GL_BlendFunc(GL_ZERO, GL_ONE);
+ }
+ else
+ {
+ // fog sky
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ }
+ RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
+ RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
+ if (skyrendermasked)
+ GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
+ }
+}
+
+static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
+{
+ 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);