From c651b263f8a63fa5846df832051d4f5658680a03 Mon Sep 17 00:00:00 2001 From: havoc Date: Thu, 17 Mar 2005 07:11:41 +0000 Subject: [PATCH] merged q1bsp and q3bsp surface rendering disabled MarkLights based dlights (lightmap dlights, etc) because they're just too hard to maintain (broken AGAIN), and the code for them will be removed soon renamed r_shadow_whitetexture and related textures to r_texture_white and such, and moved them to gl_rmain for more general use git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5089 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_draw.c | 2 +- gl_models.c | 2 +- gl_rmain.c | 47 ++ gl_rsurf.c | 2084 ++++++++++++++++++++++++++++++++++++------------ model_alias.c | 2 +- model_brush.c | 48 +- model_brush.h | 5 +- model_shared.c | 30 +- model_shared.h | 2 +- r_light.c | 94 ++- r_light.h | 2 + r_shadow.c | 46 +- render.h | 5 + 13 files changed, 1730 insertions(+), 639 deletions(-) diff --git a/gl_draw.c b/gl_draw.c index 65c6a835..e861f118 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -335,7 +335,7 @@ cachepic_t *Draw_CachePic (char *path) if (pic->tex == NULL) { Con_Printf("Draw_CachePic: failed to load %s\n", path); - pic->tex = r_notexture; + pic->tex = r_texture_notexture; } pic->width = R_TextureWidth(pic->tex); diff --git a/gl_models.c b/gl_models.c index e5976d7e..c84fcf01 100644 --- a/gl_models.c +++ b/gl_models.c @@ -26,7 +26,7 @@ aliasskin_t *R_FetchAliasSkin(const entity_render_t *ent, const aliasmesh_t *mes } else { - r_aliasnoskinlayers[0].texture = r_notexture; + r_aliasnoskinlayers[0].texture = r_texture_notexture; return &r_aliasnoskin; } } diff --git a/gl_rmain.c b/gl_rmain.c index 8e7fab34..de832728 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -106,6 +106,10 @@ cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"}; rtexturepool_t *r_main_texturepool; rtexture_t *r_bloom_texture_screen; rtexture_t *r_bloom_texture_bloom; +rtexture_t *r_texture_blanknormalmap; +rtexture_t *r_texture_white; +rtexture_t *r_texture_black; +rtexture_t *r_texture_notexture; void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) { @@ -207,9 +211,49 @@ void FOG_registercvars(void) void gl_main_start(void) { + int x, y; + qbyte pix[16][16][4]; + qbyte data[4]; r_main_texturepool = R_AllocTexturePool(); r_bloom_texture_screen = NULL; r_bloom_texture_bloom = NULL; + data[0] = 128; // normal X + data[1] = 128; // normal Y + data[2] = 255; // normal Z + data[3] = 128; // height + r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); + data[0] = 255; + data[1] = 255; + data[2] = 255; + data[3] = 255; + r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 255; + r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); + // this makes a light grey/dark grey checkerboard texture + for (y = 0;y < 16;y++) + { + for (x = 0;x < 16;x++) + { + if ((y < 8) ^ (x < 8)) + { + pix[y][x][0] = 128; + pix[y][x][1] = 128; + pix[y][x][2] = 128; + pix[y][x][3] = 255; + } + else + { + pix[y][x][0] = 64; + pix[y][x][1] = 64; + pix[y][x][2] = 64; + pix[y][x][3] = 255; + } + } + } + r_texture_notexture = R_LoadTexture2D(mod_shared_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL); } void gl_main_shutdown(void) @@ -217,6 +261,9 @@ void gl_main_shutdown(void) R_FreeTexturePool(&r_main_texturepool); r_bloom_texture_screen = NULL; r_bloom_texture_bloom = NULL; + r_texture_blanknormalmap = NULL; + r_texture_white = NULL; + r_texture_black = NULL; } extern void CL_ParseEntityLump(char *entitystring); diff --git a/gl_rsurf.c b/gl_rsurf.c index 57f23523..633007f9 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -49,6 +49,7 @@ qbyte r_worldleafvisible[32768]; // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_surfaces qbyte r_worldsurfacevisible[262144]; +#ifdef LHREMOVESOON static int dlightdivtable[32768]; static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface) @@ -64,14 +65,15 @@ static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface tmax = (surface->extents[1] >> 4) + 1; smax3 = smax * 3; + VectorCopy(surface->mesh.data_normal3f, planenormal); + planedist = DotProduct(surface->mesh.data_vertex3f, planenormal); + for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) { if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue; // not lit by this light Matrix4x4_Transform(matrix, light->origin, local); - VectorCopy(surface->mesh.data_normal3f, planenormal); - planedist = DotProduct(surface->mesh.data_vertex3f, planenormal); dist = DotProduct(local, planenormal) - planedist; // for comparisons to minimum acceptable light @@ -150,14 +152,15 @@ static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surfa tmax = (surface->extents[1] >> 4) + 1; smax3 = smax * 3; + VectorCopy(surface->mesh.data_normal3f, planenormal); + planedist = DotProduct(surface->mesh.data_vertex3f, planenormal); + for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++) { if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue; // not lit by this light Matrix4x4_Transform(matrix, light->origin, local); - VectorCopy(surface->mesh.data_normal3f, planenormal); - planedist = DotProduct(surface->mesh.data_vertex3f, planenormal); dist = DotProduct(local, planenormal) - planedist; // for comparisons to minimum acceptable light @@ -220,6 +223,7 @@ static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surfa } return lit; } +#endif /* =============== @@ -257,12 +261,15 @@ static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) // clear to no light memset(bl, 0, size*3*sizeof(unsigned int)); +#ifdef LHREMOVESOON if (surface->dlightframe == r_framecount) { + surface->dlightframe = -1; surface->cached_dlight = R_IntAddDynamicLights(&ent->inversematrix, surface); if (surface->cached_dlight) c_light_polys++; } +#endif // add all the lightmaps if (lightmap) @@ -337,12 +344,15 @@ static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) { memset(bl, 0, size*3*sizeof(float)); +#ifdef LHREMOVESOON if (surface->dlightframe == r_framecount) { + surface->dlightframe = -1; surface->cached_dlight = R_FloatAddDynamicLights(&ent->inversematrix, surface); if (surface->cached_dlight) c_light_polys++; } +#endif // add all the lightmaps if (lightmap) @@ -562,6 +572,7 @@ void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ============================================================= */ +#ifdef LHREMOVESOON static void RSurf_AddLightmapToVertexColors_Color4f(const int *lightmapoffsets, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles) { int i; @@ -595,7 +606,9 @@ static void RSurf_AddLightmapToVertexColors_Color4f(const int *lightmapoffsets, } } } +#endif +#ifdef LHREMOVESOON static void RSurf_FogColors_Vertex3f_Color4f(const float *v, float *c, float colorscale, int numverts, const float *modelorg) { int i; @@ -613,7 +626,9 @@ static void RSurf_FogColors_Vertex3f_Color4f(const float *v, float *c, float col for (i = 0;i < numverts;i++, c += 4) VectorScale(c, colorscale, c); } +#endif +#ifdef LHREMOVESOON static void RSurf_FoggedColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg) { int i; @@ -644,7 +659,9 @@ static void RSurf_FoggedColors_Vertex3f_Color4f(const float *v, float *c, float } } } +#endif +#ifdef LHREMOVESOON static void RSurf_FogPassColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg) { int i; @@ -662,7 +679,9 @@ static void RSurf_FogPassColors_Vertex3f_Color4f(const float *v, float *c, float c[3] = a * f; } } +#endif +#ifdef LHREMOVESOON static int RSurf_LightSeparate_Vertex3f_Color4f(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color, float scale) { float f; @@ -691,189 +710,111 @@ static int RSurf_LightSeparate_Vertex3f_Color4f(const matrix4x4_t *matrix, const } return lit; } +#endif + +static float *RSurf_GetVertexPointer(const entity_render_t *ent, const msurface_t *surface) +{ + if (surface->texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) + { + texture_t *texture = surface->texture; + int i, j; + float center[3], center2[3], forward[3], right[3], up[3], v[4][3]; + matrix4x4_t matrix1, imatrix1; + R_Mesh_Matrix(&r_identitymatrix); + // a single autosprite surface can contain multiple sprites... + for (j = 0;j < surface->mesh.num_vertices - 3;j += 4) + { + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, surface->mesh.data_vertex3f + (j+i) * 3, center); + VectorScale(center, 0.25f, center); + Matrix4x4_Transform(&ent->matrix, center, center2); + // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out? + Matrix4x4_FromVectors(&matrix1, surface->mesh.data_normal3f + j*3, surface->mesh.data_svector3f + j*3, surface->mesh.data_tvector3f + j*3, center); + Matrix4x4_Invert_Simple(&imatrix1, &matrix1); + for (i = 0;i < 4;i++) + Matrix4x4_Transform(&imatrix1, surface->mesh.data_vertex3f + (j+i)*3, v[i]); + if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2) + { + forward[0] = r_vieworigin[0] - center2[0]; + forward[1] = r_vieworigin[1] - center2[1]; + forward[2] = 0; + VectorNormalize(forward); + right[0] = forward[1]; + right[1] = -forward[0]; + right[2] = 0; + up[0] = 0; + up[1] = 0; + up[2] = 1; + } + else + { + VectorCopy(r_viewforward, forward); + VectorCopy(r_viewright, right); + VectorCopy(r_viewup, up); + } + for (i = 0;i < 4;i++) + VectorMAMAMAM(1, center2, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (i+j) * 3); + } + return varray_vertex3f; + } + else + return surface->mesh.data_vertex3f; +} void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { + // we don't need to set currentframe if t->animated is false because + // it was already set up by the texture loader for non-animating + if (t->animated) + { + t->currentframe = 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]; + t = t->currentframe; + } 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; - if (t->currentalpha < 1 || t->skin.fog != NULL) + else if (t->currentalpha < 1) t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT; - // we don't need to set currentframe if t->animated is false because - // it was already set up by the texture loader for non-animating - if (t->animated) - t->currentframe = 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]; } +matrix4x4_t r_surf_waterscrollmatrix; + void R_UpdateAllTextureInfo(entity_render_t *ent) { int i; + Matrix4x4_CreateTranslate(&r_surf_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); if (ent->model) for (i = 0;i < ent->model->brush.num_textures;i++) R_UpdateTextureInfo(ent, ent->model->brush.data_textures + i); } -static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2) -{ - const entity_render_t *ent = calldata1; - const msurface_t *surface = ent->model->brush.data_surfaces + calldata2; - rmeshstate_t m; - float base, colorscale; - vec3_t modelorg; - texture_t *texture; - float args[4] = {0.05f,0,0,0.04f}; - int turb, fullbright; - - texture = surface->texture; - R_UpdateTextureInfo(ent, texture); - if (texture->currentmaterialflags & MATERIALFLAG_SKY) - return; // transparent sky is too difficult - - R_Mesh_Matrix(&ent->matrix); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); - - 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); - - turb = texture->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value; - fullbright = !(ent->flags & RENDER_LIGHT) || (texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !surface->samples; - base = fullbright ? 2.0f : r_ambient.value * (1.0f / 64.0f); - if (texture->currentmaterialflags & MATERIALFLAG_WATER) - base *= 0.5f; - if (texture->currentmaterialflags & MATERIALFLAG_WATER && gl_textureshader && r_watershader.value && !fogenabled && fullbright && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1) - { - // NVIDIA Geforce3 distortion texture shader on water - GL_Color(1, 1, 1, texture->currentalpha); - memset(&m, 0, sizeof(m)); - m.pointer_vertex = surface->mesh.data_vertex3f; - m.tex[0] = R_GetTexture(mod_shared_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; - m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; - m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; - Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value); - Matrix4x4_CreateTranslate(&m.texmatrix[1], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); - R_Mesh_State(&m); - - 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); - - GL_LockArrays(0, surface->mesh.num_vertices); - R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); - 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 - { - memset(&m, 0, sizeof(m)); - m.pointer_vertex = surface->mesh.data_vertex3f; - m.pointer_color = varray_color4f; - m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; - m.tex[0] = R_GetTexture(texture->skin.base); - if (turb) - { - // scrolling in texture matrix - Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); - } - colorscale = 1; - if (gl_combine.integer) - { - m.texrgbscale[0] = 4; - colorscale *= 0.25f; - } - R_FillColors(varray_color4f, surface->mesh.num_vertices, base * ent->colormod[0], base * ent->colormod[1], base * ent->colormod[2], texture->currentalpha); - if (!fullbright) - { - if (surface->dlightframe == r_framecount) - RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surface->dlightbits, surface->mesh.num_vertices, surface->mesh.data_vertex3f, varray_color4f, 1); - if (surface->samples) - RSurf_AddLightmapToVertexColors_Color4f(surface->mesh.data_lightmapoffsets, varray_color4f,surface->mesh.num_vertices, surface->samples, ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3, surface->styles); - } - RSurf_FogColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, colorscale, surface->mesh.num_vertices, modelorg); - R_Mesh_State(&m); - GL_LockArrays(0, surface->mesh.num_vertices); - R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); - GL_LockArrays(0, 0); - if (texture->skin.glow) - { - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - GL_DepthMask(false); - m.pointer_color = varray_color4f; - m.tex[0] = R_GetTexture(texture->skin.glow); - m.pointer_vertex = surface->mesh.data_vertex3f; - if (m.tex[0]) - { - m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; - if (turb) - { - // scrolling in texture matrix - Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); - } - } - R_Mesh_State(&m); - RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, 1, 1, 1, texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); - GL_LockArrays(0, surface->mesh.num_vertices); - R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); - GL_LockArrays(0, 0); - } - if (fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD)) - { - memset(&m, 0, sizeof(m)); - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - GL_DepthMask(false); - m.pointer_color = varray_color4f; - m.tex[0] = R_GetTexture(texture->skin.fog); - m.pointer_vertex = surface->mesh.data_vertex3f; - if (m.tex[0]) - { - m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; - if (turb) - { - // scrolling in texture matrix - Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); - } - } - R_Mesh_State(&m); - RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); - GL_LockArrays(0, surface->mesh.num_vertices); - R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); - GL_LockArrays(0, 0); - } - } -} - -void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, msurface_t **texturesurfacelist) +static void R_DrawSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg) { + int i; int texturesurfaceindex; - vec3_t tempcenter, center, modelorg; - msurface_t *surface; + const float *v; + float *c; + float diff[3]; + float f, r, g, b, a, base, colorscale; + const msurface_t *surface; qboolean dolightmap; qboolean dobase; qboolean doambient; qboolean dodetail; qboolean doglow; - qboolean dofog; + qboolean dofogpass; + qboolean fogallpasses; + qboolean waterscrolling; rmeshstate_t m; - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + texture = texture->currentframe; + if (texture->currentmaterialflags & MATERIALFLAG_NODRAW) + return; c_faces += texturenumsurfaces; // gl_lightmaps debugging mode skips normal texturing if (gl_lightmaps.integer) @@ -905,49 +846,1356 @@ void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenums qglEnable(GL_CULL_FACE); return; } - // transparent surfaces get sorted for later drawing - if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + 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) { - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + if (skyrendernow) { - 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(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces); + skyrendernow = false; + if (skyrendermasked) + R_Sky(); } - return; - } - if (texture->currentmaterialflags & MATERIALFLAG_WALL) - { - dolightmap = (ent->flags & RENDER_LIGHT); - dobase = true; - doambient = r_ambient.value > 0; - dodetail = texture->skin.detail != NULL && r_detailtextures.integer != 0; - doglow = texture->skin.glow != NULL; - dofog = fogenabled; - // multitexture cases - if (r_textureunits.integer >= 2 && gl_combine.integer && dobase && dolightmap) + // LordHavoc: HalfLife maps have freaky skypolys... + if (!ent->model->brush.ishlbsp) { - GL_BlendFunc(GL_ONE, GL_ZERO); + 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); - GL_Color(1, 1, 1, 1); - 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(texture->skin.base); - dobase = false; - m.texrgbscale[1] = 2; - dolightmap = false; - if (r_textureunits.integer >= 4 && !doambient && dodetail && doglow) + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { - m.tex[2] = R_GetTexture(texture->skin.detail); - m.texrgbscale[2] = 2; - dodetail = false; - m.tex[3] = R_GetTexture(texture->skin.glow); - m.texcombinergb[3] = GL_ADD; - doglow = false; + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = surface->mesh.data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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(mod_shared_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_surf_waterscrollmatrix; + + 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]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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) + dobase = true; + dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT); + doambient = r_ambient.value >= (1/64.0f); + dodetail = 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 (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + { + if (dobase && dolightmap && gl_combine.integer) + { + dobase = false; + memset(&m, 0, sizeof(m)); + m.tex[1] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[1] = r_surf_waterscrollmatrix; + m.texrgbscale[1] = 2; + m.pointer_color = varray_color4f; + colorscale = 1; + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + base = r_ambient.value * (1.0f / 64.0f); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f; + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + if (surface->lightmaptexture) + { + m.tex[0] = R_GetTexture(surface->lightmaptexture); + if (fogallpasses) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = f * r; + c[1] = f * g; + c[2] = f * b; + c[3] = a; + } + } + else + { + m.pointer_color = NULL; + GL_Color(r, g, b, a); + } + } + else + { + m.tex[0] = R_GetTexture(r_texture_white); + m.pointer_color = varray_color4f; +#ifdef LHREMOVESOON + if (surface->styles[0] != 255 || surface->dlightframe == r_framecount) +#else + if (surface->styles[0] != 255) +#endif + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = 0; + c[1] = 0; + c[2] = 0; + if (surface->styles[0] != 255) + { + if (surface->mesh.data_lightmapcolor4f) + { + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f); + VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c); + } + else if (surface->mesh.data_lightmapoffsets) + { + const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i]; + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[1] != 255) + { + int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3; + lm += size3; + scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[2] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[3] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + } + } + } + } + } +#ifdef LHREMOVESOON + if (surface->dlightframe == r_framecount) + { + int l; + float worldvertex[3]; + // TODO: make this work with autosprite which uses identitymatrix + Matrix4x4_Transform(&ent->matrix, v, worldvertex); + for (l = 0;l < r_numdlights;l++) + { + if (surface->dlightbits[l >> 5] & (1 << (l & 31))) + { + float f2; + dlight_t *light = &r_dlight[l]; + f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET; + if (f2 < light->rtlight.lightmap_cullradius2) + { + f2 = (1.0f / f2) - light->rtlight.lightmap_subtract; + VectorMA(c, f2, light->rtlight.lightmap_light, c); + } + } + } + } +#endif + c[0] *= r; + c[1] *= g; + c[2] *= b; + if (fogallpasses) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + } + else + { + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = NULL; + GL_Color(0, 0, 0, a); + } + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + if (dobase) + { + dobase = false; + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[0] = r_surf_waterscrollmatrix; + m.texmatrix[0] = r_surf_waterscrollmatrix; + m.pointer_color = varray_color4f; + colorscale = 1; + if (gl_combine.integer) + { + m.texrgbscale[0] = 4; + colorscale *= 0.25f; + } + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + if (dolightmap) + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = 0; + c[1] = 0; + c[2] = 0; + if (surface->styles[0] != 255) + { + if (surface->mesh.data_lightmapcolor4f) + { + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f); + VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c); + } + else if (surface->mesh.data_lightmapoffsets) + { + const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i]; + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[1] != 255) + { + int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3; + lm += size3; + scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[2] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[3] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + } + } + } + } + } +#ifdef LHREMOVESOON + if (surface->dlightframe == r_framecount) + { + // TODO: make this work with autosprite which uses identitymatrix + Matrix4x4_Transform(&ent->matrix, v, worldvertex); + for (l = 0;l < r_numdlights;l++) + { + if (surface->dlightbits[l >> 5] & (1 << (l & 31))) + { + float f2; + dlight_t *light = &r_dlight[l]; + f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET; + if (f2 < light->rtlight.lightmap_cullradius2) + { + f2 = (1.0f / f2) - light->rtlight.lightmap_subtract; + VectorMA(c, f2, light->rtlight.lightmap_light, c); + } + } + } + } +#endif + c[0] *= r; + c[1] *= g; + c[2] *= b; + if (fogallpasses) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + else + { + if (fogallpasses) + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + if (m.tex[1]) + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = r * f; + c[1] = g * f; + c[2] = b * f; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = r * f; + c[1] = g * f; + c[2] = b * f; + c[3] = a; + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + else + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + if (m.tex[1]) + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = NULL; + GL_Color(r, g, b, a); + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + } + } + } + else + { + if (!dolightmap && dobase) + { + dolightmap = false; + dobase = false; + GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[0] = r_surf_waterscrollmatrix; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + if (r_lightmapintensity <= 0 && dolightmap && dobase) + { + dolightmap = false; + dobase = false; + GL_Color(0, 0, 0, 1); + memset(&m, 0, sizeof(m)); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + if (r_textureunits.integer >= 2 && gl_combine.integer && dolightmap && dobase) + { + // dualtexture combine + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + dolightmap = false; + dobase = false; + memset(&m, 0, sizeof(m)); + m.tex[1] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[1] = r_surf_waterscrollmatrix; + m.texrgbscale[1] = 2; + r = ent->colormod[0] * r_lightmapintensity; + g = ent->colormod[1] * r_lightmapintensity; + b = ent->colormod[2] * r_lightmapintensity; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + memset(&m, 0, sizeof(m)); + m.tex[1] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[1] = r_surf_waterscrollmatrix; + m.texrgbscale[1] = 2; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f; + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + if (surface->lightmaptexture) + { + m.tex[0] = R_GetTexture(surface->lightmaptexture); + m.pointer_color = NULL; + GL_Color(r, g, b, 1); + } + else if (r == 1 && g == 1 && b == 1) + { + m.tex[0] = R_GetTexture(r_texture_white); + m.pointer_color = surface->mesh.data_lightmapcolor4f; + } + else + { + m.tex[0] = R_GetTexture(r_texture_white); + m.pointer_color = varray_color4f; + for (i = 0;i < surface->mesh.num_vertices;i++) + { + varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * r; + varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * g; + varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * b; + varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3]; + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + // single texture + if (dolightmap) + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + GL_Color(1, 1, 1, 1); + memset(&m, 0, sizeof(m)); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.tex[0] = R_GetTexture(surface->lightmaptexture); + m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f; + if (surface->lightmaptexture) + m.pointer_color = NULL; + else + m.pointer_color = surface->mesh.data_lightmapcolor4f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + if (dobase) + { + 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(texture->skin.base); + if (waterscrolling) + m.texmatrix[0] = r_surf_waterscrollmatrix; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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_surf_waterscrollmatrix; + m.pointer_color = varray_color4f; + colorscale = 1; + if (gl_combine.integer) + { + m.texrgbscale[0] = 4; + colorscale *= 0.25f; + } + base = r_ambient.value * (1.0f / 64.0f); + r = ent->colormod[0] * colorscale * base; + g = ent->colormod[1] * colorscale * base; + b = ent->colormod[2] * colorscale * base; + a = texture->currentalpha; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = r; + c[1] = g; + c[2] = b; + if (fogallpasses) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + // marklights based vertex dlight rendering... evil and broken +#if 0 + GL_BlendFunc(GL_ONE, GL_ONE); + GL_DepthMask(false); + memset(&m, 0, sizeof(m)); + m.tex[0] = R_GetTexture(texture->skin.base); + if (waterscrolling) + m.texmatrix[0] = r_surf_waterscrollmatrix; + m.pointer_color = varray_color4f; + r = ent->colormod[0] * r_lightmapintensity; + g = ent->colormod[1] * r_lightmapintensity; + b = ent->colormod[2] * r_lightmapintensity; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + qboolean lit; + surface = texturesurfacelist[texturesurfaceindex]; + if (surface->dlightframe != r_framecount) + continue; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + lit = false; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 1; + // TODO: make this work with autosprite which uses identitymatrix or change autosprite + Matrix4x4_Transform(&ent->matrix, v, worldvertex); + for (l = 0;l < r_numdlights;l++) + { + if (surface->dlightbits[l >> 5] & (1 << (l & 31))) + { + float f2; + dlight_t *light = &r_dlight[l]; + f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET; + if (f2 < light->rtlight.lightmap_cullradius2) + { + f2 = (1.0f / f2) - light->rtlight.lightmap_subtract; + VectorMA(c, f2, light->rtlight.lightmap_light, c); + lit = true; + } + } + } + c[0] *= r; + c[1] *= g; + c[2] *= b; + if (fogallpasses) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + if (!lit) + continue; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } +#endif + 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); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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_surf_waterscrollmatrix; + m.pointer_color = varray_color4f; + colorscale = 1; + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + if (fogallpasses) + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = f * r; + c[1] = f * g; + c[2] = f * b; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = f * r; + c[1] = f * g; + c[2] = f * b; + c[3] = a; + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + else + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = NULL; + GL_Color(r, g, b, a); + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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_surf_waterscrollmatrix; + r = fogcolor[0]; + g = fogcolor[1]; + b = fogcolor[2]; + a = texture->currentalpha; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.pointer_color = varray_color4f; + //RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); + if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.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->mesh.data_lightmapcolor4f[i*4+3] * f * a; + } + } + else + { + m.pointer_color = varray_color4f; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.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; + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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->brush.data_surfaces + calldata2; + vec3_t modelorg; + texture_t *texture; +#ifdef LHREMOVESOON + rmeshstate_t m; + float base, colorscale; + float args[4] = {0.05f,0,0,0.04f}; + matrix4x4_t scrollmatrix; +#endif + + 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_DrawSurfaceList(ent, texture, 1, &surface, modelorg); +#ifdef LHREMOVESOON + 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 scrolling in texture matrix + if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0) + Matrix4x4_CreateTranslate(&scrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); + else + scrollmatrix = r_identitymatrix; + + if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglDisable(GL_CULL_FACE); + 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 + GL_Color(1, 1, 1, texture->currentalpha); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.tex[0] = R_GetTexture(mod_shared_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; + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value); + m.texmatrix[1] = scrollmatrix; + R_Mesh_State(&m); + + 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); + + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + 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 + { + int i; + float r, g, b, a, f, *c, diff[3]; + const float *v; + qboolean dolightmaptexture; + qboolean dodetail; + qboolean doglow; + dolightmaptexture = surface->lightmaptexture && gl_combine.integer && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT); + dodetail = texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT); + doglow = texture->skin.glow != NULL; + // TODO: ideally transparent surface rendering should call + // R_RenderLighting instead of using vertex dlights + // (it would need scrolling support added though!) + if (dolightmaptexture) + { + { + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.tex[0] = R_GetTexture(texture->skin.base); + m.texmatrix[0] = scrollmatrix; + m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f; + m.tex[1] = R_GetTexture(surface->lightmaptexture); + m.texrgbscale[1] = 2; + m.pointer_color = varray_color4f; + if (r_textureunits.integer >= 3 && dodetail) + { + dodetail = false; + m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f; + m.tex[2] = R_GetTexture(texture->skin.detail); + m.texmatrix[2] = scrollmatrix; + if (r_textureunits.integer >= 4 && doglow) + { + doglow = false; + m.pointer_texcoord[3] = surface->mesh.data_texcoordtexture2f; + m.tex[3] = R_GetTexture(texture->skin.glow); + m.texmatrix[3] = scrollmatrix; + } + } + else if (r_textureunits.integer >= 3 && doglow && !dodetail) + { + doglow = false; + m.pointer_texcoord[2] = surface->mesh.data_texcoordtexture2f; + m.tex[2] = R_GetTexture(texture->skin.glow); + m.texmatrix[2] = scrollmatrix; + } + colorscale = 1; + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = r; + c[1] = g; + c[2] = b; + if (fogenabled) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + if ((r_ambient.value > 0 || surface->dlightframe == r_framecount) && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.tex[0] = R_GetTexture(texture->skin.base); + m.texmatrix[0] = scrollmatrix; + m.pointer_color = varray_color4f; + colorscale = 1; + if (gl_combine.integer) + { + m.texrgbscale[0] = 4; + colorscale *= 0.25f; + } + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + base = r_ambient.value * (1.0f / 64.0f); + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = base; + c[1] = base; + c[2] = base; + if (surface->dlightframe == r_framecount) + { + // TODO: make this work with autosprite which uses identitymatrix + Matrix4x4_Transform(&ent->matrix, v, worldvertex); + for (l = 0;l < r_numdlights;l++) + { + if (surface->dlightbits[l >> 5] & (1 << (l & 31))) + { + float f2; + dlight_t *light = &r_dlight[l]; + f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET; + if (f2 < light->rtlight.lightmap_cullradius2) + { + f2 = (1.0f / f2) - light->rtlight.lightmap_subtract; + VectorMA(c, f2, light->rtlight.lightmap_light, c); + } + } + } + } + c[0] *= r; + c[1] *= g; + c[2] *= b; + if (fogenabled) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + else + { + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.tex[0] = R_GetTexture(texture->skin.base); + m.texmatrix[0] = scrollmatrix; + m.pointer_color = varray_color4f; + colorscale = 1; + if (gl_combine.integer) + { + m.texrgbscale[0] = 4; + colorscale *= 0.25f; + } + if (doglow) + { + doglow = false; + m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f; + m.tex[1] = R_GetTexture(texture->skin.glow); + m.texmatrix[1] = scrollmatrix; + } + r = ent->colormod[0] * colorscale; + g = ent->colormod[1] * colorscale; + b = ent->colormod[2] * colorscale; + a = texture->currentalpha; + base = r_ambient.value * (1.0f / 64.0f); + if ((ent->flags & RENDER_LIGHT) && !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = base; + c[1] = base; + c[2] = base; + if (surface->styles[0] != 255) + { + if (surface->mesh.data_lightmapcolor4f) + { + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f); + VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c); + } + else if (surface->mesh.data_lightmapoffsets) + { + const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i]; + float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[1] != 255) + { + int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3; + lm += size3; + scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[2] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + if (surface->styles[3] != 255) + { + lm += size3; + scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f); + VectorMA(c, scale, lm, c); + } + } + } + } + } + if (surface->dlightframe == r_framecount) + { + // TODO: make this work with autosprite which uses identitymatrix + Matrix4x4_Transform(&ent->matrix, v, worldvertex); + for (l = 0;l < r_numdlights;l++) + { + if (surface->dlightbits[l >> 5] & (1 << (l & 31))) + { + float f2; + dlight_t *light = &r_dlight[l]; + f2 = VectorDistance2(worldvertex, light->origin) + LIGHTOFFSET; + if (f2 < light->rtlight.lightmap_cullradius2) + { + f2 = (1.0f / f2) - light->rtlight.lightmap_subtract; + VectorMA(c, f2, light->rtlight.lightmap_light, c); + } + } + } + } + c[0] *= r; + c[1] *= g; + c[2] *= b; + if (fogenabled) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + VectorScale(c, f, c); + } + if (surface->mesh.data_lightmapcolor4f) + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + else + c[3] = a; + } + } + else + { + if (fogenabled) + { + if (surface->mesh.data_lightmapcolor4f) + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = r * f; + c[1] = g * f; + c[2] = b * f; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + VectorSubtract(v, modelorg, diff); + f = 1 - exp(fogdensity/DotProduct(diff, diff)); + c[0] = r * f; + c[1] = g * f; + c[2] = b * f; + c[3] = a; + } + } + } + else + { + if (surface->mesh.data_lightmapcolor4f) + { + for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4) + { + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a; + } + } + else + { + m.pointer_color = NULL; + GL_Color(r, g, b, a); + } + } + } + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + // note: dodetail is never set if transparent + if (dodetail) + { + GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + GL_DepthMask(false); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f; + m.tex[0] = R_GetTexture(texture->skin.detail); + m.pointer_color = varray_color4f; + RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, ent->colormod[0], ent->colormod[1], ent->colormod[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + if (doglow) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.tex[0] = R_GetTexture(texture->skin.glow); + m.texmatrix[0] = scrollmatrix; + m.pointer_color = varray_color4f; + RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, ent->colormod[0], ent->colormod[1], ent->colormod[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + if (fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD)) + { + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = RSurf_GetVertexPointer(ent, surface); + m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; + m.tex[0] = R_GetTexture(texture->skin.fog); + m.texmatrix[0] = scrollmatrix; + m.pointer_color = varray_color4f; + RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg); + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + } + if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglEnable(GL_CULL_FACE); +#endif +} + +#ifdef LHREMOVESOON +void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, msurface_t **texturesurfacelist) +{ + int texturesurfaceindex; + vec3_t tempcenter, center, modelorg; + msurface_t *surface; + qboolean dolightmap; + qboolean dobase; + qboolean doambient; + qboolean dodetail; + qboolean doglow; + qboolean dofog; + rmeshstate_t m; + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + c_faces += texturenumsurfaces; + // 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)); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + m.tex[0] = R_GetTexture(surface->lightmaptexture); + m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f; + if (surface->lightmaptexture) + { + GL_Color(1, 1, 1, 1); + m.pointer_color = NULL; + } + else + m.pointer_color = surface->mesh.data_lightmapcolor4f; + m.pointer_vertex = surface->mesh.data_vertex3f; + R_Mesh_State(&m); + GL_LockArrays(0, surface->mesh.num_vertices); + R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); + GL_LockArrays(0, 0); + } + qglEnable(GL_CULL_FACE); + return; + } + if (texture->currentmaterialflags & MATERIALFLAG_WALL) + { + dolightmap = (ent->flags & RENDER_LIGHT); + dobase = true; + doambient = r_ambient.value > 0; + dodetail = texture->skin.detail != NULL && r_detailtextures.integer != 0; + doglow = texture->skin.glow != NULL; + dofog = fogenabled; + // multitexture cases + if (r_textureunits.integer >= 2 && gl_combine.integer && dobase && dolightmap) + { + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_DepthMask(true); + GL_DepthTest(true); + GL_Color(1, 1, 1, 1); + 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(texture->skin.base); + dobase = false; + m.texrgbscale[1] = 2; + dolightmap = false; + if (r_textureunits.integer >= 4 && !doambient && dodetail && doglow) + { + m.tex[2] = R_GetTexture(texture->skin.detail); + m.texrgbscale[2] = 2; + dodetail = false; + m.tex[3] = R_GetTexture(texture->skin.glow); + m.texcombinergb[3] = GL_ADD; + doglow = false; for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { surface = texturesurfacelist[texturesurfaceindex]; @@ -1194,6 +2442,32 @@ void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenums return; } } +#endif + +void R_QueueSurfaceList(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(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces); + } + } + } + else + R_DrawSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg); +} void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) { @@ -1204,12 +2478,13 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) vec3_t modelorg; const int maxsurfacelist = 1024; int numsurfacelist = 0; - msurface_t *surfacelist[1024]; + const msurface_t *surfacelist[1024]; if (model == NULL) return; R_Mesh_Matrix(&ent->matrix); Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); +#ifdef LHREMOVESOON if (ent != r_refdef.worldentity) { // because bmodels can be reused, we have to clear dlightframe every time @@ -1217,12 +2492,15 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) for (i = 0;i < model->nummodelsurfaces;i++, surface++) surface->dlightframe = -1; } +#endif // update light styles if (!skysurfaces) { +#ifdef LHREMOVESOON if (r_dynamic.integer && !r_rtdlight) R_MarkLights(ent); +#endif for (i = 0;i < model->brushq1.light_styles;i++) { if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]]) @@ -1239,6 +2517,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL); f = 0; t = NULL; + texture = NULL; numsurfacelist = 0; for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++) { @@ -1249,7 +2528,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) { if (numsurfacelist) { - R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist); + R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); numsurfacelist = 0; } t = surface->texture; @@ -1258,20 +2537,21 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } if (f) { - // add face to draw list and update lightmap if necessary - if (surface->cached_dlight && surface->lightmaptexture != NULL) + // if lightmap parameters changed, rebuild lightmap texture + if (surface->cached_dlight && surface->samples) R_BuildLightMap(ent, surface); + // add face to draw list surfacelist[numsurfacelist++] = surface; if (numsurfacelist >= maxsurfacelist) { - R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist); + R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); numsurfacelist = 0; } } } } if (numsurfacelist) - R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist); + R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg); } static void R_DrawPortal_Callback(const void *calldata1, int calldata2) @@ -1331,6 +2611,36 @@ static void R_DrawPortals(void) } } +static void R_DrawCollisionBrush(colbrushf_t *brush) +{ + int i; + rmeshstate_t m; + memset(&m, 0, sizeof(m)); + m.pointer_vertex = brush->points->v; + R_Mesh_State(&m); + i = (int)(((size_t)brush) / sizeof(colbrushf_t)); + GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f); + GL_LockArrays(0, brush->numpoints); + R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements); + GL_LockArrays(0, 0); +} + +static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface) +{ + int i; + rmeshstate_t m; + if (!surface->mesh.num_collisiontriangles) + return; + memset(&m, 0, sizeof(m)); + m.pointer_vertex = surface->mesh.data_collisionvertex3f; + R_Mesh_State(&m); + i = (int)(((size_t)surface) / sizeof(msurface_t)); + GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f); + GL_LockArrays(0, surface->mesh.num_collisionvertices); + R_Mesh_Draw(surface->mesh.num_collisionvertices, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i); + GL_LockArrays(0, 0); +} + void R_WorldVisibility(void) { int i, j, *mark; @@ -1424,6 +2734,24 @@ void R_Q1BSP_Draw(entity_render_t *ent) c_bmodels++; if (r_drawcollisionbrushes.integer < 2) R_DrawSurfaces(ent, false); + if (r_drawcollisionbrushes.integer >= 1 && ent->model->brush.num_brushes) + { + int i; + model_t *model = ent->model; + msurface_t *surface; + q3mbrush_t *brush; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthMask(false); + GL_DepthTest(true); + qglPolygonOffset(r_drawcollisionbrushes_polygonfactor.value, r_drawcollisionbrushes_polygonoffset.value); + for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) + if (brush->colbrushf && brush->colbrushf->numtriangles) + R_DrawCollisionBrush(brush->colbrushf); + for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++) + if (surface->mesh.num_collisiontriangles) + R_DrawCollisionSurface(ent, surface); + qglPolygonOffset(0, 0); + } } void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer) @@ -1486,14 +2814,15 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa if (!CHECKPVSBIT(outsurfacepvs, surfaceindex)) { surface = model->brush.data_surfaces + surfaceindex; - if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs) && ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) && !surface->texture->skin.fog) + if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs)) + if ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) { for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3) { v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3; v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3; v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3; - if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + if (lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) { SETPVSBIT(outsurfacepvs, surfaceindex); outsurfacelist[outnumsurfaces++] = surfaceindex; @@ -1528,9 +2857,15 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, { R_Mesh_Matrix(&ent->matrix); R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + if (!r_shadow_compilingrtlight) + R_UpdateAllTextureInfo(ent); for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { surface = model->brush.data_surfaces + surfacelist[surfacelistindex]; + if ((surface->texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL) + continue; + if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + continue; R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->mesh.num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs); } R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + r_shadow_projectdistance.value, numshadowmark, shadowmarklist); @@ -1551,6 +2886,8 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { surface = model->brush.data_surfaces + surfacelist[surfacelistindex]; + if (surface->texture->basematerialflags & MATERIALFLAG_NODRAW || !surface->mesh.num_triangles) + continue; if (r_shadow_compilingrtlight) { // if compiling an rtlight, capture the mesh @@ -1563,156 +2900,23 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t t = surface->texture->currentframe; // FIXME: transparent surfaces need to be lit later if ((t->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) - R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale); - } - } - } -} - -void R_DrawCollisionBrush(colbrushf_t *brush) -{ - int i; - rmeshstate_t m; - memset(&m, 0, sizeof(m)); - m.pointer_vertex = brush->points->v; - R_Mesh_State(&m); - i = (int)(((size_t)brush) / sizeof(colbrushf_t)); - GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f); - GL_LockArrays(0, brush->numpoints); - R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface) -{ - int i; - rmeshstate_t m; - if (!surface->mesh.num_collisiontriangles) - return; - memset(&m, 0, sizeof(m)); - m.pointer_vertex = surface->mesh.data_collisionvertex3f; - R_Mesh_State(&m); - i = (int)(((size_t)surface) / sizeof(msurface_t)); - GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f); - GL_LockArrays(0, surface->mesh.num_collisionvertices); - R_Mesh_Draw(surface->mesh.num_collisionvertices, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i); - GL_LockArrays(0, 0); -} - -void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int surfacenumber) -{ - const entity_render_t *ent = voident; - msurface_t *surface = ent->model->brush.data_surfaces + surfacenumber; - rmeshstate_t m; - R_Mesh_Matrix(&ent->matrix); - memset(&m, 0, sizeof(m)); - if ((ent->effects & EF_ADDITIVE) || (surface->texture->textureflags & Q3TEXTUREFLAG_ADDITIVE)) - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); - else - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GL_DepthMask(false); - GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); - m.tex[0] = R_GetTexture(surface->texture->skin.base); - m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f; - // LordHavoc: quake3 was not able to do this; lit transparent surfaces - if (gl_combine.integer) - { - m.texrgbscale[0] = 2; - if (r_textureunits.integer >= 2) - { - m.tex[1] = R_GetTexture(surface->lightmaptexture); - m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f; - GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha); - } - else - { - if (ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1 && ent->alpha == 1) - m.pointer_color = surface->mesh.data_lightmapcolor4f; - else - { - int i; - for (i = 0;i < surface->mesh.num_vertices;i++) { - varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * ent->colormod[0]; - varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * ent->colormod[1]; - varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * ent->colormod[2]; - varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3] * ent->alpha; + if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglDisable(GL_CULL_FACE); + R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale); + if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglEnable(GL_CULL_FACE); } - m.pointer_color = varray_color4f; - } - } - } - else - { - int i; - for (i = 0;i < surface->mesh.num_vertices;i++) - { - varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * ent->colormod[0] * 2.0f; - varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * ent->colormod[1] * 2.0f; - varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * ent->colormod[2] * 2.0f; - varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3] * ent->alpha; - } - m.pointer_color = varray_color4f; - } - if (surface->texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) - { - int i, j; - float center[3], center2[3], forward[3], right[3], up[3], v[4][3]; - matrix4x4_t matrix1, imatrix1; - R_Mesh_Matrix(&r_identitymatrix); - // a single autosprite surface can contain multiple sprites... - for (j = 0;j < surface->mesh.num_vertices - 3;j += 4) - { - VectorClear(center); - for (i = 0;i < 4;i++) - VectorAdd(center, surface->mesh.data_vertex3f + (j+i) * 3, center); - VectorScale(center, 0.25f, center); - Matrix4x4_Transform(&ent->matrix, center, center2); - // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out? - Matrix4x4_FromVectors(&matrix1, surface->mesh.data_normal3f + j*3, surface->mesh.data_svector3f + j*3, surface->mesh.data_tvector3f + j*3, center); - Matrix4x4_Invert_Simple(&imatrix1, &matrix1); - for (i = 0;i < 4;i++) - Matrix4x4_Transform(&imatrix1, surface->mesh.data_vertex3f + (j+i)*3, v[i]); - if (surface->texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2) - { - forward[0] = r_vieworigin[0] - center2[0]; - forward[1] = r_vieworigin[1] - center2[1]; - forward[2] = 0; - VectorNormalize(forward); - right[0] = forward[1]; - right[1] = -forward[0]; - right[2] = 0; - up[0] = 0; - up[1] = 0; - up[2] = 1; - } - else - { - VectorCopy(r_viewforward, forward); - VectorCopy(r_viewright, right); - VectorCopy(r_viewup, up); } - for (i = 0;i < 4;i++) - VectorMAMAMAM(1, center2, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (i+j) * 3); } - m.pointer_vertex = varray_vertex3f; } - else - m.pointer_vertex = surface->mesh.data_vertex3f; - R_Mesh_State(&m); - if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) - qglDisable(GL_CULL_FACE); - GL_LockArrays(0, surface->mesh.num_vertices); - R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i); - GL_LockArrays(0, 0); - if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) - qglEnable(GL_CULL_FACE); } +#if 0 void R_Q3BSP_DrawFaceList(entity_render_t *ent, texture_t *t, int texturenumsurfaces, msurface_t **texturesurfacelist) { int i, texturesurfaceindex; - vec3_t modelorg; + vec3_t tempcenter, center, modelorg; msurface_t *surface; qboolean dolightmap; qboolean dobase; @@ -1756,18 +2960,17 @@ void R_Q3BSP_DrawFaceList(entity_render_t *ent, texture_t *t, int texturenumsurf // transparent surfaces get sorted for later drawing if ((t->surfaceparms & Q3SURFACEPARM_TRANS) || ent->alpha < 1 || (ent->effects & EF_ADDITIVE)) { - vec3_t facecenter, center; // drawing sky transparently would be too difficult if (t->surfaceparms & Q3SURFACEPARM_SKY) return; for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { surface = texturesurfacelist[texturesurfaceindex]; - facecenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f; - facecenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f; - facecenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f; - Matrix4x4_Transform(&ent->matrix, facecenter, center); - R_MeshQueue_AddTransparent(center, R_Q3BSP_DrawFace_TransparentCallback, ent, surface - ent->model->brush.data_surfaces); + 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(center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces); } return; } @@ -2084,7 +3287,21 @@ void R_Q3BSP_DrawFaces(entity_render_t *ent, int skyfaces) { if (!surface->mesh.num_triangles) continue; - surfacelist[numsurfaces++] = surface; + if (t->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + { + // drawing sky transparently would be too difficult + if (!(t->currentmaterialflags & MATERIALFLAG_SKY)) + { + vec3_t tempcenter, center; + 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(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces); + } + } + else + surfacelist[numsurfaces++] = surface; if (numsurfaces >= maxfaces) { R_Q3BSP_DrawFaceList(ent, t, numsurfaces, surfacelist); @@ -2126,172 +3343,7 @@ void R_Q3BSP_Draw(entity_render_t *ent) qglPolygonOffset(0, 0); } } - -void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer) -{ - model_t *model = ent->model; - vec3_t lightmins, lightmaxs; - int t, leafindex, leafsurfaceindex, surfaceindex, triangleindex, outnumclusters = 0, outnumsurfaces = 0; - const int *e; - const float *v[3]; - msurface_t *surface; - mleaf_t *leaf; - const qbyte *pvs; - lightmins[0] = relativelightorigin[0] - lightradius; - lightmins[1] = relativelightorigin[1] - lightradius; - lightmins[2] = relativelightorigin[2] - lightradius; - lightmaxs[0] = relativelightorigin[0] + lightradius; - lightmaxs[1] = relativelightorigin[1] + lightradius; - lightmaxs[2] = relativelightorigin[2] + lightradius; - *outnumclusterspointer = 0; - *outnumsurfacespointer = 0; - memset(outclusterpvs, 0, model->brush.num_pvsclusterbytes); - memset(outsurfacepvs, 0, (model->nummodelsurfaces + 7) >> 3); - if (model == NULL) - { - VectorCopy(lightmins, outmins); - VectorCopy(lightmaxs, outmaxs); - return; - } - VectorCopy(relativelightorigin, outmins); - VectorCopy(relativelightorigin, outmaxs); - if (model->brush.GetPVS) - pvs = model->brush.GetPVS(model, relativelightorigin); - else - pvs = NULL; - // FIXME: use BSP recursion as lights are often small - for (leafindex = 0, leaf = model->brush.data_leafs;leafindex < model->brush.num_leafs;leafindex++, leaf++) - { - if (BoxesOverlap(lightmins, lightmaxs, leaf->mins, leaf->maxs) && (pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex))) - { - outmins[0] = min(outmins[0], leaf->mins[0]); - outmins[1] = min(outmins[1], leaf->mins[1]); - outmins[2] = min(outmins[2], leaf->mins[2]); - outmaxs[0] = max(outmaxs[0], leaf->maxs[0]); - outmaxs[1] = max(outmaxs[1], leaf->maxs[1]); - outmaxs[2] = max(outmaxs[2], leaf->maxs[2]); - if (outclusterpvs) - { - if (!CHECKPVSBIT(outclusterpvs, leaf->clusterindex)) - { - SETPVSBIT(outclusterpvs, leaf->clusterindex); - outclusterlist[outnumclusters++] = leaf->clusterindex; - } - } - if (outsurfacepvs) - { - for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++) - { - surfaceindex = leaf->firstleafsurface[leafsurfaceindex]; - surface = model->brush.data_surfaces + surfaceindex; - if (!CHECKPVSBIT(outsurfacepvs, surfaceindex)) - { - if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs) && !(surface->texture->surfaceparms & Q3SURFACEPARM_TRANS) && !(surface->texture->surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NODRAW)) && surface->mesh.num_triangles) - { - if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) - { - for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3) - { - v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3; - v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3; - v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3; - if (lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) - { - SETPVSBIT(outsurfacepvs, surfaceindex); - outsurfacelist[outnumsurfaces++] = surfaceindex; - break; - } - } - } - else - { - for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3) - { - v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3; - v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3; - v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3; - if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) - { - SETPVSBIT(outsurfacepvs, surfaceindex); - outsurfacelist[outnumsurfaces++] = surfaceindex; - break; - } - } - } - } - } - } - } - } - } - - // limit combined leaf box to light boundaries - outmins[0] = max(outmins[0], lightmins[0]); - outmins[1] = max(outmins[1], lightmins[1]); - outmins[2] = max(outmins[2], lightmins[2]); - outmaxs[0] = min(outmaxs[0], lightmaxs[0]); - outmaxs[1] = min(outmaxs[1], lightmaxs[1]); - outmaxs[2] = min(outmaxs[2], lightmaxs[2]); - - *outnumclusterspointer = outnumclusters; - *outnumsurfacespointer = outnumsurfaces; -} - -void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs) -{ - model_t *model = ent->model; - msurface_t *surface; - int surfacelistindex; - if (r_drawcollisionbrushes.integer < 2) - { - R_Mesh_Matrix(&ent->matrix); - R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); - for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) - { - surface = model->brush.data_surfaces + surfacelist[surfacelistindex]; - // FIXME: check some manner of surface->rendermode here? - if (!(surface->texture->surfaceflags & Q3SURFACEFLAG_NODRAW) && !(surface->texture->surfaceparms & (Q3SURFACEPARM_SKY | Q3SURFACEPARM_TRANS)) && !(surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)) - R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->mesh.num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs); - } - R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + r_shadow_projectdistance.value, numshadowmark, shadowmarklist); - } -} - -void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist) -{ - model_t *model = ent->model; - vec3_t lightmins, lightmaxs, modelorg; - msurface_t *surface; - int surfacelistindex; - if (r_drawcollisionbrushes.integer < 2) - { - lightmins[0] = relativelightorigin[0] - lightradius; - lightmins[1] = relativelightorigin[1] - lightradius; - lightmins[2] = relativelightorigin[2] - lightradius; - lightmaxs[0] = relativelightorigin[0] + lightradius; - lightmaxs[1] = relativelightorigin[1] + lightradius; - lightmaxs[2] = relativelightorigin[2] + lightradius; - R_Mesh_Matrix(&ent->matrix); - Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); - for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) - { - surface = model->brush.data_surfaces + surfacelist[surfacelistindex]; - if (r_shadow_compilingrtlight) - { - // if compiling an rtlight, capture the mesh - Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, surface->mesh.num_triangles, surface->mesh.data_element3i); - } - else if ((ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]]) && !(surface->texture->surfaceflags & Q3SURFACEFLAG_NODRAW) && surface->mesh.num_triangles) - { - if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) - qglDisable(GL_CULL_FACE); - R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, surface->texture->skin.base, surface->texture->skin.nmap, surface->texture->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale); - if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) - qglEnable(GL_CULL_FACE); - } - } - } -} +#endif #if 0 static void gl_surf_start(void) @@ -2309,10 +3361,12 @@ static void gl_surf_newmap(void) void GL_Surf_Init(void) { +#ifdef LHREMOVESOON int i; dlightdivtable[0] = 4194304; for (i = 1;i < 32768;i++) dlightdivtable[i] = 4194304 / (i << 7); +#endif Cvar_RegisterVariable(&r_ambient); Cvar_RegisterVariable(&r_drawportals); diff --git a/model_alias.c b/model_alias.c index cea654b3..86b5e64a 100644 --- a/model_alias.c +++ b/model_alias.c @@ -296,7 +296,7 @@ void Mod_BuildAliasSkinFromSkinFrame(aliasskin_t *skin, skinframe_t *skinframe) { skinframe = &missingskinframe; memset(skinframe, 0, sizeof(*skinframe)); - skinframe->base = r_notexture; + skinframe->base = r_texture_notexture; } memset(&mod_alias_layersbuffer, 0, sizeof(mod_alias_layersbuffer)); diff --git a/model_brush.c b/model_brush.c index 99088440..bd238e48 100644 --- a/model_brush.c +++ b/model_brush.c @@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "wad.h" -// note: model_shared.c sets up r_notexture, and r_surf_notexture - qbyte mod_q1bsp_novis[(MAX_MAP_LEAFS + 7)/ 8]; //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"}; @@ -1008,7 +1006,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) strcpy(tx->name, "NO TEXTURE FOUND"); tx->width = 16; tx->height = 16; - tx->skin.base = r_notexture; + tx->skin.base = r_texture_notexture; if (i == loadmodel->brush.num_textures - 1) { tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES; @@ -1092,7 +1090,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } else { - if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true, true)) + if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*', true)) { // did not find external texture, load it from the bsp or wad3 if (loadmodel->brush.ishlbsp) @@ -1127,7 +1125,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) Mem_Free(freepixels); } else if (mtdata) // texture included - Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height); + Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*', tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height); } } if (tx->skin.base == NULL) @@ -1135,7 +1133,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) // no texture found tx->width = 16; tx->height = 16; - tx->skin.base = r_notexture; + tx->skin.base = r_texture_notexture; } tx->basematerialflags = 0; @@ -1895,13 +1893,22 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) surface->lightmaptexture = NULL; i = LittleLong(in->lightofs); if (i == -1) + { surface->samples = NULL; + // give non-lightmapped water a 1x white lightmap + if ((surface->texture->basematerialflags & MATERIALFLAG_WATER) && (surface->texinfo->flags & TEX_SPECIAL) && ssize <= 256 && tsize <= 256) + { + surface->samples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); + surface->styles[0] = 0; + memset(surface->samples, 128, ssize * tsize * 3); + } + } else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30) surface->samples = loadmodel->brushq1.lightdata + i; else // LordHavoc: white lighting (bsp version 29) surface->samples = loadmodel->brushq1.lightdata + (i * 3); - if (surface->texture->basematerialflags & MATERIALFLAG_WALL) + if (!(surface->texinfo->flags & TEX_SPECIAL) || surface->samples) { int i, iu, iv; float u, v, ubase, vbase, uscale, vscale; @@ -3854,11 +3861,13 @@ parseerror: //if (R_TextureHasAlpha(out->skin.base)) // out->surfaceparms |= Q3SURFACEPARM_TRANS; } - if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true)) - if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true)) + if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, false, true)) + if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, false, true)) Con_Printf("%s: texture loading for shader \"%s\" failed (first layer \"%s\" not found either)\n", loadmodel->name, out->name, out->firstpasstexturename); if (out->skin.fog) out->basematerialflags |= (MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT); + // no animation + out->currentframe = out; } if (c) Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c); @@ -4395,6 +4404,11 @@ static void Mod_Q3BSP_LoadFaces(lump_t *l) out->maxs[1] += 1.0f; out->maxs[2] += 1.0f; } + // set lightmap styles for consistency with q1bsp + out->styles[0] = 0; + out->styles[1] = 255; + out->styles[2] = 255; + out->styles[3] = 255; } } @@ -5358,11 +5372,6 @@ void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node) loadmodel->brush.num_leafs = numleafs; } -extern void R_Q3BSP_DrawSky(struct entity_render_s *ent); -extern void R_Q3BSP_Draw(struct entity_render_s *ent); -extern void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer); -extern void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs); -extern void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist); void Mod_Q3BSP_Load(model_t *mod, void *buffer) { int i, j, numshadowmeshtriangles; @@ -5392,11 +5401,10 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) mod->brush.BoxTouchingVisibleLeafs = Mod_Q1BSP_BoxTouchingVisibleLeafs; mod->brush.LightPoint = Mod_Q3BSP_LightPoint; mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation; - //mod->DrawSky = R_Q3BSP_DrawSky; - mod->Draw = R_Q3BSP_Draw; - mod->GetLightInfo = R_Q3BSP_GetLightInfo; - mod->DrawShadowVolume = R_Q3BSP_DrawShadowVolume; - mod->DrawLight = R_Q3BSP_DrawLight; + mod->Draw = R_Q1BSP_Draw; + mod->GetLightInfo = R_Q1BSP_GetLightInfo; + mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume; + mod->DrawLight = R_Q1BSP_DrawLight; mod_base = (qbyte *)header; @@ -5501,7 +5509,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer) if (mod->brush.data_surfaces[j + mod->firstmodelsurface].texture->surfaceflags & Q3SURFACEFLAG_SKY) break; if (j < mod->nummodelsurfaces) - mod->DrawSky = R_Q3BSP_DrawSky; + mod->DrawSky = R_Q1BSP_DrawSky; } } diff --git a/model_brush.h b/model_brush.h index 6484ccf8..44ecdc38 100644 --- a/model_brush.h +++ b/model_brush.h @@ -181,11 +181,13 @@ typedef struct msurface_s int extents[2]; // q1bsp // if lightmap settings changed, this forces update int cached_dlight; // q1bsp +#ifdef LHREMOVESOON // if this == r_framecount there are dynamic lights on the surface int dlightframe; // q1bsp // which dynamic lights are touching this surface // (only access this if dlightframe is current) int dlightbits[8]; // q1bsp +#endif struct q3deffect_s *effect; // q3bsp // FIXME: collisionmarkframe should be kept in a separate array @@ -307,9 +309,6 @@ typedef struct mlight_s } mlight_t; -extern rtexture_t *r_notexture; -extern texture_t r_notexture_mip; - struct model_s; void Mod_Q1BSP_Load(struct model_s *mod, void *buffer); void Mod_IBSP_Load(struct model_s *mod, void *buffer); diff --git a/model_shared.c b/model_shared.c index e456f02b..34859f8c 100644 --- a/model_shared.c +++ b/model_shared.c @@ -35,7 +35,7 @@ model_t *loadmodel; static model_t mod_known[MAX_MOD_KNOWN]; rtexturepool_t *mod_shared_texturepool; -rtexture_t *r_notexture; +rtexture_t *r_texture_notexture; rtexture_t *mod_shared_detailtextures[NUM_DETAILTEXTURES]; rtexture_t *mod_shared_distorttexture[64]; @@ -136,36 +136,8 @@ void Mod_BuildDistortTexture (void) return; } -texture_t r_surf_notexture; - void Mod_SetupNoTexture(void) { - int x, y; - qbyte pix[16][16][4]; - - // this makes a light grey/dark grey checkerboard texture - for (y = 0;y < 16;y++) - { - for (x = 0;x < 16;x++) - { - if ((y < 8) ^ (x < 8)) - { - pix[y][x][0] = 128; - pix[y][x][1] = 128; - pix[y][x][2] = 128; - pix[y][x][3] = 255; - } - else - { - pix[y][x][0] = 64; - pix[y][x][1] = 64; - pix[y][x][2] = 64; - pix[y][x][3] = 255; - } - } - } - - r_notexture = R_LoadTexture2D(mod_shared_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL); } static void mod_start(void) diff --git a/model_shared.h b/model_shared.h index b7c33bbd..136cf854 100644 --- a/model_shared.h +++ b/model_shared.h @@ -431,7 +431,7 @@ model_t; //============================================================================ // this can be used for anything without a valid texture -extern rtexture_t *r_notexture; +extern rtexture_t *r_texture_notexture; #define NUM_DETAILTEXTURES 1 extern rtexture_t *mod_shared_detailtextures[NUM_DETAILTEXTURES]; // every texture must be in a pool... diff --git a/r_light.c b/r_light.c index 272eed2a..4e7d51fa 100644 --- a/r_light.c +++ b/r_light.c @@ -161,6 +161,7 @@ void R_DrawCoronas(void) } } +#ifdef LHREMOVESOON /* ============================================================================= @@ -177,7 +178,7 @@ static qbyte lightpvs[(MAX_MAP_LEAFS+7)>>3]; R_MarkLights ============= */ -static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, dlight_t *light, int bit, int bitindex, mnode_t *node, qbyte *pvs, int pvsbits) +static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, vec3_t lightmins, vec3_t lightmaxs, dlight_t *light, int bit, int bitindex, mnode_t *node, qbyte *pvs, int pvsbits) { int i; mleaf_t *leaf; @@ -192,7 +193,7 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, dlig else { if (dist >= -light->rtlight.lightmap_cullradius) - R_RecursiveMarkLights(ent, lightorigin, light, bit, bitindex, node->children[0], pvs, pvsbits); + R_RecursiveMarkLights(ent, lightorigin, lightmins, lightmaxs, light, bit, bitindex, node->children[0], pvs, pvsbits); node = node->children[1]; } } @@ -209,36 +210,44 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, dlig maxdist = light->rtlight.lightmap_cullradius2; for (i = 0;i < leaf->numleafsurfaces;i++) { - if (ent == r_refdef.worldentity && !r_worldsurfacevisible[leaf->firstleafsurface[i]]) + // note: this is only called on the worldmodel + if (r_worldsurfacevisible[leaf->firstleafsurface[i]]) continue; surface = ent->model->brush.data_surfaces + leaf->firstleafsurface[i]; - VectorCopy(surface->mesh.data_normal3f, planenormal); - planedist = DotProduct(surface->mesh.data_vertex3f, surface->mesh.data_normal3f); - dist = sdist = DotProduct(lightorigin, planenormal) - planedist; - - if (dist < -0.25f && !(surface->texture->currentmaterialflags & MATERIALFLAG_LIGHTBOTHSIDES)) + if (!BoxesOverlap(surface->mins, surface->maxs, lightmins, lightmaxs)) continue; - dist2 = dist * dist; - if (dist2 >= maxdist) - continue; + // do q1bsp culling checks only if it is a q1bsp surface + if (surface->samples && surface->texinfo) + { + VectorNegate(surface->mesh.data_normal3f, planenormal); + planedist = DotProduct(surface->mesh.data_vertex3f, planenormal); + dist = sdist = DotProduct(lightorigin, planenormal) - planedist; - VectorCopy(lightorigin, impact); - VectorMA(impact, -sdist, planenormal, impact); + if (dist < -0.25f && !(surface->texture->currentmaterialflags & MATERIALFLAG_LIGHTBOTHSIDES)) + continue; - impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0]; + dist2 = dist * dist; + if (dist2 >= maxdist) + continue; - d = bound(0, impacts, surface->extents[0] + 16) - impacts; - dist2 += d * d; - if (dist2 > maxdist) - continue; + VectorCopy(lightorigin, impact); + VectorMA(impact, -sdist, planenormal, impact); - impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1]; + impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0]; - d = bound(0, impactt, surface->extents[1] + 16) - impactt; - dist2 += d * d; - if (dist2 > maxdist) - continue; + d = bound(0, impacts, surface->extents[0] + 16) - impacts; + dist2 += d * d; + if (dist2 > maxdist) + continue; + + impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1]; + + d = bound(0, impactt, surface->extents[1] + 16) - impactt; + dist2 += d * d; + if (dist2 > maxdist) + continue; + } if (surface->dlightframe != r_framecount) // not dynamic until now { @@ -253,9 +262,9 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, dlig void R_MarkLights(entity_render_t *ent) { - int i, bit, bitindex; + int i, j, bit, bitindex; dlight_t *light; - vec3_t lightorigin; + vec3_t lightorigin, lightmins, lightmaxs; if (!gl_flashblend.integer && r_dynamic.integer && ent->model && ent->model->brush.num_leafs) { for (i = 0, light = r_dlight;i < r_numdlights;i++, light++) @@ -263,13 +272,40 @@ void R_MarkLights(entity_render_t *ent) bit = 1 << (i & 31); bitindex = i >> 5; Matrix4x4_Transform(&ent->inversematrix, light->origin, lightorigin); - lightpvsbytes = 0; - if (r_vismarklights.integer && ent->model->brush.FatPVS) - lightpvsbytes = ent->model->brush.FatPVS(ent->model, lightorigin, 0, lightpvs, sizeof(lightpvs)); - R_RecursiveMarkLights(ent, lightorigin, light, bit, bitindex, ent->model->brush.data_nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brush.num_pvsclusters)); + lightmins[0] = lightorigin[0] - light->rtlight.lightmap_cullradius; + lightmins[1] = lightorigin[1] - light->rtlight.lightmap_cullradius; + lightmins[2] = lightorigin[2] - light->rtlight.lightmap_cullradius; + lightmaxs[0] = lightorigin[0] + light->rtlight.lightmap_cullradius; + lightmaxs[1] = lightorigin[1] + light->rtlight.lightmap_cullradius; + lightmaxs[2] = lightorigin[2] + light->rtlight.lightmap_cullradius; + if (ent == r_refdef.worldentity) + { + lightpvsbytes = 0; + if (r_vismarklights.integer && ent->model->brush.FatPVS) + lightpvsbytes = ent->model->brush.FatPVS(ent->model, lightorigin, 0, lightpvs, sizeof(lightpvs)); + R_RecursiveMarkLights(ent, lightorigin, lightmins, lightmaxs, light, bit, bitindex, ent->model->brush.data_nodes, lightpvs, min(lightpvsbytes * 8, ent->model->brush.num_pvsclusters)); + } + else + { + msurface_t *surface; + for (j = 0, surface = ent->model->brush.data_surfaces + ent->model->firstmodelsurface;j < ent->model->nummodelsurfaces;j++, surface++) + { + if (BoxesOverlap(surface->mins, surface->maxs, lightmins, lightmaxs)) + { + if (surface->dlightframe != r_framecount) // not dynamic until now + { + surface->dlightbits[0] = surface->dlightbits[1] = surface->dlightbits[2] = surface->dlightbits[3] = surface->dlightbits[4] = surface->dlightbits[5] = surface->dlightbits[6] = surface->dlightbits[7] = 0; + surface->dlightframe = r_framecount; + surface->cached_dlight = true; + } + surface->dlightbits[bitindex] |= bit; + } + } + } } } } +#endif /* ============================================================================= diff --git a/r_light.h b/r_light.h index 5190e001..6020c915 100644 --- a/r_light.h +++ b/r_light.h @@ -6,7 +6,9 @@ extern int r_numdlights; extern dlight_t r_dlight[MAX_DLIGHTS]; void R_UpdateLights(void); +#ifdef LHREMOVESOON void R_MarkLights(entity_render_t *ent); +#endif void R_DrawCoronas(void); void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic, const mleaf_t *leaf); int R_LightModel(float *ambient4f, float *diffusecolor, float *diffusenormal, const entity_render_t *ent, float colorr, float colorg, float colorb, float colora, int worldcoords); diff --git a/r_shadow.c b/r_shadow.c index 0f0bd69b..ee083d24 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -154,11 +154,7 @@ rtexturepool_t *r_shadow_texturepool; rtexture_t *r_shadow_normalcubetexture; rtexture_t *r_shadow_attenuation2dtexture; rtexture_t *r_shadow_attenuation3dtexture; -rtexture_t *r_shadow_blankbumptexture; -rtexture_t *r_shadow_blankglosstexture; -rtexture_t *r_shadow_blankwhitetexture; rtexture_t *r_shadow_blankwhitecubetexture; -rtexture_t *r_shadow_blankblacktexture; // lights are reloaded when this changes char r_shadow_mapname[MAX_QPATH]; @@ -394,11 +390,7 @@ void r_shadow_start(void) r_shadow_normalcubetexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; - r_shadow_blankbumptexture = NULL; - r_shadow_blankglosstexture = NULL; - r_shadow_blankwhitetexture = NULL; r_shadow_blankwhitecubetexture = NULL; - r_shadow_blankblacktexture = NULL; r_shadow_texturepool = NULL; r_shadow_filters_texturepool = NULL; R_Shadow_ValidateCvars(); @@ -503,11 +495,7 @@ void r_shadow_shutdown(void) r_shadow_normalcubetexture = NULL; r_shadow_attenuation2dtexture = NULL; r_shadow_attenuation3dtexture = NULL; - r_shadow_blankbumptexture = NULL; - r_shadow_blankglosstexture = NULL; - r_shadow_blankwhitetexture = NULL; r_shadow_blankwhitecubetexture = NULL; - r_shadow_blankblacktexture = NULL; R_FreeTexturePool(&r_shadow_texturepool); R_FreeTexturePool(&r_shadow_filters_texturepool); maxshadowelements = 0; @@ -955,26 +943,6 @@ static void R_Shadow_MakeTextures(void) #define ATTEN2DSIZE 64 #define ATTEN3DSIZE 32 data = Mem_Alloc(tempmempool, max(6*NORMSIZE*NORMSIZE*4, max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE*4, ATTEN2DSIZE*ATTEN2DSIZE*4))); - data[0] = 128; // normal X - data[1] = 128; // normal Y - data[2] = 255; // normal Z - data[3] = 128; // height - r_shadow_blankbumptexture = R_LoadTexture2D(r_shadow_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); - data[0] = 255; - data[1] = 255; - data[2] = 255; - data[3] = 255; - r_shadow_blankglosstexture = R_LoadTexture2D(r_shadow_texturepool, "blankgloss", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); - data[0] = 255; - data[1] = 255; - data[2] = 255; - data[3] = 255; - r_shadow_blankwhitetexture = R_LoadTexture2D(r_shadow_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); - data[0] = 0; - data[1] = 0; - data[2] = 0; - data[3] = 255; - r_shadow_blankblacktexture = R_LoadTexture2D(r_shadow_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL); r_shadow_blankwhitecubetexture = NULL; r_shadow_normalcubetexture = NULL; if (gl_texturecubemap) @@ -1593,18 +1561,18 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements GL_DepthMask(false); GL_DepthTest(true); if (!bumptexture) - bumptexture = r_shadow_blankbumptexture; + bumptexture = r_texture_blanknormalmap; specularscale *= r_shadow_glossintensity.value; if (!glosstexture) { if (r_shadow_gloss.integer >= 2) { - glosstexture = r_shadow_blankglosstexture; + glosstexture = r_texture_white; specularscale *= r_shadow_gloss2intensity.value; } else { - glosstexture = r_shadow_blankblacktexture; + glosstexture = r_texture_black; specularscale = 0; } } @@ -1629,7 +1597,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements m.tex[2] = R_GetTexture(glosstexture); m.texcubemap[3] = R_GetTexture(lightcubemap); // TODO: support fog (after renderer is converted to texture fog) - m.tex[4] = R_GetTexture(r_shadow_blankwhitetexture); + m.tex[4] = R_GetTexture(r_texture_white); m.texmatrix[3] = *matrix_modeltolight; R_Mesh_State(&m); GL_BlendFunc(GL_ONE, GL_ONE); @@ -1687,9 +1655,9 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements else if (gl_dot3arb && gl_texturecubemap && gl_combine.integer && gl_stencil) { if (!bumptexture) - bumptexture = r_shadow_blankbumptexture; + bumptexture = r_texture_blanknormalmap; if (!glosstexture) - glosstexture = r_shadow_blankglosstexture; + glosstexture = r_texture_white; if (ambientscale) { GL_Color(1,1,1,1); @@ -2145,7 +2113,7 @@ void R_Shadow_RenderLighting(int numverts, int numtriangles, const int *elements } GL_LockArrays(0, 0); } - if (specularscale && glosstexture != r_shadow_blankblacktexture) + if (specularscale && glosstexture != r_texture_black) { // FIXME: detect blendsquare! //if (gl_support_blendsquare) diff --git a/render.h b/render.h index 80f1a2b2..85b927a0 100644 --- a/render.h +++ b/render.h @@ -173,6 +173,11 @@ extern cvar_t gl_dither; #include "r_light.h" +extern rtexture_t *r_texture_blanknormalmap; +extern rtexture_t *r_texture_white; +extern rtexture_t *r_texture_black; +extern rtexture_t *r_texture_notexture; + void R_TimeReport(char *name); void R_TimeReport_Start(void); void R_TimeReport_End(void); -- 2.39.2