cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
-cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
+cvar_t developer_texturelogging = {0, "developer_texturelogging", "0"};
+
+cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"};
rtexturepool_t *r_main_texturepool;
rtexture_t *r_bloom_texture_screen;
if (cl.worldmodel)
{
strlcpy(entname, cl.worldmodel->name, sizeof(entname));
- l = strlen(entname) - 4;
+ l = (int)strlen(entname) - 4;
if (l >= 0 && !strcmp(entname + l, ".bsp"))
{
strcpy(entname + l, ".ent");
Cvar_RegisterVariable(&r_bloom_resolution);
Cvar_RegisterVariable(&r_bloom_power);
Cvar_RegisterVariable(&developer_texturelogging);
+ Cvar_RegisterVariable(&gl_lightmaps);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
{
gl_backend_init();
R_Textures_Init();
- Mod_RenderInit();
R_MeshQueue_Init();
GL_Main_Init();
GL_Draw_Init();
UI_Init();
Sbar_Init();
R_LightningBeams_Init();
+ Mod_RenderInit();
}
/*
VID_CheckExtensions();
// LordHavoc: report supported extensions
- Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
+ Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions );
// clear to black (loading plaque will be seen over this)
qglClearColor(0,0,0,1);
// set the (poorly named) screenwidth and screenheight variables to
// a power of 2 at least as large as the screen, these will define the
// size of the texture to allocate
- for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
- for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+ for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
+ for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
// allocate textures as needed
if (!r_bloom_texture_screen)
r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
R_Mesh_State(&m);
// copy view into the full resolution screen image texture
GL_ActiveTexture(0);
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
c_bloomcopies++;
c_bloomcopypixels += r_view_width * r_view_height;
// now scale it down to the bloom size and raise to a power of itself
// to darken it (this leaves the really bright stuff bright, and
// everything else becomes very dark)
// TODO: optimize with multitexture or GLSL
- qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ qglViewport(r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_Color(1, 1, 1, 1);
R_Mesh_Draw(0, 4, 2, polygonelements);
m.pointer_texcoord[0] = varray_texcoord2f[2];
R_Mesh_State(&m);
GL_ActiveTexture(0);
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
c_bloomcopies++;
c_bloomcopypixels += bloomwidth * bloomheight;
// blend on at multiple vertical offsets to achieve a vertical blur
}
// copy the vertically blurred bloom view to a texture
GL_ActiveTexture(0);
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
c_bloomcopies++;
c_bloomcopypixels += bloomwidth * bloomheight;
// blend the vertically blurred image at multiple offsets horizontally
}
// copy the blurred bloom view to a texture
GL_ActiveTexture(0);
- qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
c_bloomcopies++;
c_bloomcopypixels += bloomwidth * bloomheight;
// go back to full view area
- qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
// put the original screen image back in place and blend the bloom
// texture on it
memset(&m, 0, sizeof(m));
void R_RenderScene(void);
+matrix4x4_t r_waterscrollmatrix;
+
/*
================
R_RenderView
if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
- r_view_width = bound(0, r_refdef.width, vid.realwidth);
- r_view_height = bound(0, r_refdef.height, vid.realheight);
+ r_view_width = bound(0, r_refdef.width, vid.width);
+ r_view_height = bound(0, r_refdef.height, vid.height);
r_view_depth = 1;
- r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
- r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
+ r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width);
+ r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height);
r_view_z = 0;
r_view_fov_x = bound(1, r_refdef.fov_x, 170);
r_view_fov_y = bound(1, r_refdef.fov_y, 170);
r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
// GL is weird because it's bottom to top, r_view_y is top to bottom
- qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
GL_ScissorTest(true);
GL_DepthMask(true);
R_BlendView();
R_TimeReport("blendview");
- GL_Scissor(0, 0, vid.realwidth, vid.realheight);
+ GL_Scissor(0, 0, vid.width, vid.height);
GL_ScissorTest(false);
}
GL_SetupView_Orientation_FromEntity(&r_view_matrix);
+ Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
+
R_SkyStartFrame();
R_WorldVisibility();
}
}
+void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
+{
+ texture_t *texture = t;
+ model_t *model = ent->model;
+ int s = ent->skinnum;
+ if ((unsigned int)s >= (unsigned int)model->numskins)
+ s = 0;
+ if (s >= 1)
+ c_models++;
+ if (model->skinscenes)
+ {
+ if (model->skinscenes[s].framecount > 1)
+ s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
+ else
+ s = model->skinscenes[s].firstframe;
+ }
+ if (s > 0)
+ t = t + s * model->num_surfaces;
+ if (t->animated)
+ t = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
+ texture->currentframe = t;
+ t->currentmaterialflags = t->basematerialflags;
+ t->currentalpha = ent->alpha;
+ if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
+ t->currentalpha *= r_wateralpha.value;
+ if (!(ent->flags & RENDER_LIGHT))
+ t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
+ if (ent->effects & EF_ADDITIVE)
+ t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
+ else if (t->currentalpha < 1)
+ t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+ if (ent->effects & EF_NODEPTHTEST)
+ t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST;
+}
+
+void R_UpdateAllTextureInfo(entity_render_t *ent)
+{
+ int i;
+ if (ent->model)
+ for (i = 0;i < ent->model->num_textures;i++)
+ R_UpdateTextureInfo(ent, ent->model->data_textures + i);
+}
+
+float *rsurface_vertex3f;
+float *rsurface_svector3f;
+float *rsurface_tvector3f;
+float *rsurface_normal3f;
+float *rsurface_lightmapcolor4f;
+
+void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg)
+{
+ int i, j;
+ float center[3], forward[3], right[3], up[3], v[4][3];
+ matrix4x4_t matrix1, imatrix1;
+ if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights))
+ {
+ rsurface_vertex3f = varray_vertex3f;
+ rsurface_svector3f = NULL;
+ rsurface_tvector3f = NULL;
+ rsurface_normal3f = NULL;
+ Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f);
+ }
+ else
+ {
+ rsurface_vertex3f = surface->groupmesh->data_vertex3f;
+ rsurface_svector3f = surface->groupmesh->data_svector3f;
+ rsurface_tvector3f = surface->groupmesh->data_tvector3f;
+ rsurface_normal3f = surface->groupmesh->data_normal3f;
+ }
+ if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
+ {
+ if (!rsurface_svector3f)
+ {
+ rsurface_svector3f = varray_svector3f;
+ rsurface_tvector3f = varray_tvector3f;
+ rsurface_normal3f = varray_normal3f;
+ Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f);
+ }
+ // a single autosprite surface can contain multiple sprites...
+ VectorClear(forward);
+ VectorClear(right);
+ VectorSet(up, 0, 0, 1);
+ for (j = 0;j < surface->num_vertices - 3;j += 4)
+ {
+ VectorClear(center);
+ for (i = 0;i < 4;i++)
+ VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
+ VectorScale(center, 0.25f, center);
+ // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
+ Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center);
+ Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
+ for (i = 0;i < 4;i++)
+ Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
+ forward[0] = modelorg[0] - center[0];
+ forward[1] = modelorg[1] - center[1];
+ VectorNormalize(forward);
+ right[0] = forward[1];
+ right[1] = -forward[0];
+ for (i = 0;i < 4;i++)
+ VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
+ }
+ rsurface_vertex3f = varray_vertex3f;
+ rsurface_svector3f = NULL;
+ rsurface_tvector3f = NULL;
+ rsurface_normal3f = NULL;
+ }
+ else if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE)
+ {
+ if (!rsurface_svector3f)
+ {
+ rsurface_svector3f = varray_svector3f;
+ rsurface_tvector3f = varray_tvector3f;
+ rsurface_normal3f = varray_normal3f;
+ Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f);
+ }
+ Matrix4x4_Transform(&ent->inversematrix, r_viewforward, forward);
+ Matrix4x4_Transform(&ent->inversematrix, r_viewright, right);
+ Matrix4x4_Transform(&ent->inversematrix, r_viewup, up);
+ // a single autosprite surface can contain multiple sprites...
+ for (j = 0;j < surface->num_vertices - 3;j += 4)
+ {
+ VectorClear(center);
+ for (i = 0;i < 4;i++)
+ VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
+ VectorScale(center, 0.25f, center);
+ // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
+ Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center);
+ Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
+ for (i = 0;i < 4;i++)
+ Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
+ for (i = 0;i < 4;i++)
+ VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
+ }
+ rsurface_vertex3f = varray_vertex3f;
+ rsurface_svector3f = NULL;
+ rsurface_tvector3f = NULL;
+ rsurface_normal3f = NULL;
+ }
+ R_Mesh_VertexPointer(rsurface_vertex3f);
+}
+
+void RSurf_SetColorPointer(const entity_render_t *ent, const msurface_t *surface, const vec3_t modelorg, float r, float g, float b, float a, qboolean lightmodel, qboolean vertexlight, qboolean applycolor, qboolean applyfog)
+{
+ int i;
+ float f;
+ float *v, *c, *c2;
+ vec3_t diff;
+ if (lightmodel)
+ {
+ vec4_t ambientcolor4f;
+ vec3_t diffusecolor;
+ vec3_t diffusenormal;
+ if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, r, g, b, a, false))
+ {
+ rsurface_lightmapcolor4f = varray_color4f;
+ if (rsurface_normal3f == NULL)
+ {
+ rsurface_normal3f = varray_normal3f;
+ Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f);
+ }
+ R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, surface->groupmesh->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, rsurface_lightmapcolor4f + 4 * surface->num_firstvertex);
+ r = 1;
+ g = 1;
+ b = 1;
+ a = 1;
+ applycolor = false;
+ }
+ else
+ {
+ r = ambientcolor4f[0];
+ g = ambientcolor4f[1];
+ b = ambientcolor4f[2];
+ a = ambientcolor4f[3];
+ rsurface_lightmapcolor4f = NULL;
+ }
+ }
+ else if (vertexlight)
+ {
+ if (surface->lightmapinfo)
+ {
+ rsurface_lightmapcolor4f = varray_color4f;
+ for (i = 0, c = rsurface_lightmapcolor4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
+ {
+ const qbyte *lm = surface->lightmapinfo->samples + (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i];
+ float scale = d_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 = d_lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
+ VectorMA(c, scale, lm, c);
+ if (surface->lightmapinfo->styles[2] != 255)
+ {
+ lm += size3;
+ scale = d_lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
+ VectorMA(c, scale, lm, c);
+ if (surface->lightmapinfo->styles[3] != 255)
+ {
+ lm += size3;
+ scale = d_lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
+ VectorMA(c, scale, lm, c);
+ }
+ }
+ }
+ }
+ }
+ else
+ rsurface_lightmapcolor4f = surface->groupmesh->data_lightmapcolor4f;
+ }
+ else
+ rsurface_lightmapcolor4f = NULL;
+ if (applyfog)
+ {
+ if (rsurface_lightmapcolor4f)
+ {
+ for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
+ {
+ VectorSubtract(v, modelorg, diff);
+ f = 1 - exp(fogdensity/DotProduct(diff, diff));
+ c2[0] = c[0] * f;
+ c2[1] = c[1] * f;
+ c2[2] = c[2] * f;
+ c2[3] = c[3];
+ }
+ }
+ else
+ {
+ for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
+ {
+ VectorSubtract(v, modelorg, diff);
+ f = 1 - exp(fogdensity/DotProduct(diff, diff));
+ c2[0] = f;
+ c2[1] = f;
+ c2[2] = f;
+ c2[3] = 1;
+ }
+ }
+ rsurface_lightmapcolor4f = varray_color4f;
+ }
+ if (applycolor && rsurface_lightmapcolor4f)
+ {
+ for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_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;
+ }
+ }
+ R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
+ GL_Color(r, g, b, a);
+}
+
+
+static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
+{
+ int i;
+ int texturesurfaceindex;
+ const float *v;
+ float *c;
+ float diff[3];
+ float colorpants[3], colorshirt[3];
+ float f, r, g, b, a, colorscale;
+ const msurface_t *surface;
+ qboolean dolightmap;
+ qboolean doambient;
+ qboolean dodetail;
+ qboolean doglow;
+ qboolean dofogpass;
+ qboolean fogallpasses;
+ qboolean waterscrolling;
+ qboolean dopants;
+ qboolean doshirt;
+ qboolean dofullbrightpants;
+ qboolean dofullbrightshirt;
+ qboolean applycolor;
+ qboolean lightmodel = false;
+ rtexture_t *basetexture;
+ rmeshstate_t m;
+ if (texture->currentmaterialflags & MATERIALFLAG_NODRAW)
+ return;
+ c_faces += texturenumsurfaces;
+ // FIXME: identify models using a better check than ent->model->shadowmesh
+ if (!(ent->effects & EF_FULLBRIGHT) && !ent->model->brush.shadowmesh)
+ lightmodel = true;
+ // gl_lightmaps debugging mode skips normal texturing
+ if (gl_lightmaps.integer)
+ {
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ qglDisable(GL_CULL_FACE);
+ GL_Color(1, 1, 1, 1);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State(&m);
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ RSurf_SetColorPointer(ent, surface, modelorg, 1, 1, 1, 1, lightmodel, !surface->lightmaptexture, false, false);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ qglEnable(GL_CULL_FACE);
+ return;
+ }
+ GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
+ GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
+ if (texture->currentmaterialflags & MATERIALFLAG_ADD)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ else
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ // water waterscrolling in texture matrix
+ waterscrolling = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0;
+ if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
+ qglDisable(GL_CULL_FACE);
+ if (texture->currentmaterialflags & MATERIALFLAG_SKY)
+ {
+ if (skyrendernow)
+ {
+ skyrendernow = false;
+ if (skyrendermasked)
+ R_Sky();
+ }
+ // LordHavoc: HalfLife maps have freaky skypolys...
+ //if (!ent->model->brush.ishlbsp)
+ {
+ R_Mesh_Matrix(&ent->matrix);
+ GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
+ 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);
+ }
+ GL_DepthMask(true);
+ GL_DepthTest(true);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State(&m);
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+ }
+ }
+ else if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value && gl_textureshader && !texture->skin.glow && !fogenabled && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
+ {
+ // NVIDIA Geforce3 distortion texture shader on water
+ float args[4] = {0.05f,0,0,0.04f};
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(r_texture_distorttexture[(int)(r_refdef.time * 16)&63]);
+ m.tex[1] = R_GetTexture(texture->skin.base);
+ m.texcombinergb[0] = GL_REPLACE;
+ m.texcombinergb[1] = GL_REPLACE;
+ Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
+ m.texmatrix[1] = r_waterscrollmatrix;
+ R_Mesh_State(&m);
+
+ GL_Color(1, 1, 1, texture->currentalpha);
+ GL_ActiveTexture(0);
+ qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
+ GL_ActiveTexture(1);
+ qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
+ qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
+ qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
+ qglEnable(GL_TEXTURE_SHADER_NV);
+
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+
+ qglDisable(GL_TEXTURE_SHADER_NV);
+ qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
+ GL_ActiveTexture(0);
+ }
+ else if (texture->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
+ {
+ // normal surface (wall or water)
+ dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
+ doambient = r_ambient.value >= (1/64.0f);
+ dodetail = r_detailtextures.integer && texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
+ doglow = texture->skin.glow != NULL;
+ dofogpass = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD);
+ fogallpasses = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
+ if (ent->colormap >= 0)
+ {
+ int b;
+ qbyte *bcolor;
+ basetexture = texture->skin.base;
+ dopants = texture->skin.pants != NULL;
+ doshirt = texture->skin.shirt != NULL;
+ // 128-224 are backwards ranges
+ b = (ent->colormap & 0xF) << 4;b += (b >= 128 && b < 224) ? 4 : 12;
+ dofullbrightpants = b >= 224;
+ bcolor = (qbyte *) (&palette_complete[b]);
+ VectorScale(bcolor, (1.0f / 255.0f), colorpants);
+ // 128-224 are backwards ranges
+ b = (ent->colormap & 0xF0);b += (b >= 128 && b < 224) ? 4 : 12;
+ dofullbrightshirt = b >= 224;
+ bcolor = (qbyte *) (&palette_complete[b]);
+ VectorScale(bcolor, (1.0f / 255.0f), colorshirt);
+ }
+ else
+ {
+ basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
+ dopants = false;
+ doshirt = false;
+ dofullbrightshirt = false;
+ dofullbrightpants = false;
+ }
+ if (dolightmap && r_textureunits.integer >= 2 && gl_combine.integer)
+ {
+ memset(&m, 0, sizeof(m));
+ m.tex[1] = R_GetTexture(basetexture);
+ if (waterscrolling)
+ m.texmatrix[1] = r_waterscrollmatrix;
+ m.texrgbscale[1] = 2;
+ m.pointer_color = varray_color4f;
+ R_Mesh_State(&m);
+ // transparent is not affected by r_lightmapintensity
+ if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ colorscale = r_lightmapintensity;
+ else
+ colorscale = 1;
+ r = ent->colormod[0] * colorscale;
+ g = ent->colormod[1] * colorscale;
+ b = ent->colormod[2] * colorscale;
+ a = texture->currentalpha;
+ // q3bsp has no lightmap updates, so the lightstylevalue that
+ // would normally be baked into the lightmaptexture must be
+ // applied to the color
+ if (ent->model->brushq3.data_lightmaps)
+ {
+ float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
+ r *= scale;
+ g *= scale;
+ b *= scale;
+ }
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
+ R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
+ if (surface->lightmaptexture)
+ R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
+ else
+ R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, !surface->lightmaptexture, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ else if (dolightmap && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) && !lightmodel)
+ {
+ // single texture
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_DepthMask(true);
+ GL_Color(1, 1, 1, 1);
+ memset(&m, 0, sizeof(m));
+ R_Mesh_State(&m);
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
+ if (surface->lightmaptexture)
+ {
+ R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
+ R_Mesh_ColorPointer(NULL);
+ }
+ else
+ {
+ R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
+ R_Mesh_ColorPointer(surface->groupmesh->data_lightmapcolor4f);
+ }
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
+ GL_DepthMask(false);
+ GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(basetexture);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ R_Mesh_State(&m);
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ else
+ {
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(basetexture);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ m.pointer_color = varray_color4f;
+ colorscale = 2;
+ if (gl_combine.integer)
+ {
+ m.texrgbscale[0] = 2;
+ colorscale = 1;
+ }
+ // transparent is not affected by r_lightmapintensity
+ if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ colorscale *= r_lightmapintensity;
+ R_Mesh_State(&m);
+ r = ent->colormod[0] * colorscale;
+ g = ent->colormod[1] * colorscale;
+ b = ent->colormod[2] * colorscale;
+ a = texture->currentalpha;
+ if (dolightmap)
+ {
+ // q3bsp has no lightmap updates, so the lightstylevalue that
+ // would normally be baked into the lightmaptexture must be
+ // applied to the color
+ if (ent->model->brushq3.data_lightmaps)
+ {
+ float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
+ r *= scale;
+ g *= scale;
+ b *= scale;
+ }
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ else
+ {
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ }
+ if (dopants)
+ {
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.pants);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ m.pointer_color = varray_color4f;
+ colorscale = 1;
+ if (gl_combine.integer)
+ {
+ m.texrgbscale[0] = 2;
+ colorscale *= 0.5f;
+ }
+ // transparent is not affected by r_lightmapintensity
+ if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ colorscale *= r_lightmapintensity;
+ R_Mesh_State(&m);
+ r = ent->colormod[0] * colorpants[0] * colorscale;
+ g = ent->colormod[1] * colorpants[1] * colorscale;
+ b = ent->colormod[2] * colorpants[2] * colorscale;
+ a = texture->currentalpha;
+ if (dolightmap && !dofullbrightpants)
+ {
+ // q3bsp has no lightmap updates, so the lightstylevalue that
+ // would normally be baked into the lightmaptexture must be
+ // applied to the color
+ if (ent->model->brushq3.data_lightmaps)
+ {
+ float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
+ r *= scale;
+ g *= scale;
+ b *= scale;
+ }
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ else
+ {
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ }
+ if (doshirt)
+ {
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.shirt);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ m.pointer_color = varray_color4f;
+ colorscale = 1;
+ if (gl_combine.integer)
+ {
+ m.texrgbscale[0] = 2;
+ colorscale *= 0.5f;
+ }
+ // transparent is not affected by r_lightmapintensity
+ if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ colorscale *= r_lightmapintensity;
+ R_Mesh_State(&m);
+ r = ent->colormod[0] * colorshirt[0] * colorscale;
+ g = ent->colormod[1] * colorshirt[1] * colorscale;
+ b = ent->colormod[2] * colorshirt[2] * colorscale;
+ a = texture->currentalpha;
+ if (dolightmap && !dofullbrightshirt)
+ {
+ // q3bsp has no lightmap updates, so the lightstylevalue that
+ // would normally be baked into the lightmaptexture must be
+ // applied to the color
+ if (ent->model->brushq3.data_lightmaps)
+ {
+ float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
+ r *= scale;
+ g *= scale;
+ b *= scale;
+ }
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ else
+ {
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ }
+ if (doambient)
+ {
+ doambient = false;
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(false);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.base);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ m.pointer_color = varray_color4f;
+ colorscale = 1;
+ if (gl_combine.integer)
+ {
+ m.texrgbscale[0] = 2;
+ colorscale *= 0.5f;
+ }
+ R_Mesh_State(&m);
+ colorscale *= r_ambient.value * (1.0f / 64.0f);
+ r = ent->colormod[0] * colorscale;
+ g = ent->colormod[1] * colorscale;
+ b = ent->colormod[2] * colorscale;
+ a = texture->currentalpha;
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ if (dodetail)
+ {
+ GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
+ GL_DepthMask(false);
+ GL_Color(1, 1, 1, 1);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.detail);
+ R_Mesh_State(&m);
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoorddetail2f);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ if (doglow)
+ {
+ // if glow was not already done using multitexture, do it now.
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(false);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.glow);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ m.pointer_color = varray_color4f;
+ R_Mesh_State(&m);
+ colorscale = 1;
+ r = ent->colormod[0] * colorscale;
+ g = ent->colormod[1] * colorscale;
+ b = ent->colormod[2] * colorscale;
+ a = texture->currentalpha;
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ if (dofogpass)
+ {
+ // if this is opaque use alpha blend which will darken the earlier
+ // passes cheaply.
+ //
+ // if this is an alpha blended material, all the earlier passes
+ // were darkened by fog already, so we only need to add the fog
+ // color ontop through the fog mask texture
+ //
+ // if this is an additive blended material, all the earlier passes
+ // were darkened by fog already, and we should not add fog color
+ // (because the background was not darkened, there is no fog color
+ // that was lost behind it).
+ if (fogallpasses)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_DepthMask(false);
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture->skin.fog);
+ if (waterscrolling)
+ m.texmatrix[0] = r_waterscrollmatrix;
+ R_Mesh_State(&m);
+ r = fogcolor[0];
+ g = fogcolor[1];
+ b = fogcolor[2];
+ a = texture->currentalpha;
+ applycolor = r != 1 || g != 1 || b != 1 || a != 1;
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ surface = texturesurfacelist[texturesurfaceindex];
+ RSurf_SetVertexPointer(ent, texture, surface, modelorg);
+ R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
+ R_Mesh_ColorPointer(varray_color4f);
+ //RSurf_FogPassColors_Vertex3f_Color4f((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->num_vertices, modelorg);
+ if (!surface->lightmaptexture && surface->groupmesh->data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
+ {
+ for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
+ {
+ VectorSubtract(v, modelorg, diff);
+ f = exp(fogdensity/DotProduct(diff, diff));
+ c[0] = r;
+ c[1] = g;
+ c[2] = b;
+ c[3] = (surface->groupmesh->data_lightmapcolor4f + 4 * surface->num_firstvertex)[i*4+3] * f * a;
+ }
+ }
+ else
+ {
+ for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
+ {
+ VectorSubtract(v, modelorg, diff);
+ f = exp(fogdensity/DotProduct(diff, diff));
+ c[0] = r;
+ c[1] = g;
+ c[2] = b;
+ c[3] = f * a;
+ }
+ }
+ GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
+ R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ GL_LockArrays(0, 0);
+ }
+ }
+ }
+ if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
+ qglEnable(GL_CULL_FACE);
+}
+
+static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
+{
+ const entity_render_t *ent = calldata1;
+ const msurface_t *surface = ent->model->data_surfaces + calldata2;
+ vec3_t modelorg;
+ texture_t *texture;
+
+ texture = surface->texture;
+ if (texture->basematerialflags & MATERIALFLAG_SKY)
+ return; // transparent sky is too difficult
+ R_UpdateTextureInfo(ent, texture);
+
+ R_Mesh_Matrix(&ent->matrix);
+ Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
+ R_DrawTextureSurfaceList(ent, texture->currentframe, 1, &surface, modelorg);
+}
+
+void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
+{
+ int texturesurfaceindex;
+ const msurface_t *surface;
+ vec3_t tempcenter, center;
+ if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
+ {
+ // drawing sky transparently would be too difficult
+ if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
+ {
+ for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
+ {
+ 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(&ent->matrix, tempcenter, center);
+ R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->data_surfaces);
+ }
+ }
+ }
+ else
+ R_DrawTextureSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg);
+}
+
+extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
+void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
+{
+ int i, j, f, flagsmask;
+ msurface_t *surface, **surfacechain;
+ texture_t *t, *texture;
+ model_t *model = ent->model;
+ vec3_t modelorg;
+ const int maxsurfacelist = 1024;
+ int numsurfacelist = 0;
+ const msurface_t *surfacelist[1024];
+ if (model == NULL)
+ return;
+ R_Mesh_Matrix(&ent->matrix);
+ Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
+
+ // update light styles
+ if (!skysurfaces && model->brushq1.light_styleupdatechains)
+ {
+ for (i = 0;i < model->brushq1.light_styles;i++)
+ {
+ if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
+ {
+ model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
+ if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
+ for (;(surface = *surfacechain);surfacechain++)
+ surface->cached_dlight = true;
+ }
+ }
+ }
+
+ R_UpdateAllTextureInfo(ent);
+ flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
+ f = 0;
+ t = NULL;
+ texture = NULL;
+ numsurfacelist = 0;
+ if (ent == r_refdef.worldentity)
+ {
+ for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ {
+ if (!r_worldsurfacevisible[j])
+ continue;
+ if (t != surface->texture)
+ {
+ if (numsurfacelist)
+ {
+ R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
+ numsurfacelist = 0;
+ }
+ t = surface->texture;
+ texture = t->currentframe;
+ f = texture->currentmaterialflags & flagsmask;
+ }
+ if (f && surface->num_triangles)
+ {
+ // if lightmap parameters changed, rebuild lightmap texture
+ if (surface->cached_dlight && surface->lightmapinfo->samples)
+ R_BuildLightMap(ent, surface);
+ // add face to draw list
+ surfacelist[numsurfacelist++] = surface;
+ if (numsurfacelist >= maxsurfacelist)
+ {
+ R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
+ numsurfacelist = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
+ {
+ if (t != surface->texture)
+ {
+ if (numsurfacelist)
+ {
+ R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
+ numsurfacelist = 0;
+ }
+ t = surface->texture;
+ texture = t->currentframe;
+ f = texture->currentmaterialflags & flagsmask;
+ }
+ if (f && surface->num_triangles)
+ {
+ // if lightmap parameters changed, rebuild lightmap texture
+ if (surface->cached_dlight && surface->lightmapinfo->samples)
+ R_BuildLightMap(ent, surface);
+ // add face to draw list
+ surfacelist[numsurfacelist++] = surface;
+ if (numsurfacelist >= maxsurfacelist)
+ {
+ R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
+ numsurfacelist = 0;
+ }
+ }
+ }
+ }
+ if (numsurfacelist)
+ R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
+}