X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rsurf.c;h=e21fcc1a7acebbcf2ebdc485ab97d7fa38df0e5b;hb=986e2df5ca730f3984b37805aa48c6359d09f042;hp=be07117ce096a3366b1ecc6e6ee739c88983d029;hpb=855932aeb5707c5efb2858c3e51b913d8203ebbe;p=xonotic%2Fdarkplaces.git diff --git a/gl_rsurf.c b/gl_rsurf.c index be07117c..e21fcc1a 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -20,78 +20,29 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // r_surf.c: surface-related refresh code #include "quakedef.h" +#include "r_shadow.h" +#include "portals.h" + +#define MAX_LIGHTMAP_SIZE 256 + +cvar_t r_ambient = {0, "r_ambient", "0", "brighter world cheat (not allowed in multiplayer), value is 0-128"}; +cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"}; +cvar_t r_lockpvs = {0, "r_lockpvs", "0", "disables pvs switching, allows you to walk around and inspect what is visible from a given location in the map (anything not visible from your current location will not be drawn)"}; +cvar_t r_lockvisibility = {0, "r_lockvisibility", "0", "disables visibility updates, allows you to walk around and inspect what is visible from a given viewpoint in the map (anything offscreen at the moment this is enabled will not be drawn)"}; +cvar_t r_useportalculling = {0, "r_useportalculling", "1", "use advanced portal culling visibility method to improve performance over just Potentially Visible Set, provides an even more significant speed improvement in unvised maps"}; +cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0", "draws sky depth masking in q3 maps (as in q1 maps), this means for example that sky polygons can hide other things"}; + +// flag arrays used for visibility checking on world model +// (all other entities have no per-surface/per-leaf visibility checks) +// TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters +unsigned char r_pvsbits[(32768+7)>>3]; +// TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs +unsigned char r_worldleafvisible[32768]; +// TODO: dynamic resize according to r_refdef.worldmodel->num_surfaces +unsigned char r_worldsurfacevisible[262144]; +// if true, the view is currently in a leaf without pvs data +qboolean r_worldnovis; -extern int skytexturenum; - -int lightmap_textures; - -signed blocklights[18*18*3]; // LordHavoc: *3 for colored lighting - -// LordHavoc: skinny but tall lightmaps for quicker subimage uploads -#define BLOCK_WIDTH 128 -#define BLOCK_HEIGHT 128 -// LordHavoc: increased lightmap limit from 64 to 1024 -#define MAX_LIGHTMAPS 1024 -#define LIGHTMAPSIZE (BLOCK_WIDTH*BLOCK_HEIGHT*4) - -int active_lightmaps; - -short allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; - -byte *lightmaps[MAX_LIGHTMAPS]; -short lightmapupdate[MAX_LIGHTMAPS][2]; - -int lightmapalign, lightmapalignmask; // LordHavoc: NVIDIA's broken subimage fix, see BuildLightmaps for notes -cvar_t gl_lightmapalign = {"gl_lightmapalign", "4"}; -cvar_t gl_lightmaprgba = {"gl_lightmaprgba", "0"}; -cvar_t gl_nosubimagefragments = {"gl_nosubimagefragments", "0"}; -cvar_t gl_nosubimage = {"gl_nosubimage", "0"}; -cvar_t r_ambient = {"r_ambient", "0"}; -cvar_t gl_vertex = {"gl_vertex", "0"}; -cvar_t gl_texsort = {"gl_texsort", "1"}; -//cvar_t gl_funnywalls = {"gl_funnywalls", "0"}; // LordHavoc: see BuildSurfaceDisplayList - -qboolean lightmaprgba, nosubimagefragments, nosubimage, skyisvisible; -int lightmapbytes; - -extern qboolean gl_arrays; - -extern int r_dlightframecount; - -void gl_surf_start() -{ -} - -void gl_surf_shutdown() -{ -} - -void GL_Surf_Init() -{ - int i; - for (i = 0;i < MAX_LIGHTMAPS;i++) - lightmaps[i] = NULL; - Cvar_RegisterVariable(&gl_lightmapalign); - Cvar_RegisterVariable(&gl_lightmaprgba); - Cvar_RegisterVariable(&gl_nosubimagefragments); - Cvar_RegisterVariable(&gl_nosubimage); - Cvar_RegisterVariable(&r_ambient); -// Cvar_RegisterVariable(&gl_funnywalls); - Cvar_RegisterVariable(&gl_vertex); - Cvar_RegisterVariable(&gl_texsort); - // check if it's the glquake minigl driver - if (strncasecmp(gl_vendor,"3Dfx",4)==0) - if (!gl_arrays) - { -// Cvar_SetValue("gl_nosubimagefragments", 1); -// Cvar_SetValue("gl_nosubimage", 1); - Cvar_SetValue("gl_lightmode", 0); - } - - R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown); -} - -extern qboolean lighthalf; /* =============== R_BuildLightMap @@ -99,203 +50,282 @@ R_BuildLightMap Combine and scale multiple lightmaps into the 8.8 format in blocklights =============== */ -void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) +void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface) { - int smax, tmax; - int t; - int i, j, size; - byte *lightmap; - int scale; - int maps; - int *bl; - - surf->cached_lighthalf = lighthalf; - surf->cached_ambient = r_ambient.value; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; + int smax, tmax, i, size, size3, maps, l; + int *bl, scale; + unsigned char *lightmap, *out, *stain; + model_t *model = ent->model; + static int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting + static unsigned char templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4]; + + // update cached lighting info + surface->cached_dlight = 0; + + smax = (surface->lightmapinfo->extents[0]>>4)+1; + tmax = (surface->lightmapinfo->extents[1]>>4)+1; size = smax*tmax; - lightmap = surf->samples; + size3 = size*3; + lightmap = surface->lightmapinfo->samples; // set to full bright if no light data - if (currententity->effects & EF_FULLBRIGHT || !cl.worldmodel->lightdata) + bl = intblocklights; + if (!model->brushq1.lightdata) { - bl = blocklights; - for (i=0 ; istyles[maps] != 255;maps++) - { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - bl = blocklights; - for (i=0 ; ilightmapinfo->styles[maps] != 255;maps++, lightmap += size3) + for (scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++) + bl[i] += lightmap[i] * scale; } - stride -= (smax*lightmapbytes); - bl = blocklights; - if (lighthalf) + + stain = surface->lightmapinfo->stainsamples; + bl = intblocklights; + out = templight; + // the >> 16 shift adjusts down 8 bits to account for the stainmap + // scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will + // be doubled during rendering to achieve 2x overbright + // (0 = 0.0, 128 = 1.0, 256 = 2.0) + if (model->brushq1.lightmaprgba) { - // LordHavoc: I shift down by 8 unlike GLQuake's 7, - // the image is brightened as a processing pass - if (lightmaprgba) + for (i = 0;i < size;i++) { - for (i=0 ; i> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - *dest++ = 255; - } - } + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + *out++ = 255; } - else + } + else + { + for (i = 0;i < size;i++) { - for (i=0 ; i> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 8;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - } - } + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); } } - else + + R_UpdateTexture(surface->lightmaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax); + + // update the surface's deluxemap if it has one + if (surface->deluxemaptexture != r_texture_blanknormalmap) { - if (lightmaprgba) + vec3_t n; + unsigned char *normalmap = surface->lightmapinfo->nmapsamples; + lightmap = surface->lightmapinfo->samples; + // clear to no normalmap + bl = intblocklights; + memset(bl, 0, size3*sizeof(*bl)); + // add all the normalmaps + if (lightmap && normalmap) { - for (i=0 ; ilightmapinfo->styles[maps] != 255;maps++, lightmap += size3, normalmap += size3) { - for (j=0 ; jlightmapinfo->styles[maps]], i = 0;i < size;i++) { - t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - *dest++ = 255; + // add the normalmap with weighting proportional to the style's lightmap intensity + l = (int)(VectorLength(lightmap + i*3) * scale); + bl[i*3+0] += ((int)normalmap[i*3+0] - 128) * l; + bl[i*3+1] += ((int)normalmap[i*3+1] - 128) * l; + bl[i*3+2] += ((int)normalmap[i*3+2] - 128) * l; } } } + bl = intblocklights; + out = templight; + // we simply renormalize the weighted normals to get a valid deluxemap + if (model->brushq1.lightmaprgba) + { + for (i = 0;i < size;i++, bl += 3) + { + VectorCopy(bl, n); + VectorNormalize(n); + l = (int)(n[0] * 128 + 128);*out++ = bound(0, l, 255); + l = (int)(n[1] * 128 + 128);*out++ = bound(0, l, 255); + l = (int)(n[2] * 128 + 128);*out++ = bound(0, l, 255); + *out++ = 255; + } + } else { - for (i=0 ; i> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - t = *bl++ >> 7;if (t > 255) t = 255;else if (t < 0) t = 0;*dest++ = t; - } + VectorCopy(bl, n); + VectorNormalize(n); + l = (int)(n[0] * 128 + 128);*out++ = bound(0, l, 255); + l = (int)(n[1] * 128 + 128);*out++ = bound(0, l, 255); + l = (int)(n[2] * 128 + 128);*out++ = bound(0, l, 255); } } + R_UpdateTexture(surface->deluxemaptexture, templight, surface->lightmapinfo->lightmaporigin[0], surface->lightmapinfo->lightmaporigin[1], smax, tmax); } } -byte templight[32*32*4]; - -void R_UpdateLightmap(msurface_t *s, int lnum) +void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8]) { - int smax, tmax; - // upload the new lightmap texture fragment - glBindTexture(GL_TEXTURE_2D, lightmap_textures + lnum); - if (nosubimage || nosubimagefragments) + float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2; + msurface_t *surface, *endsurface; + int i, s, t, smax, tmax, smax3, impacts, impactt, stained; + unsigned char *bl; + vec3_t impact; + + maxdist = radius * radius; + invradius = 1.0f / radius; + +loc0: + if (!node->plane) + return; + ndist = PlaneDiff(origin, node->plane); + if (ndist > radius) { - if (lightmapupdate[lnum][0] > s->light_t) - lightmapupdate[lnum][0] = s->light_t; - if (lightmapupdate[lnum][1] < (s->light_t + ((s->extents[1]>>4)+1))) - lightmapupdate[lnum][1] = (s->light_t + ((s->extents[1]>>4)+1)); - if (lightmaprgba) - R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 4, BLOCK_WIDTH * 4); - else - R_BuildLightMap (s, lightmaps[s->lightmaptexturenum] + (s->light_t * BLOCK_WIDTH + s->light_s) * 3, BLOCK_WIDTH * 3); + node = node->children[0]; + goto loc0; + } + if (ndist < -radius) + { + node = node->children[1]; + goto loc0; + } + + dist2 = ndist * ndist; + maxdist3 = maxdist - dist2; + + if (node->plane->type < 3) + { + VectorCopy(origin, impact); + impact[node->plane->type] -= ndist; } else { - smax = ((s->extents[0]>>4)+lightmapalign) & lightmapalignmask; - tmax = (s->extents[1]>>4)+1; - if (lightmaprgba) - { - R_BuildLightMap (s, templight, smax * 4); - glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight); - } - else - { - R_BuildLightMap (s, templight, smax * 3); - glTexSubImage2D(GL_TEXTURE_2D, 0, s->light_s, s->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight); - } + impact[0] = origin[0] - node->plane->normal[0] * ndist; + impact[1] = origin[1] - node->plane->normal[1] * ndist; + impact[2] = origin[2] - node->plane->normal[2] * ndist; } -} + for (surface = model->data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++) + { + if (surface->lightmapinfo->stainsamples) + { + smax = (surface->lightmapinfo->extents[0] >> 4) + 1; + tmax = (surface->lightmapinfo->extents[1] >> 4) + 1; -/* -=============== -R_TextureAnimation + impacts = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3] - surface->lightmapinfo->texturemins[0]); + impactt = (int)(DotProduct (impact, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3] - surface->lightmapinfo->texturemins[1]); -Returns the proper texture for a given time and base texture -=============== -*/ -texture_t *R_TextureAnimation (texture_t *base) -{ - texture_t *original; - int relative; - int count; + s = bound(0, impacts, smax * 16) - impacts; + t = bound(0, impactt, tmax * 16) - impactt; + i = (int)(s * s + t * t + dist2); + if (i > maxdist) + continue; - if (currententity->frame) - { - if (base->alternate_anims) - base = base->alternate_anims; - } - - if (!base->anim_total) - return base; + // reduce calculations + for (s = 0, i = impacts; s < smax; s++, i -= 16) + sdtable[s] = i * i + dist2; - original = base; + bl = surface->lightmapinfo->stainsamples; + smax3 = smax * 3; + stained = false; - relative = (int)(cl.time*10) % base->anim_total; + i = impactt; + for (t = 0;t < tmax;t++, i -= 16) + { + td = i * i; + // make sure some part of it is visible on this line + if (td < maxdist3) + { + maxdist2 = maxdist - td; + for (s = 0;s < smax;s++) + { + if (sdtable[s] < maxdist2) + { + ratio = lhrandom(0.0f, 1.0f); + a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius); + if (a >= (1.0f / 64.0f)) + { + if (a > 1) + a = 1; + bl[0] = (unsigned char) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0])); + bl[1] = (unsigned char) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1])); + bl[2] = (unsigned char) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2])); + stained = true; + } + } + bl += 3; + } + } + else // skip line + bl += smax3; + } + // force lightmap upload + if (stained) + surface->cached_dlight = true; + } + } - count = 0; - while (base->anim_min > relative || base->anim_max <= relative) + if (node->children[0]->plane) { - base = base->anim_next; - if (!base) + if (node->children[1]->plane) { - Con_Printf("R_TextureAnimation: broken cycle"); - return original; + R_StainNode(node->children[0], model, origin, radius, fcolor); + node = node->children[1]; + goto loc0; } - if (++count > 100) + else { - Con_Printf("R_TextureAnimation: infinite cycle"); - return original; + node = node->children[0]; + goto loc0; } } + else if (node->children[1]->plane) + { + node = node->children[1]; + goto loc0; + } +} - return base; +void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2) +{ + int n; + float fcolor[8]; + entity_render_t *ent; + model_t *model; + vec3_t org; + if (r_refdef.worldmodel == NULL || !r_refdef.worldmodel->brush.data_nodes || !r_refdef.worldmodel->brushq1.lightdata) + return; + fcolor[0] = cr1; + fcolor[1] = cg1; + fcolor[2] = cb1; + fcolor[3] = ca1 * (1.0f / 64.0f); + fcolor[4] = cr2 - cr1; + fcolor[5] = cg2 - cg1; + fcolor[6] = cb2 - cb1; + fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f); + + R_StainNode(r_refdef.worldmodel->brush.data_nodes + r_refdef.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.worldmodel, origin, radius, fcolor); + + // look for embedded bmodels + for (n = 0;n < cl.num_brushmodel_entities;n++) + { + ent = &cl.entities[cl.brushmodel_entities[n]].render; + model = ent->model; + if (model && model->name[0] == '*') + { + if (model->brush.data_nodes) + { + Matrix4x4_Transform(&ent->inversematrix, origin, org); + R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor); + } + } + } } @@ -307,1061 +337,624 @@ texture_t *R_TextureAnimation (texture_t *base) ============================================================= */ - -extern int solidskytexture; -extern int alphaskytexture; -extern float speedscale; // for top sky and bottom sky - -extern char skyname[]; - -void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits); -float turbsin[256] = +static void R_DrawPortal_Callback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) { - #include "gl_warp_sin.h" -}; -#define TURBSCALE (256.0 / (2 * M_PI)) - + const mportal_t *portal = (mportal_t *)ent; + int i, numpoints; + float *v; + float vertex3f[POLYGONELEMENTS_MAXPOINTS*3]; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + GL_DepthTest(true); + qglDisable(GL_CULL_FACE); + R_Mesh_Matrix(&identitymatrix); + + numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS); + + R_Mesh_VertexPointer(vertex3f); + R_Mesh_ColorPointer(NULL); + R_Mesh_ResetTextureState(); + + i = surfacenumber; + GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f), + ((i & 0x0038) >> 3) * (1.0f / 7.0f), + ((i & 0x01C0) >> 6) * (1.0f / 7.0f), + 0.125f); + for (i = 0, v = vertex3f;i < numpoints;i++, v += 3) + VectorCopy(portal->points[i].position, v); + R_Mesh_Draw(0, numpoints, numpoints - 2, polygonelements); + qglEnable(GL_CULL_FACE); +} -void UploadLightmaps() +// LordHavoc: this is just a nice debugging tool, very slow +static void R_DrawPortals(void) { - int i; - if (nosubimage || nosubimagefragments) + int i, leafnum; + mportal_t *portal; + float center[3], f; + model_t *model = r_refdef.worldmodel; + if (model == NULL) + return; + for (leafnum = 0;leafnum < r_refdef.worldmodel->brush.num_leafs;leafnum++) { - for (i = 0;i < MAX_LIGHTMAPS;i++) + if (r_worldleafvisible[leafnum]) { - if (lightmapupdate[i][0] < lightmapupdate[i][1]) + //for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++) + for (portal = r_refdef.worldmodel->brush.data_leafs[leafnum].portals;portal;portal = portal->next) { - glBindTexture(GL_TEXTURE_2D, lightmap_textures + i); - if (nosubimage) + if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS) + if (!R_CullBox(portal->mins, portal->maxs)) { - if (lightmaprgba) - glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]); - else - glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]); - } - else - { - if (lightmaprgba) - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 4 * lightmapupdate[i][0])); - else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lightmapupdate[i][0], BLOCK_WIDTH, lightmapupdate[i][1] - lightmapupdate[i][0], GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i] + (BLOCK_WIDTH * 3 * lightmapupdate[i][0])); + VectorClear(center); + for (i = 0;i < portal->numpoints;i++) + VectorAdd(center, portal->points[i].position, center); + f = ixtable[portal->numpoints]; + VectorScale(center, f, center); + R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, (entity_render_t *)portal, leafnum, r_shadow_rtlight); } } - lightmapupdate[i][0] = BLOCK_HEIGHT; - lightmapupdate[i][1] = 0; } } } -float wvert[1024*6]; // used by the following functions - -void RSurf_DrawSky(msurface_t *s, int transform) +void R_WorldVisibility(void) { - glpoly_t *p; - int i; - float *v; - for (p=s->polys ; p ; p=p->next) + int i, j, *mark; + mleaf_t *leaf; + mleaf_t *viewleaf; + model_t *model = r_refdef.worldmodel; + + if (!model) + return; + + // if possible find the leaf the view origin is in + viewleaf = model->brush.PointInLeaf ? model->brush.PointInLeaf(model, r_vieworigin) : NULL; + // if possible fetch the visible cluster bits + if (!r_lockpvs.integer && model->brush.FatPVS) + model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits)); + + if (!r_lockvisibility.integer) { - if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS) + // clear the visible surface and leaf flags arrays + memset(r_worldsurfacevisible, 0, model->num_surfaces); + memset(r_worldleafvisible, 0, model->brush.num_leafs); + + r_worldnovis = false; + + // if floating around in the void (no pvs data available, and no + // portals available), simply use all on-screen leafs. + if (!viewleaf || viewleaf->clusterindex < 0) { - skypoly[currentskypoly].firstvert = currentskyvert; - skypoly[currentskypoly++].verts = p->numverts; - if (transform) + // no visibility method: (used when floating around in the void) + // simply cull each leaf to the frustum (view pyramid) + // similar to quake's RecursiveWorldNode but without cache misses + r_worldnovis = true; + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) { - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + // if leaf is in current pvs and on the screen, mark its surfaces + if (!R_CullBox(leaf->mins, leaf->maxs)) { - softwaretransform(v, skyvert[currentskyvert].v); - currentskyvert++; + renderstats.world_leafs++; + r_worldleafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_worldsurfacevisible[*mark] = true; } } - else + } + // if the user prefers to disable portal culling (testing?), simply + // use all on-screen leafs that are in the pvs. + else if (!r_useportalculling.integer) + { + // pvs method: + // simply check if each leaf is in the Potentially Visible Set, + // and cull to frustum (view pyramid) + // similar to quake's RecursiveWorldNode but without cache misses + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) { - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + // if leaf is in current pvs and on the screen, mark its surfaces + if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs)) { - skyvert[currentskyvert].v[0] = v[0]; - skyvert[currentskyvert].v[1] = v[1]; - skyvert[currentskyvert++].v[2] = v[2]; + renderstats.world_leafs++; + r_worldleafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_worldsurfacevisible[*mark] = true; } } } - } -} - -int RSurf_Light(int *dlightbits, glpoly_t *polys) -{ - float cr, cg, cb, radius, radius2, f, *v, *wv; - int i, a, b, lit = false; - unsigned int c, d; - dlight_t *light; - vec_t *lightorigin; - glpoly_t *p; - for (a = 0;a < 8;a++) - { - if ((c = dlightbits[a])) + // otherwise use a recursive portal flow, culling each portal to + // frustum and checking if the leaf the portal leads to is in the pvs + else { - for (b = 0, d = 1;c;b++, d <<= 1) + int leafstackpos; + mportal_t *p; + mleaf_t *leafstack[8192]; + // simple-frustum portal method: + // follows portals leading outward from viewleaf, does not venture + // offscreen or into leafs that are not visible, faster than + // Quake's RecursiveWorldNode and vastly better in unvised maps, + // often culls some surfaces that pvs alone would miss + // (such as a room in pvs that is hidden behind a wall, but the + // passage leading to the room is off-screen) + leafstack[0] = viewleaf; + leafstackpos = 1; + while (leafstackpos) { - if (c & d) + renderstats.world_leafs++; + leaf = leafstack[--leafstackpos]; + r_worldleafvisible[leaf - model->brush.data_leafs] = true; + // mark any surfaces bounding this leaf + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_worldsurfacevisible[*mark] = true; + // follow portals into other leafs + // the checks are: + // if viewer is behind portal (portal faces outward into the scene) + // and the portal polygon's bounding box is on the screen + // and the leaf has not been visited yet + // and the leaf is visible in the pvs + // (the first two checks won't cause as many cache misses as the leaf checks) + for (p = leaf->portals;p;p = p->next) { - c -= d; - light = &cl_dlights[a * 32 + b]; - lightorigin = light->origin; - cr = light->color[0]; - cg = light->color[1]; - cb = light->color[2]; - radius = light->radius*light->radius*LIGHTSCALE; - radius2 = radius * (256.0f / LIGHTSCALE); - wv = wvert; - for (p = polys;p;p = p->next) - { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) - { - f = VectorDistance2(wv, lightorigin); - if (f < radius) - { - f = radius2 / (f + LIGHTOFFSET); - wv[3] += cr * f; - wv[4] += cg * f; - wv[5] += cb * f; - lit = true; - } - wv += 6; - } - } + renderstats.world_portals++; + if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex)) + leafstack[leafstackpos++] = p->past; } } } } - return lit; -} - -void RSurf_DrawWater(msurface_t *s, texture_t *t, int transform, int alpha) -{ - int i; - float os = turbsin[(int)(realtime * TURBSCALE) & 255], ot = turbsin[(int)(realtime * TURBSCALE + 96.0) & 255]; - glpoly_t *p; - float *wv, *v; - wv = wvert; - for (p = s->polys;p;p = p->next) - { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) - { - if (transform) - softwaretransform(v, wv); - else - VectorCopy(v, wv); - if (r_waterripple.value) - wv[2] += r_waterripple.value * turbsin[(int)((wv[0]*(1.0f/32.0f)+realtime) * TURBSCALE) & 255] * turbsin[(int)((wv[1]*(1.0f/32.0f)+realtime) * TURBSCALE) & 255] * (1.0f / 64.0f); - wv[3] = wv[4] = wv[5] = 128.0f; - wv += 6; - } - } - if (s->dlightframe == r_dlightframecount && r_dynamic.value) - RSurf_Light(s->dlightbits, s->polys); - wv = wvert; - // FIXME: make fog texture if water texture is transparent? - for (p=s->polys ; p ; p=p->next) - { - transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, TPOLYTYPE_ALPHA); - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6) - transpolyvert(wv[0], wv[1], wv[2], (v[3] + os) * (1.0f/64.0f), (v[4] + ot) * (1.0f/64.0f), wv[3], wv[4], wv[5], alpha); - transpolyend(); - } -} -void RSurf_CheckLightmap(msurface_t *s) -{ - if (r_dynamic.value) - { - if (r_ambient.value != s->cached_ambient || lighthalf != s->cached_lighthalf - || (s->styles[0] != 255 && d_lightstylevalue[s->styles[0]] != s->cached_light[0]) - || (s->styles[1] != 255 && d_lightstylevalue[s->styles[1]] != s->cached_light[1]) - || (s->styles[2] != 255 && d_lightstylevalue[s->styles[2]] != s->cached_light[2]) - || (s->styles[3] != 255 && d_lightstylevalue[s->styles[3]] != s->cached_light[3])) - R_UpdateLightmap(s, s->lightmaptexturenum); - } + if (r_drawportals.integer) + R_DrawPortals(); } -void RSurf_Transform(glpoly_t *p, int transform) +void R_Q1BSP_DrawSky(entity_render_t *ent) { - int i; - float *v, *wv = wvert; - for (;p;p = p->next) - { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) - { - if (transform) - softwaretransform(v, wv); - else - VectorCopy(v, wv); - wv[3] = wv[4] = wv[5] = 0.0f; - wv += 6; - } - } + if (ent->model == NULL) + return; + R_DrawSurfaces(ent, true); } -void RSurf_EmitWallpolys(int lightmap, glpoly_t *p, texture_t *t, int lit) +void R_Q1BSP_Draw(entity_render_t *ent) { - int i; - float *v, *wv = wvert; - wallpoly_t *wp = &wallpoly[currentwallpoly]; - wallvert_t *out = &wallvert[currentwallvert]; - for (;p;p = p->next) - { - if (currentwallpoly >= MAX_WALLPOLYS) - break; - if (currentwallvert+p->numverts > MAX_WALLVERTS) - break; - v = p->verts[0]; - wp->texnum = (unsigned short) t->gl_texturenum; - wp->lighttexnum = (unsigned short) lightmap; - wp->glowtexnum = (unsigned short) t->gl_glowtexturenum; - wp->firstvert = currentwallvert; - wp->numverts = p->numverts; - wp->lit = lit; - wp++; - currentwallpoly++; - currentwallvert += p->numverts; - for (i = 0;i < p->numverts;i++, v += VERTEXSIZE, wv += 6, out++) - { - if (lit) - { - if (lighthalf) - { - out->r = (byte) (bound(0, (int) wv[3] >> 1, 255)); - out->g = (byte) (bound(0, (int) wv[4] >> 1, 255)); - out->b = (byte) (bound(0, (int) wv[5] >> 1, 255)); - out->a = 255; - } - else - { - out->r = (byte) (bound(0, (int) wv[3], 255)); - out->g = (byte) (bound(0, (int) wv[4], 255)); - out->b = (byte) (bound(0, (int) wv[5], 255)); - out->a = 255; - } - } - out->vert[0] = wv[0]; - out->vert[1] = wv[1]; - out->vert[2] = wv[2]; - out->s = v[3]; - out->t = v[4]; - out->u = v[5]; - out->v = v[6]; - } - } + model_t *model = ent->model; + if (model == NULL) + return; + R_DrawSurfaces(ent, false); } -void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform) +typedef struct r_q1bsp_getlightinfo_s { - int lit = false; - // check for lightmap modification - RSurf_CheckLightmap(s); - RSurf_Transform(s->polys, transform); - if (s->dlightframe == r_dlightframecount && r_dynamic.value) - lit = RSurf_Light(s->dlightbits, s->polys); - RSurf_EmitWallpolys(lightmap_textures + s->lightmaptexturenum, s->polys, t, lit); + model_t *model; + vec3_t relativelightorigin; + float lightradius; + int *outleaflist; + unsigned char *outleafpvs; + int outnumleafs; + int *outsurfacelist; + unsigned char *outsurfacepvs; + int outnumsurfaces; + vec3_t outmins; + vec3_t outmaxs; + vec3_t lightmins; + vec3_t lightmaxs; + const unsigned char *pvs; } +r_q1bsp_getlightinfo_t; -// LordHavoc: transparent brush models -extern int r_dlightframecount; -extern float modelalpha; - -void RSurf_EmitWallVertex(glpoly_t *p, texture_t *t, int modulate, int alpha) +void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) { - int i; - float *v, *wv = wvert; - if (modulate) - { - for (;p;p = p->next) + int sides; + mleaf_t *leaf; + for (;;) + { + mplane_t *plane = node->plane; + //if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) + // return; + if (!plane) + break; + if (plane->type < 3) + sides = ((info->lightmaxs[plane->type] >= plane->dist) | ((info->lightmins[plane->type] < plane->dist) << 1)); + else + sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, plane); + if (sides == 3) { - v = p->verts[0]; - transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6) - transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->colormod[0], wv[4] * currententity->colormod[1], wv[5] * currententity->colormod[2], alpha); - transpolyend(); + R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]); + node = node->children[1]; } + else if (sides == 0) + return; // ERROR: NAN bounding box! + else + node = node->children[sides - 1]; } - else + leaf = (mleaf_t *)node; + if (info->pvs == NULL || CHECKPVSBIT(info->pvs, leaf->clusterindex)) { - for (;p;p = p->next) + info->outmins[0] = min(info->outmins[0], leaf->mins[0]); + info->outmins[1] = min(info->outmins[1], leaf->mins[1]); + info->outmins[2] = min(info->outmins[2], leaf->mins[2]); + info->outmaxs[0] = max(info->outmaxs[0], leaf->maxs[0]); + info->outmaxs[1] = max(info->outmaxs[1], leaf->maxs[1]); + info->outmaxs[2] = max(info->outmaxs[2], leaf->maxs[2]); + if (info->outleafpvs) { - v = p->verts[0]; - transpolybegin(t->gl_texturenum, t->gl_glowtexturenum, 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6) - transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha); - transpolyend(); + int leafindex = leaf - info->model->brush.data_leafs; + if (!CHECKPVSBIT(info->outleafpvs, leafindex)) + { + SETPVSBIT(info->outleafpvs, leafindex); + info->outleaflist[info->outnumleafs++] = leafindex; + } } - } -} - -void RSurf_WallVertexTransform(msurface_t *s, texture_t *t, int transform) -{ - int i; - glpoly_t *p; - float *wv, *v; - int size3; - float scale; - byte *lm; - size3 = ((s->extents[0]>>4)+1)*((s->extents[1]>>4)+1)*3; // *3 for colored lighting - wv = wvert; - for (p = s->polys;p;p = p->next) - { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + if (info->outsurfacepvs) { - if (transform) - softwaretransform(v, wv); - else - VectorCopy(v, wv); - wv[3] = wv[4] = wv[5] = r_ambient.value * 2.0f; - if (s->styles[0] != 255) + int leafsurfaceindex; + for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++) { - lm = (byte *)((long) s->samples + (int) v[7]); - scale = d_lightstylevalue[s->styles[0]] * (1.0f / 128.0f);wv[3] += lm[size3*0+0] * scale;wv[4] += lm[size3*0+1] * scale;wv[5] += lm[size3*0+2] * scale; - if (s->styles[1] != 255) + int surfaceindex = leaf->firstleafsurface[leafsurfaceindex]; + if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) { - scale = d_lightstylevalue[s->styles[1]] * (1.0f / 128.0f);wv[3] += lm[size3*1+0] * scale;wv[4] += lm[size3*1+1] * scale;wv[5] += lm[size3*1+2] * scale; - if (s->styles[2] != 255) + msurface_t *surface = info->model->data_surfaces + surfaceindex; + if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs)) { - scale = d_lightstylevalue[s->styles[2]] * (1.0f / 128.0f);wv[3] += lm[size3*2+0] * scale;wv[4] += lm[size3*2+1] * scale;wv[5] += lm[size3*2+2] * scale; - if (s->styles[3] != 255) + int triangleindex, t; + const int *e; + const vec_t *v[3]; + for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = info->model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->num_triangles;triangleindex++, t++, e += 3) { - scale = d_lightstylevalue[s->styles[3]] * (1.0f / 128.0f);wv[3] += lm[size3*3+0] * scale;wv[4] += lm[size3*3+1] * scale;wv[5] += lm[size3*3+2] * scale; + v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3; + v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3; + v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3; + if (PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2]))) + { + SETPVSBIT(info->outsurfacepvs, surfaceindex); + info->outsurfacelist[info->outnumsurfaces++] = surfaceindex; + break; + } } } } } - wv += 6; } } } -void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel) -{ - RSurf_WallVertexTransform(s, t, transform); - if (s->dlightframe == r_dlightframecount && r_dynamic.value) - RSurf_Light(s->dlightbits, s->polys); - RSurf_EmitWallVertex(s->polys, t, isbmodel && (currententity->colormod[0] != 1 || currententity->colormod[1] != 1 || currententity->colormod[2] != 1), (int) (modelalpha * 255.0f)); -} - -/* -================ -DrawTextureChains -================ -*/ -extern qboolean hlbsp; -extern char skyname[]; -void R_DrawSurf(msurface_t *s, int isbmodel, int vertexlit) +void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer) { - texture_t *t; - if (s->flags & SURF_DRAWSKY) - { - skyisvisible = true; - if (!hlbsp) // LordHavoc: HalfLife maps have freaky skypolys... - RSurf_DrawSky(s, false); - return; - } - t = R_TextureAnimation (s->texinfo->texture); - if (s->flags & SURF_DRAWTURB) - { - RSurf_DrawWater(s, t, false, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f); + r_q1bsp_getlightinfo_t info; + VectorCopy(relativelightorigin, info.relativelightorigin); + info.lightradius = lightradius; + info.lightmins[0] = info.relativelightorigin[0] - info.lightradius; + info.lightmins[1] = info.relativelightorigin[1] - info.lightradius; + info.lightmins[2] = info.relativelightorigin[2] - info.lightradius; + info.lightmaxs[0] = info.relativelightorigin[0] + info.lightradius; + info.lightmaxs[1] = info.relativelightorigin[1] + info.lightradius; + info.lightmaxs[2] = info.relativelightorigin[2] + info.lightradius; + if (ent->model == NULL) + { + VectorCopy(info.lightmins, outmins); + VectorCopy(info.lightmaxs, outmaxs); + *outnumleafspointer = 0; + *outnumsurfacespointer = 0; return; } - if (vertexlit) - RSurf_DrawWallVertex(s, t, false, false); + info.model = ent->model; + info.outleaflist = outleaflist; + info.outleafpvs = outleafpvs; + info.outnumleafs = 0; + info.outsurfacelist = outsurfacelist; + info.outsurfacepvs = outsurfacepvs; + info.outnumsurfaces = 0; + VectorCopy(info.relativelightorigin, info.outmins); + VectorCopy(info.relativelightorigin, info.outmaxs); + memset(outleafpvs, 0, (info.model->brush.num_leafs + 7) >> 3); + memset(outsurfacepvs, 0, (info.model->nummodelsurfaces + 7) >> 3); + if (info.model->brush.GetPVS) + info.pvs = info.model->brush.GetPVS(info.model, info.relativelightorigin); else - RSurf_DrawWall(s, t, false); -} - -void DrawTextureChains (void) -{ - int n; - msurface_t *s; - texture_t *t; - - for (n = 0;n < cl.worldmodel->numtextures;n++) + info.pvs = NULL; + R_UpdateAllTextureInfo(ent); + if (r_shadow_compilingrtlight) { - if (!cl.worldmodel->textures[n] || !(s = cl.worldmodel->textures[n]->texturechain)) - continue; - cl.worldmodel->textures[n]->texturechain = NULL; -// for (;s;s = s->texturechain) -// R_DrawSurf(s, false, gl_vertex.value); - // LordHavoc: decide the render type only once, because the surface properties were determined by texture anyway - // sky - if (s->flags & SURF_DRAWSKY) - { - skyisvisible = true; - if (!hlbsp) // LordHavoc: HalfLife maps have freaky skypolys... - for (;s;s = s->texturechain) - RSurf_DrawSky(s, false); - continue; - } - t = R_TextureAnimation (cl.worldmodel->textures[n]); - // subdivided water surface warp - if (s->flags & SURF_DRAWTURB) - { - int alpha = s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f; - for (;s;s = s->texturechain) - RSurf_DrawWater(s, t, false, alpha); - continue; - } - if (gl_vertex.value) - for (;s;s = s->texturechain) - RSurf_DrawWallVertex(s, t, false, false); - else - for (;s;s = s->texturechain) - RSurf_DrawWall(s, t, false); + // use portal recursion for exact light volume culling, and exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs); } -} - -void R_NoVisMarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, model_t *model); - -/* -================= -R_DrawBrushModel -================= -*/ -void R_DrawBrushModel (entity_t *e) -{ - int i; - vec3_t mins, maxs; - msurface_t *s; - model_t *clmodel; - int rotated, vertexlit = false; - texture_t *t; - vec3_t org; - - currententity = e; - - clmodel = e->model; - - if (e->angles[0] || e->angles[1] || e->angles[2]) + else if (r_shadow_realtime_dlight_portalculling.integer) { - rotated = true; - for (i=0 ; i<3 ; i++) - { - mins[i] = e->origin[i] - clmodel->radius; - maxs[i] = e->origin[i] + clmodel->radius; - } + // use portal recursion for exact light volume culling, but not the expensive exact surface checking + Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs); } else { - rotated = false; - VectorAdd (e->origin, clmodel->mins, mins); - VectorAdd (e->origin, clmodel->maxs, maxs); + // use BSP recursion as lights are often small + R_Q1BSP_RecursiveGetLightInfo(&info, info.model->brush.data_nodes); } - if (R_CullBox (mins, maxs)) - return; - - VectorSubtract (r_refdef.vieworg, e->origin, modelorg); - if (rotated) - { - vec3_t temp; - vec3_t forward, right, up; - - VectorCopy (modelorg, temp); - AngleVectors (e->angles, forward, right, up); - modelorg[0] = DotProduct (temp, forward); - modelorg[1] = -DotProduct (temp, right); - modelorg[2] = DotProduct (temp, up); - } + // limit combined leaf box to light boundaries + outmins[0] = max(info.outmins[0] - 1, info.lightmins[0]); + outmins[1] = max(info.outmins[1] - 1, info.lightmins[1]); + outmins[2] = max(info.outmins[2] - 1, info.lightmins[2]); + outmaxs[0] = min(info.outmaxs[0] + 1, info.lightmaxs[0]); + outmaxs[1] = min(info.outmaxs[1] + 1, info.lightmaxs[1]); + outmaxs[2] = min(info.outmaxs[2] + 1, info.lightmaxs[2]); - s = &clmodel->surfaces[clmodel->firstmodelsurface]; + *outnumleafspointer = info.outnumleafs; + *outnumsurfacespointer = info.outnumsurfaces; +} -// calculate dynamic lighting for bmodel if it's not an -// instanced model - for (i = 0;i < MAX_DLIGHTS;i++) - { - if ((cl_dlights[i].die < cl.time) || (!cl_dlights[i].radius)) +void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist) +{ + model_t *model = ent->model; + msurface_t *surface; + int surfacelistindex; + float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value; + texture_t *texture; + r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Begin(r_main_mempool, 32768, 32768, NULL, NULL, NULL, false, false, true); + R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + surface = model->data_surfaces + surfacelist[surfacelistindex]; + texture = surface->texture; + if ((texture->basematerialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL) continue; - - VectorSubtract(cl_dlights[i].origin, currententity->origin, org); - R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel); + if ((texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) || (ent->flags & RENDER_NOCULLFACE)) + continue; + R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs); } - vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->effects & EF_FULLBRIGHT) || currententity->colormod[0] != 1 || currententity->colormod[2] != 1 || currententity->colormod[2] != 1; - -e->angles[0] = -e->angles[0]; // stupid quake bug - softwaretransformforentity (e); -e->angles[0] = -e->angles[0]; // stupid quake bug + 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 + projectdistance, numshadowmark, shadowmarklist); + r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false); +} - // draw texture - for (i = 0;i < clmodel->nummodelsurfaces;i++, s++) +void R_Q1BSP_DrawShadowVolume_Batch(entity_render_t *ent, texture_t *texture, const vec3_t modelorg, const vec3_t relativelightorigin, const vec3_t lightmins, const vec3_t lightmaxs, int texturenumsurfaces, msurface_t **texturesurfacelist) +{ + int texturesurfaceindex; + RSurf_PrepareVerticesForBatch(ent, texture, modelorg, false, false, texturenumsurfaces, texturesurfacelist); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { - if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0)) - { -// R_DrawSurf(s, true, vertexlit || s->texinfo->texture->transparent); - if (s->flags & SURF_DRAWSKY) - { - RSurf_DrawSky(s, true); - continue; - } - t = R_TextureAnimation (s->texinfo->texture); - if (s->flags & SURF_DRAWTURB) - { - RSurf_DrawWater(s, t, true, s->flags & SURF_DRAWNOALPHA ? 255 : r_wateralpha.value*255.0f); - continue; - } - if (vertexlit || s->texinfo->texture->transparent) - RSurf_DrawWallVertex(s, t, true, true); - else - RSurf_DrawWall(s, t, true); - } + msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, rsurface_model->surfmesh.data_element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs); } - UploadLightmaps(); } -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - -void R_StoreEfrags (efrag_t **ppefrag); - -/* -================ -R_WorldNode -================ -*/ -void R_WorldNode () +void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs) { - int c, side, s = 0; - double dot; - struct - { - double dot; - mnode_t *node; - } nodestack[8192]; - mnode_t *node; - - if (!(node = cl.worldmodel->nodes)) + model_t *model = ent->model; + msurface_t *surface; + int modelsurfacelistindex; + int f = 0; + float projectdistance = lightradius + model->radius*2 + r_shadow_projectdistance.value; + vec3_t modelorg; + texture_t *t = NULL, *texture = NULL; + const int maxsurfacelist = 1024; + int numsurfacelist = 0; + msurface_t *surfacelist[1024]; + // check the box in modelspace, it was already checked in worldspace + if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs)) return; - - while(1) + R_UpdateAllTextureInfo(ent); + if (model->brush.shadowmesh) { - // if a leaf node, draw stuff - if (node->contents < 0) + R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles); + for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) { - if (node->contents != CONTENTS_SOLID) - { - mleaf_t *pleaf; - pleaf = (mleaf_t *)node; - - c_leafs++; - if ((c = pleaf->nummarksurfaces)) - { - msurface_t **mark; - mark = pleaf->firstmarksurface; - do - { - (*mark)->visframe = r_framecount; - mark++; - } while (--c); - } - - // deal with model fragments in this leaf - if (pleaf->efrags) - R_StoreEfrags (&pleaf->efrags); - } - - if (!s) - break; - node = nodestack[--s].node; - dot = nodestack[s].dot; - goto loc0; - } - - c_nodes++; - - // node is just a decision point, so go down the apropriate sides - - // find which side of the node we are on - dot = (node->plane->type < 3 ? modelorg[node->plane->type] : DotProduct (modelorg, node->plane->normal)) - node->plane->dist; - - // recurse down the children, front side first - side = dot < 0; - if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3)) - { - nodestack[s].node = node; - nodestack[s++].dot = dot; - node = node->children[side]; - continue; + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + texture = surface->texture->currentframe; + if ((texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL) + continue; + if ((texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) || (ent->flags & RENDER_NOCULLFACE)) + continue; + R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs); } -loc0: - - // backside - side = dot >= 0; - // draw stuff - if ((c = node->numsurfaces)) + 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 + projectdistance, numshadowmark, shadowmarklist); + } + else + { + projectdistance = lightradius + model->radius*2; + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + R_Shadow_PrepareShadowMark(model->surfmesh.num_triangles); + // identify lit faces within the bounding box + for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++) { - msurface_t *surf; - surf = cl.worldmodel->surfaces + node->firstsurface; - - if (side) - { - for (;c;c--, surf++) - { - if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK)) - { - if (gl_texsort.value) - { - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - else - R_DrawSurf(surf, false, gl_vertex.value); - } - } - } - else + surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex]; + if (t != surface->texture || numsurfacelist >= maxsurfacelist) { - for (;c;c--, surf++) + if (numsurfacelist) { - if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK)) - { - if (gl_texsort.value) - { - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - else - R_DrawSurf(surf, false, gl_vertex.value); - } + R_Q1BSP_DrawShadowVolume_Batch(ent, texture, modelorg, relativelightorigin, lightmins, lightmaxs, numsurfacelist, surfacelist); + numsurfacelist = 0; } + t = surface->texture; + texture = t->currentframe; + f = (texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) == MATERIALFLAG_WALL; } + if (f && surface->num_triangles) + surfacelist[numsurfacelist++] = surface; } - - // recurse down the back side - if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3)) - { - node = node->children[side]; - continue; - } - - if (!s) - break; - node = nodestack[--s].node; - dot = nodestack[s].dot; - goto loc0; + if (numsurfacelist) + R_Q1BSP_DrawShadowVolume_Batch(ent, texture, modelorg, relativelightorigin, lightmins, lightmaxs, numsurfacelist, surfacelist); + R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface_vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist); } } - -/* -============= -R_DrawWorld -============= -*/ -void R_DrawWorld (void) +static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) { - entity_t ent; - - memset (&ent, 0, sizeof(ent)); - ent.model = cl.worldmodel; - ent.colormod[0] = ent.colormod[1] = ent.colormod[2] = 1; - modelalpha = ent.alpha = 1; - ent.scale = 1; - - VectorCopy (r_refdef.vieworg, modelorg); - - currententity = &ent; - - softwaretransformidentity(); // LordHavoc: clear transform - - if (cl.worldmodel) - R_WorldNode (); - - glClear (GL_DEPTH_BUFFER_BIT); - - R_PushDlights (); // now mark the lit surfaces - - DrawTextureChains (); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + msurface_t *surface = ent->model->data_surfaces + surfacenumber; + texture_t *texture = surface->texture; + R_UpdateTextureInfo(ent, texture); + texture = texture->currentframe; + R_Shadow_RenderMode_Begin(); + R_Shadow_RenderMode_ActiveLight((rtlight_t *)rtlight); + R_Shadow_RenderMode_Lighting(false, true); + R_Shadow_SetupEntityLight(ent); + R_Shadow_RenderSurfacesLighting(ent, texture, 1, &surface); + R_Shadow_RenderMode_End(); } - -/* -=============== -R_MarkLeaves -=============== -*/ -void R_MarkLeaves (void) +static void R_Q1BSP_DrawLight_TransparentBatch(const entity_render_t *ent, texture_t *texture, int batchnumsurfaces, msurface_t **batchsurfacelist) { - byte *vis; - mnode_t *node; - int i; + int batchsurfaceindex; + model_t *model = ent->model; + msurface_t *batchsurface; + vec3_t tempcenter, center; + for (batchsurfaceindex = 0;batchsurfaceindex < batchnumsurfaces;batchsurfaceindex++) + { + batchsurface = batchsurfacelist[batchsurfaceindex]; + tempcenter[0] = (batchsurface->mins[0] + batchsurface->maxs[0]) * 0.5f; + tempcenter[1] = (batchsurface->mins[1] + batchsurface->maxs[1]) * 0.5f; + tempcenter[2] = (batchsurface->mins[2] + batchsurface->maxs[2]) * 0.5f; + Matrix4x4_Transform(&ent->matrix, tempcenter, center); + R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, R_Q1BSP_DrawLight_TransparentCallback, ent, batchsurface - model->data_surfaces, r_shadow_rtlight); + } +} - if (r_oldviewleaf == r_viewleaf && !r_novis.value) - return; - - r_visframecount++; - r_oldviewleaf = r_viewleaf; +#define RSURF_MAX_BATCHSURFACES 1024 - if (r_novis.value) - { - for (i=0 ; inumleafs ; i++) +void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surfacelist) +{ + model_t *model = ent->model; + msurface_t *surface; + texture_t *texture; + int surfacelistindex, batchnumsurfaces; + msurface_t *batchsurfacelist[RSURF_MAX_BATCHSURFACES]; + vec3_t modelorg; + texture_t *tex; + qboolean skip; + R_UpdateAllTextureInfo(ent); + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + tex = NULL; + texture = NULL; + skip = false; + batchnumsurfaces = 0; + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + if ((ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]])) + continue; + surface = model->data_surfaces + surfacelist[surfacelistindex]; + renderstats.lights_lighttriangles += surface->num_triangles; + if (tex != surface->texture) { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do + if (batchnumsurfaces > 0) { - if (node->visframe == r_visframecount) - break; - node->visframe = r_visframecount; - node = node->parent; - } while (node); + if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist); + else + R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist); + batchnumsurfaces = 0; + } + tex = surface->texture; + texture = surface->texture->currentframe; + skip = (texture->currentmaterialflags & MATERIALFLAG_SKY) != 0; + if (skip) + continue; } - } - else - { - vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); - - for (i=0 ; inumleafs ; i++) + if (!skip && surface->num_triangles) { - if (vis[i>>3] & (1<<(i&7))) + if (batchnumsurfaces == RSURF_MAX_BATCHSURFACES) { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do - { - if (node->visframe == r_visframecount) - break; - node->visframe = r_visframecount; - node = node->parent; - } while (node); + if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist); + else + R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist); + batchnumsurfaces = 0; } + batchsurfacelist[batchnumsurfaces++] = surface; } } + if (batchnumsurfaces > 0) + { + if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) + R_Q1BSP_DrawLight_TransparentBatch(ent, texture, batchnumsurfaces, batchsurfacelist); + else + R_Shadow_RenderSurfacesLighting(ent, texture, batchnumsurfaces, batchsurfacelist); + batchnumsurfaces = 0; + } + qglEnable(GL_CULL_FACE); } - - -/* -============================================================================= - - LIGHTMAP ALLOCATION - -============================================================================= -*/ - -// returns a texture number and the position inside it -int AllocBlock (int w, int h, int *x, int *y) +//Made by [515] +void R_ReplaceWorldTexture (void) { - int i, j; - int best, best2; - int texnum; + model_t *m; + texture_t *t; + int i; + const char *r, *newt; + m = r_refdef.worldmodel; - for (texnum=0 ; texnum= best) - break; - if (allocated[texnum][i+j] > best2) - best2 = allocated[texnum][i+j]; - } - if (j == w) - { // this is a valid spot - *x = i; - *y = best = best2; - } - } - - if (best + h > BLOCK_HEIGHT) - continue; - - if (nosubimagefragments || nosubimage) - { - if (!lightmaps[texnum]) - lightmaps[texnum] = calloc(BLOCK_WIDTH*BLOCK_HEIGHT*4, 1); - } - // LordHavoc: clear texture to blank image, fragments are uploaded using subimage - else if (!allocated[texnum][0]) - { - byte blank[BLOCK_WIDTH*BLOCK_HEIGHT*3]; - memset(blank, 0, sizeof(blank)); - glBindTexture(GL_TEXTURE_2D, lightmap_textures + texnum); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (lightmaprgba) - glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, blank); - else - glTexImage2D (GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, blank); - } - - for (i=0 ; i - replaces texture\n"); + Con_Print("r_replacemaptexture - switch back to default texture\n"); + return; } - - Sys_Error ("AllocBlock: full"); - return 0; -} - - -mvertex_t *r_pcurrentvertbase; -model_t *currentmodel; - -int nColinElim; - -/* -================ -BuildSurfaceDisplayList -================ -*/ -void BuildSurfaceDisplayList (msurface_t *fa) -{ - int i, j, lindex, lnumverts; - medge_t *pedges, *r_pedge; - int vertpage; - float *vec; - float s, t; - glpoly_t *poly; - -// reconstruct the polygon - pedges = currentmodel->edges; - lnumverts = fa->numedges; - vertpage = 0; - - // - // draw texture - // - poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); - poly->next = fa->polys; - poly->flags = fa->flags; - fa->polys = poly; - poly->numverts = lnumverts; - - for (i=0 ; isurfedges[fa->firstedge + i]; - - if (lindex > 0) - { - r_pedge = &pedges[lindex]; - vec = r_pcurrentvertbase[r_pedge->v[0]].position; - } - else - { - r_pedge = &pedges[-lindex]; - vec = r_pcurrentvertbase[r_pedge->v[1]].position; - } - s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; - t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; - - VectorCopy (vec, poly->verts[i]); - poly->verts[i][3] = s / fa->texinfo->texture->width; - poly->verts[i][4] = t / fa->texinfo->texture->height; - - // - // lightmap texture coordinates - // - s -= fa->texturemins[0]; - t -= fa->texturemins[1]; - s += 8; - t += 8; - // LordHavoc: calc lightmap data offset - j = (bound(0l, (int)t>>4, fa->extents[1]>>4) * ((fa->extents[0]>>4)+1) + bound(0l, (int)s>>4, fa->extents[0]>>4)) * 3; - poly->verts[i][7] = j; - s += fa->light_s*16; - s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; - - t += fa->light_t*16; - t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; - - poly->verts[i][5] = s; - poly->verts[i][6] = t; + Con_Print("This command works only in singleplayer\n"); + return; } - - // - // remove co-linear points - Ed - // - /* - if (!gl_keeptjunctions.value) + r = Cmd_Argv(1); + newt = Cmd_Argv(2); + if(!newt[0]) + newt = r; + for(i=0,t=m->data_textures;inum_textures;i++,t++) { - for (i = 0 ; i < lnumverts ; ++i) + if(t->width && !strcasecmp(t->name, r)) { - vec3_t v1, v2; - float *prev, *this, *next; - - prev = poly->verts[(i + lnumverts - 1) % lnumverts]; - this = poly->verts[i]; - next = poly->verts[(i + 1) % lnumverts]; - - VectorSubtract( this, prev, v1 ); - VectorNormalize( v1 ); - VectorSubtract( next, prev, v2 ); - VectorNormalize( v2 ); - - // skip co-linear points - #define COLINEAR_EPSILON 0.001 - if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) && - (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && - (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON)) + if(Mod_LoadSkinFrame(&t->skin, (char*)newt, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer)) { - int j; - for (j = i + 1; j < lnumverts; ++j) - { - int k; - for (k = 0; k < VERTEXSIZE; ++k) - poly->verts[j - 1][k] = poly->verts[j][k]; - } - --lnumverts; - ++nColinElim; - // retry next vertex next time, which is now current vertex - --i; + Con_Printf("%s replaced with %s\n", r, newt); + return; + } + else + { + Con_Printf("%s was not found\n", newt); + Mod_LoadSkinFrame(&t->skin, (char*)r, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer);//back to default + return; } } } - */ - poly->numverts = lnumverts; } -/* -======================== -GL_CreateSurfaceLightmap -======================== -*/ -void GL_CreateSurfaceLightmap (msurface_t *surf) +//Made by [515] +void R_ListWorldTextures (void) { - int smax, tmax; - - if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) - return; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; + model_t *m; + texture_t *t; + int i; + m = r_refdef.worldmodel; - surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); - if (nosubimage || nosubimagefragments) - return; - glBindTexture(GL_TEXTURE_2D, lightmap_textures + surf->lightmaptexturenum); - smax = ((surf->extents[0]>>4)+lightmapalign) & lightmapalignmask; - if (lightmaprgba) - { - R_BuildLightMap (surf, templight, smax * 4); - glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, templight); - } - else - { - R_BuildLightMap (surf, templight, smax * 3); - glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGB , GL_UNSIGNED_BYTE, templight); - } + Con_Print("Worldmodel textures :\n"); + for(i=0,t=m->data_textures;inum_textures;i++,t++) + if(t->skin.base != r_texture_notexture) + Con_Printf("%s\n", t->name); } - -/* -================== -GL_BuildLightmaps - -Builds the lightmap texture -with all the surfaces from all brush models -================== -*/ -void GL_BuildLightmaps (void) +#if 0 +static void gl_surf_start(void) { - int i, j; - model_t *m; - - memset (allocated, 0, sizeof(allocated)); - - r_framecount = 1; // no dlightcache - - if (gl_nosubimagefragments.value) - nosubimagefragments = 1; - else - nosubimagefragments = 0; +} - if (gl_nosubimage.value) - nosubimage = 1; - else - nosubimage = 0; +static void gl_surf_shutdown(void) +{ +} - if (gl_lightmaprgba.value) - { - lightmaprgba = true; - lightmapbytes = 4; - } - else - { - lightmaprgba = false; - lightmapbytes = 3; - } +static void gl_surf_newmap(void) +{ +} +#endif - // LordHavoc: NVIDIA seems to have a broken glTexSubImage2D, - // it needs to be aligned on 4 pixel boundaries... - // so I implemented an adjustable lightmap alignment - if (gl_lightmapalign.value < 1) - gl_lightmapalign.value = 1; - if (gl_lightmapalign.value > 16) - gl_lightmapalign.value = 16; - lightmapalign = 1; - while (lightmapalign < gl_lightmapalign.value) - lightmapalign <<= 1; - gl_lightmapalign.value = lightmapalign; - lightmapalignmask = ~(lightmapalign - 1); - if (nosubimagefragments || nosubimage) - { - lightmapalign = 1; - lightmapalignmask = ~0; - } +void GL_Surf_Init(void) +{ - if (!lightmap_textures) - { - lightmap_textures = texture_extension_number; - texture_extension_number += MAX_LIGHTMAPS; - } + Cvar_RegisterVariable(&r_ambient); + Cvar_RegisterVariable(&r_drawportals); + Cvar_RegisterVariable(&r_lockpvs); + Cvar_RegisterVariable(&r_lockvisibility); + Cvar_RegisterVariable(&r_useportalculling); + Cvar_RegisterVariable(&r_q3bsp_renderskydepth); - for (j=1 ; jname[0] == '*') - continue; - r_pcurrentvertbase = m->vertexes; - currentmodel = m; - for (i=0 ; inumsurfaces ; i++) - { - if ( m->surfaces[i].flags & SURF_DRAWTURB ) - continue; - if ( m->surfaces[i].flags & SURF_DRAWSKY ) - continue; - GL_CreateSurfaceLightmap (m->surfaces + i); - BuildSurfaceDisplayList (m->surfaces + i); - } - } + Cmd_AddCommand ("r_replacemaptexture", R_ReplaceWorldTexture, "override a map texture for testing purposes"); // By [515] + Cmd_AddCommand ("r_listmaptextures", R_ListWorldTextures, "list all textures used by the current map"); // By [515] - if (nosubimage || nosubimagefragments) - { - if (gl_mtexable) - qglSelectTexture(gl_mtex_enum+1); - for (i = 0;i < MAX_LIGHTMAPS;i++) - { - if (!allocated[i][0]) - break; - lightmapupdate[i][0] = BLOCK_HEIGHT; - lightmapupdate[i][1] = 0; - glBindTexture(GL_TEXTURE_2D, lightmap_textures + i); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if (lightmaprgba) - glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightmaps[i]); - else - glTexImage2D(GL_TEXTURE_2D, 0, 3, BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i]); - } - if (gl_mtexable) - qglSelectTexture(gl_mtex_enum+0); - } + //R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap); }