X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=gl_rsurf.c;h=d72dcbab094c3d13bba9d89ab3505230d28cf9ca;hb=4a14d162b12e843464f90f705c57dae8a5693964;hp=29c3d4d1ac887ee4b398707a78f699225f4e71b5;hpb=957f0f8347e5e3421cdbe8bb6d9b47e6e3b260bd;p=xonotic%2Fdarkplaces.git diff --git a/gl_rsurf.c b/gl_rsurf.c index 29c3d4d1..d72dcbab 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"}; +cvar_t r_drawportals = {0, "r_drawportals", "0"}; +cvar_t r_testvis = {0, "r_testvis", "0"}; +cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"}; +cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"}; +cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"}; +cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"}; +cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"}; + +// 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 +qbyte r_pvsbits[(32768+7)>>3]; +// TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs +qbyte r_worldleafvisible[32768]; +// TODO: dynamic resize according to r_refdef.worldmodel->num_surfaces +qbyte r_worldsurfacevisible[262144]; -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,1291 +50,804 @@ 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, j, size, size3, maps, stride, l; + unsigned int *bl, scale; + qbyte *lightmap, *out, *stain; + static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting + static qbyte 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 (!ent->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 ; 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; - } - } + bl = intblocklights; + for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++, lightmap += size3) + for (scale = d_lightstylevalue[surface->lightmapinfo->styles[maps]], i = 0;i < size3;i++) + bl[i] += lightmap[i] * scale; } - else + } + + 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 (ent->model->brushq1.lightmaprgba) + { + stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 4; + for (i = 0;i < tmax;i++, out += stride) { - 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); + *out++ = 255; } } } else { - if (lightmaprgba) + stride = (surface->lightmapinfo->lightmaptexturestride - smax) * 3; + for (i = 0;i < tmax;i++, out += stride) { - 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; - *dest++ = 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; - } + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); + l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255); } } } -} -byte templight[32*32*4]; + R_UpdateTexture(surface->lightmaptexture, templight); +} -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; + qbyte *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; } - else + if (ndist < -radius) { - 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); - } + node = node->children[1]; + goto loc0; } -} - - -/* -=============== -R_TextureAnimation -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; + dist2 = ndist * ndist; + maxdist3 = maxdist - dist2; - if (currententity->frame) + if (node->plane->type < 3) { - if (base->alternate_anims) - base = base->alternate_anims; + VectorCopy(origin, impact); + impact[node->plane->type] -= ndist; } - - if (!base->anim_total) - return base; - - original = base; - - relative = (int)(cl.time*10) % base->anim_total; - - count = 0; - while (base->anim_min > relative || base->anim_max <= relative) + else { - base = base->anim_next; - if (!base) - { - Con_Printf("R_TextureAnimation: broken cycle"); - return original; - } - if (++count > 100) - { - Con_Printf("R_TextureAnimation: infinite cycle"); - return original; - } + 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; } - return base; -} - - -/* -============================================================= - - BRUSH MODELS - -============================================================= -*/ - - -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] = -{ - #include "gl_warp_sin.h" -}; -#define TURBSCALE (256.0 / (2 * M_PI)) - - -void UploadLightmaps() -{ - int i; - if (nosubimage || nosubimagefragments) + for (surface = model->data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++) { - for (i = 0;i < MAX_LIGHTMAPS;i++) + if (surface->lightmapinfo->stainsamples) { - if (lightmapupdate[i][0] < lightmapupdate[i][1]) - { - glBindTexture(GL_TEXTURE_2D, lightmap_textures + i); - if (nosubimage) - { - 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])); - } - } - lightmapupdate[i][0] = BLOCK_HEIGHT; - lightmapupdate[i][1] = 0; - } - } -} + smax = (surface->lightmapinfo->extents[0] >> 4) + 1; + tmax = (surface->lightmapinfo->extents[1] >> 4) + 1; -float wvert[1024*6]; // used by the following functions + impacts = DotProduct (impact, surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3] - surface->lightmapinfo->texturemins[0]; + impactt = DotProduct (impact, surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3] - surface->lightmapinfo->texturemins[1]; -void RSurf_DrawSky(msurface_t *s, int transform) -{ - glpoly_t *p; - int i; - float *v; - for (p=s->polys ; p ; p=p->next) - { - if (currentskypoly < MAX_SKYPOLYS && currentskyvert + p->numverts <= MAX_SKYVERTS) - { - skypoly[currentskypoly].firstvert = currentskyvert; - skypoly[currentskypoly++].verts = p->numverts; - if (transform) - { - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) - { - softwaretransform(v, skyvert[currentskyvert].v); - currentskyvert++; - } - } - else - { - for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) - { - skyvert[currentskyvert].v[0] = v[0]; - skyvert[currentskyvert].v[1] = v[1]; - skyvert[currentskyvert++].v[2] = v[2]; - } - } - } - } -} + s = bound(0, impacts, smax * 16) - impacts; + t = bound(0, impactt, tmax * 16) - impactt; + i = s * s + t * t + dist2; + if (i > maxdist) + continue; -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])) - { - for (b = 0, d = 1;c;b++, d <<= 1) + // reduce calculations + for (s = 0, i = impacts; s < smax; s++, i -= 16) + sdtable[s] = i * i + dist2; + + bl = surface->lightmapinfo->stainsamples; + smax3 = smax * 3; + stained = false; + + i = impactt; + for (t = 0;t < tmax;t++, i -= 16) { - if (c & d) + td = i * i; + // make sure some part of it is visible on this line + if (td < maxdist3) { - 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) + maxdist2 = maxdist - td; + for (s = 0;s < smax;s++) { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + if (sdtable[s] < maxdist2) { - f = VectorDistance2(wv, lightorigin); - if (f < radius) + 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)) { - f = radius2 / (f + LIGHTOFFSET); - wv[3] += cr * f; - wv[4] += cg * f; - wv[5] += cb * f; - lit = true; + if (a > 1) + a = 1; + bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0])); + bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1])); + bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2])); + stained = true; } - wv += 6; } + bl += 3; } } + else // skip line + bl += smax3; } + // force lightmap upload + if (stained) + surface->cached_dlight = true; } } - 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) + if (node->children[0]->plane) { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + if (node->children[1]->plane) { - 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; + R_StainNode(node->children[0], model, origin, radius, fcolor); + node = node->children[1]; + goto loc0; } - } - 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); - } -} - -void RSurf_Transform(glpoly_t *p, int transform) -{ - int i; - float *v, *wv = wvert; - for (;p;p = p->next) - { - for (i = 0, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + else { - if (transform) - softwaretransform(v, wv); - else - VectorCopy(v, wv); - wv[3] = wv[4] = wv[5] = 0.0f; - wv += 6; + node = node->children[0]; + goto loc0; } } + else if (node->children[1]->plane) + { + node = node->children[1]; + goto loc0; + } } -void RSurf_EmitWallpolys(int lightmap, glpoly_t *p, texture_t *t, int lit) +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 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) + 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] == '*') + { + Mod_CheckLoaded(model); + if (model->brush.data_nodes) { - 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; - } + Matrix4x4_Transform(&ent->inversematrix, origin, org); + R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor); } - 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]; } } } -void RSurf_DrawWall(msurface_t *s, texture_t *t, int transform) -{ - 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); -} -// LordHavoc: transparent brush models -extern int r_dlightframecount; -extern float modelalpha; +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ -void RSurf_EmitWallVertex(glpoly_t *p, texture_t *t, int modulate, int alpha) +static void R_DrawPortal_Callback(const void *calldata1, int calldata2) { int i; - float *v, *wv = wvert; - if (modulate) - { - for (;p;p = p->next) - { - 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(); - } + float *v; + rmeshstate_t m; + const mportal_t *portal = calldata1; + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GL_DepthMask(false); + GL_DepthTest(true); + R_Mesh_Matrix(&r_identitymatrix); + + memset(&m, 0, sizeof(m)); + m.pointer_vertex = varray_vertex3f; + R_Mesh_State(&m); + + i = calldata2; + 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); + if (PlaneDiff(r_vieworigin, (&portal->plane)) < 0) + { + for (i = portal->numpoints - 1, v = varray_vertex3f;i >= 0;i--, v += 3) + VectorCopy(portal->points[i].position, v); } else - { - for (;p;p = p->next) - { - 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(); - } - } + for (i = 0, v = varray_vertex3f;i < portal->numpoints;i++, v += 3) + VectorCopy(portal->points[i].position, v); + GL_LockArrays(0, portal->numpoints); + R_Mesh_Draw(0, portal->numpoints, portal->numpoints - 2, polygonelements); + GL_LockArrays(0, 0); } -void RSurf_WallVertexTransform(msurface_t *s, texture_t *t, int transform) +// LordHavoc: this is just a nice debugging tool, very slow +static void R_DrawPortals(void) { - 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) + int i, leafnum;//, portalnum; + 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, v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE) + if (r_worldleafvisible[leafnum]) { - 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) + //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) { - 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) + if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS) + if (!R_CullBox(portal->mins, portal->maxs)) { - 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) - { - 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) - { - 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; - } - } + 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, portal, portalnum); + R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, leafnum); } } - wv += 6; } } } -void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmodel) +static void R_DrawCollisionBrush(colbrushf_t *brush) { - 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)); + 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(0, brush->numpoints, brush->numtriangles, brush->elements); + GL_LockArrays(0, 0); } -/* -================ -DrawTextureChains -================ -*/ -extern qboolean hlbsp; -extern char skyname[]; -void R_DrawSurf(msurface_t *s, int isbmodel, int vertexlit) +static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface) { - 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); + int i; + rmeshstate_t m; + if (!surface->num_collisiontriangles) return; - } - if (vertexlit) - RSurf_DrawWallVertex(s, t, false, false); - else - RSurf_DrawWall(s, t, false); + memset(&m, 0, sizeof(m)); + m.pointer_vertex = surface->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->num_collisionvertices); + R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i); + GL_LockArrays(0, 0); } -void DrawTextureChains (void) +void R_WorldVisibility(void) { - int n; - msurface_t *s; - texture_t *t; + int i, j, *mark; + mleaf_t *leaf; + mleaf_t *viewleaf; + model_t *model = r_refdef.worldmodel; - for (n = 0;n < cl.worldmodel->numtextures;n++) - { - 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); - } -} - -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; + if (!model) + return; - currententity = e; + // 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 (model->brush.FatPVS) + model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits)); - clmodel = e->model; + // clear the visible surface and leaf flags arrays + memset(r_worldsurfacevisible, 0, model->num_surfaces); + memset(r_worldleafvisible, 0, model->brush.num_leafs); - if (e->angles[0] || e->angles[1] || e->angles[2]) + // if the user prefers surfaceworldnode (testing?) or the viewleaf could + // not be found, or the viewleaf is not part of the visible world + // (floating around in the void), use the pvs method + if (r_surfaceworldnode.integer || !viewleaf || viewleaf->clusterindex < 0) { - rotated = true; - for (i=0 ; i<3 ; i++) + // pvs method: + // similar to quake's RecursiveWorldNode but without cache misses + for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++) { - mins[i] = e->origin[i] - clmodel->radius; - maxs[i] = e->origin[i] + clmodel->radius; + // 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)) + { + c_leafs++; + r_worldleafvisible[j] = true; + if (leaf->numleafsurfaces) + for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++) + r_worldsurfacevisible[*mark] = true; + } } } else { - rotated = false; - VectorAdd (e->origin, clmodel->mins, mins); - VectorAdd (e->origin, clmodel->maxs, maxs); - } + int leafstackpos; + mportal_t *p; + mleaf_t *leafstack[8192]; + // 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 a + // lot of surface that pvs alone would miss + leafstack[0] = viewleaf; + leafstackpos = 1; + while (leafstackpos) + { + c_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) + 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; + } + } + + if (r_drawportals.integer) + R_DrawPortals(); +} - if (R_CullBox (mins, maxs)) +void R_Q1BSP_DrawSky(entity_render_t *ent) +{ + if (ent->model == NULL) return; + if (r_drawcollisionbrushes.integer < 2) + R_DrawSurfaces(ent, true); +} - 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); - } - - s = &clmodel->surfaces[clmodel->firstmodelsurface]; - -// 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)) - continue; - - VectorSubtract(cl_dlights[i].origin, currententity->origin, org); - R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel); +void R_Q1BSP_Draw(entity_render_t *ent) +{ + if (ent->model == NULL) + return; + 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; + R_Mesh_Matrix(&ent->matrix); + 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->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++) + if (surface->num_collisiontriangles) + R_DrawCollisionSurface(ent, surface); + qglPolygonOffset(0, 0); } - 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 +typedef struct r_q1bsp_getlightinfo_s +{ + model_t *model; + vec3_t relativelightorigin; + float lightradius; + int *outleaflist; + qbyte *outleafpvs; + int outnumleafs; + int *outsurfacelist; + qbyte *outsurfacepvs; + int outnumsurfaces; + vec3_t outmins; + vec3_t outmaxs; + vec3_t lightmins; + vec3_t lightmaxs; + const qbyte *pvs; +} +r_q1bsp_getlightinfo_t; - // draw texture - for (i = 0;i < clmodel->nummodelsurfaces;i++, s++) +void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node) +{ + int sides; + mleaf_t *leaf; + for (;;) { - if (((s->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, s->plane) >= 0)) + if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs)) + return; + if (!node->plane) + break; + sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, node->plane) - 1; + if (sides == 2) { -// 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); + R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]); + node = node->children[1]; } + else + node = node->children[sides]; } - UploadLightmaps(); -} - -/* -============================================================= - - WORLD MODEL - -============================================================= -*/ - -void R_StoreEfrags (efrag_t **ppefrag); - -struct nodestack_s -{ - int side; - mnode_t *node; -} nodestack[8192]; - -/* -================ -R_WorldNode -================ -*/ -void R_WorldNode () -{ - int side, texsort, vertex; - struct nodestack_s *nstack; - mnode_t *node; - mleaf_t *pleaf; - msurface_t *surf, *endsurf, **mark, **endmark; - nstack = nodestack; - texsort = gl_texsort.value; - vertex = gl_vertex.value; - - if (!(node = cl.worldmodel->nodes)) - return; - - while(1) + leaf = (mleaf_t *)node; + if (info->pvs == NULL || CHECKPVSBIT(info->pvs, leaf->clusterindex)) { - // if a leaf node, draw stuff - if (node->contents < 0) + 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) { - if (node->contents != CONTENTS_SOLID) + int leafindex = leaf - info->model->brush.data_leafs; + if (!CHECKPVSBIT(info->outleafpvs, leafindex)) { - pleaf = (mleaf_t *)node; - - c_leafs++; - if (pleaf->nummarksurfaces) - { - mark = pleaf->firstmarksurface; - endmark = mark + pleaf->nummarksurfaces; - do - { - (*mark)->visframe = r_framecount; - mark++; - } - while (mark < endmark); - } - - // deal with model fragments in this leaf - if (pleaf->efrags) - R_StoreEfrags (&pleaf->efrags); + SETPVSBIT(info->outleafpvs, leafindex); + info->outleaflist[info->outnumleafs++] = leafindex; } - - if (nstack <= nodestack) - break; - nstack--; - node = nstack->node; - side = nstack->side; - 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 - side = PlaneDist(modelorg, node->plane) < node->plane->dist; - - // recurse down the children, front side first - if (node->children[side]->visframe == r_visframecount && R_NotCulledBox(node->children[side]->minmaxs, node->children[side]->minmaxs+3)) - { - nstack->node = node; - nstack->side = !side; // go down back side when we come back up - nstack++; - node = node->children[side]; - continue; } - side = !side; -loc0: - - // draw stuff - if (node->numsurfaces) + if (info->outsurfacepvs) { - surf = cl.worldmodel->surfaces + node->firstsurface; - endsurf = surf + node->numsurfaces; - - if (texsort) + int leafsurfaceindex; + for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++) { - if (side) - { - do - { - if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK)) - { - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; - } - surf++; - } - while (surf < endsurf); - } - else + int surfaceindex = leaf->firstleafsurface[leafsurfaceindex]; + if (!CHECKPVSBIT(info->outsurfacepvs, surfaceindex)) { - do + msurface_t *surface = info->model->data_surfaces + surfaceindex; + if (BoxesOverlap(info->lightmins, info->lightmaxs, surface->mins, surface->maxs)) + if ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) { - if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK)) + 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) { - surf->texturechain = surf->texinfo->texture->texturechain; - surf->texinfo->texture->texturechain = surf; + 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; + } } - surf++; - } - while (surf < endsurf); - } - } - else - { - if (side) - { - do - { - if (surf->visframe == r_framecount && !(surf->flags & SURF_PLANEBACK)) - R_DrawSurf(surf, false, vertex); - surf++; } - while (surf < endsurf); - } - else - { - do - { - if (surf->visframe == r_framecount && (surf->flags & SURF_PLANEBACK)) - R_DrawSurf(surf, false, vertex); - surf++; - } - while (surf < endsurf); } } } - - // 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 (nstack <= nodestack) - break; - nstack--; - node = nstack->node; - side = nstack->side; - goto loc0; } } - -/* -============= -R_DrawWorld -============= -*/ -void R_DrawWorld (void) +void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, qbyte *outleafpvs, int *outnumleafspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer) { - 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 (); - - R_PushDlights (); // now mark the lit surfaces - - DrawTextureChains (); -} - - -/* -=============== -R_MarkLeaves -=============== -*/ -void R_MarkLeaves (void) -{ - byte *vis; - mnode_t *node; - int i; - - if (r_oldviewleaf == r_viewleaf && !r_novis.value) + 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; - - r_visframecount++; - r_oldviewleaf = r_viewleaf; - - if (r_novis.value) + } + 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 + info.pvs = NULL; + R_UpdateAllTextureInfo(ent); + if (r_shadow_compilingrtlight) { - for (i=0 ; inumleafs ; i++) - { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do - { - if (node->visframe == r_visframecount) - break; - node->visframe = r_visframecount; - node = node->parent; - } while (node); - } + // 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); + } + else if (r_shadow_realtime_dlight_portalculling.integer) + { + // 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 { - vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); - - for (i=0 ; inumleafs ; i++) - { - if (vis[i>>3] & (1<<(i&7))) - { - node = (mnode_t *)&cl.worldmodel->leafs[i+1]; - do - { - if (node->visframe == r_visframecount) - break; - node->visframe = r_visframecount; - node = node->parent; - } while (node); - } - } + // use BSP recursion as lights are often small + R_Q1BSP_RecursiveGetLightInfo(&info, info.model->brush.data_nodes); } -} + // 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]); + *outnumleafspointer = info.outnumleafs; + *outnumsurfacespointer = info.outnumsurfaces; +} -/* -============================================================================= - - LIGHTMAP ALLOCATION - -============================================================================= -*/ +extern float *rsurface_vertex3f; +extern float *rsurface_svector3f; +extern float *rsurface_tvector3f; +extern float *rsurface_normal3f; +extern void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg); -// returns a texture number and the position inside it -int AllocBlock (int w, int h, short *x, short *y) +void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs) { - int i, j; - int best, best2; - int texnum; - - for (texnum=0 ; texnummodel; + msurface_t *surface; + int surfacelistindex; + float projectdistance = lightradius + model->radius + r_shadow_projectdistance.value; + vec3_t modelorg; + texture_t *texture; + // check the box in modelspace, it was already checked in worldspace + if (!BoxesOverlap(ent->model->normalmins, ent->model->normalmaxs, lightmins, lightmaxs)) + return; + if (r_drawcollisionbrushes.integer >= 2) + return; + if (!r_shadow_compilingrtlight) + R_UpdateAllTextureInfo(ent); + if (model->brush.shadowmesh) { - best = BLOCK_HEIGHT; - - for (i=0 ; ibrush.shadowmesh->numtriangles); + if (r_shadow_compilingrtlight) { - best2 = 0; - - for (j=0 ; j= 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; + surface = model->data_surfaces + surfacelist[surfacelistindex]; + texture = surface->texture; + if ((texture->basematerialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL) + continue; + if (texture->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2)) + 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); } } - - if (best + h > BLOCK_HEIGHT) - continue; - - if (nosubimagefragments || nosubimage) + else { - if (!lightmaps[texnum]) - lightmaps[texnum] = calloc(BLOCK_WIDTH*BLOCK_HEIGHT*4, 1); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) + { + surface = model->data_surfaces + surfacelist[surfacelistindex]; + 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)) + 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); + } } - // LordHavoc: clear texture to blank image, fragments are uploaded using subimage - else if (!allocated[texnum][0]) + 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 + ent->model->radius; + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { - 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); + surface = model->data_surfaces + surfacelist[surfacelistindex]; + // FIXME: get current skin + texture = surface->texture;//R_FetchAliasSkin(ent, surface->groupmesh); + if (texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT) || !surface->num_triangles) + continue; + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + // identify lit faces within the bounding box + R_Shadow_PrepareShadowMark(surface->groupmesh->num_triangles); + R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs); + R_Shadow_VolumeFromList(surface->groupmesh->num_vertices, surface->groupmesh->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i, surface->groupmesh->data_neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist); } - - for (i=0 ; iedges; - 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 ; imodel; + msurface_t *surface; + texture_t *texture; + int surfacelistindex; + vec3_t modelorg; + if (r_drawcollisionbrushes.integer >= 2) + return; + if (r_shadow_compilingrtlight) { - lindex = currentmodel->surfedges[fa->firstedge + i]; - - if (lindex > 0) + // if compiling an rtlight, capture the meshes + int tri; + int *e; + float *lightmins, *lightmaxs, *v[3], *vertex3f; + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { - 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; + surface = model->data_surfaces + surfacelist[surfacelistindex]; + texture = surface->texture; + if ((texture->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL || !surface->num_triangles) + continue; + e = surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle; + vertex3f = surface->groupmesh->data_vertex3f; + lightmins = r_shadow_compilingrtlight->cullmins; + lightmaxs = r_shadow_compilingrtlight->cullmaxs; + for (tri = 0;tri < surface->num_triangles;tri++, e += 3) + { + v[0] = vertex3f + e[0] * 3; + v[1] = vertex3f + e[1] * 3; + v[2] = vertex3f + e[2] * 3; + if (PointInfrontOfTriangle(r_shadow_compilingrtlight->shadoworigin, 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]))) + 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->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e); + } } - 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; } - - // - // remove co-linear points - Ed - // - /* - if (!gl_keeptjunctions.value) + else { - for (i = 0 ; i < lnumverts ; ++i) + R_UpdateAllTextureInfo(ent); + Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg); + for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { - 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 (ent == r_refdef.worldentity && !r_worldsurfacevisible[surfacelist[surfacelistindex]]) + continue; + surface = model->data_surfaces + surfacelist[surfacelistindex]; + texture = surface->texture->currentframe; + // FIXME: transparent surfaces need to be lit later + if ((texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) != MATERIALFLAG_WALL || !surface->num_triangles) + continue; + if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglDisable(GL_CULL_FACE); + RSurf_SetVertexPointer(ent, texture, surface, modelorg); + if (!rsurface_svector3f) { - int j; - for (j = i + 1; j < lnumverts; ++j) + rsurface_svector3f = varray_svector3f; + rsurface_tvector3f = varray_tvector3f; + rsurface_normal3f = varray_normal3f; + Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f); + } + if (ent->colormap >= 0) + { + vec3_t lightcolorpants, lightcolorshirt; + // 128-224 are backwards ranges + int b = (ent->colormap & 0xF) << 4;b += (b >= 128 && b < 224) ? 4 : 12; + if (texture->skin.pants && b >= 224) { - int k; - for (k = 0; k < VERTEXSIZE; ++k) - poly->verts[j - 1][k] = poly->verts[j][k]; + qbyte *bcolor = (qbyte *) (&palette_complete[b]); + lightcolorpants[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f); + lightcolorpants[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f); + lightcolorpants[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f); } - --lnumverts; - ++nColinElim; - // retry next vertex next time, which is now current vertex - --i; + else + VectorClear(lightcolorpants); + // 128-224 are backwards ranges + b = (ent->colormap & 0xF0);b += (b >= 128 && b < 224) ? 4 : 12; + if (texture->skin.shirt && b >= 224) + { + qbyte *bcolor = (qbyte *) (&palette_complete[b]); + lightcolorshirt[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f); + lightcolorshirt[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f); + lightcolorshirt[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f); + } + else + VectorClear(lightcolorshirt); + R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), rsurface_vertex3f, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, surface->groupmesh->data_texcoordtexture2f, lightcolor, lightcolorpants, lightcolorshirt, texture->skin.base, texture->skin.pants, texture->skin.shirt, texture->skin.nmap, texture->skin.gloss); } + else + R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), rsurface_vertex3f, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f, surface->groupmesh->data_texcoordtexture2f, lightcolor, vec3_origin, vec3_origin, texture->skin.merged ? texture->skin.merged : texture->skin.base, NULL, NULL, texture->skin.nmap, texture->skin.gloss); + if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) + qglEnable(GL_CULL_FACE); } } - */ - poly->numverts = lnumverts; } -/* -======================== -GL_CreateSurfaceLightmap -======================== -*/ -void GL_CreateSurfaceLightmap (msurface_t *surf) +#if 0 +static void gl_surf_start(void) { - int smax, tmax; - - if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) - return; - - smax = (surf->extents[0]>>4)+1; - tmax = (surf->extents[1]>>4)+1; - - 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); - } } - -/* -================== -GL_BuildLightmaps - -Builds the lightmap texture -with all the surfaces from all brush models -================== -*/ -void GL_BuildLightmaps (void) +static void gl_surf_shutdown(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; - - if (gl_lightmaprgba.value) - { - lightmaprgba = true; - lightmapbytes = 4; - } - else - { - lightmaprgba = false; - lightmapbytes = 3; - } - - // 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; - } +} - if (!lightmap_textures) - { - lightmap_textures = texture_extension_number; - texture_extension_number += MAX_LIGHTMAPS; - } +static void gl_surf_newmap(void) +{ +} +#endif - 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); - } - } +void GL_Surf_Init(void) +{ - 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); - } + Cvar_RegisterVariable(&r_ambient); + Cvar_RegisterVariable(&r_drawportals); + Cvar_RegisterVariable(&r_testvis); + Cvar_RegisterVariable(&r_detailtextures); + Cvar_RegisterVariable(&r_surfaceworldnode); + Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor); + Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset); + Cvar_RegisterVariable(&r_q3bsp_renderskydepth); + + //R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap); }