X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_rmain.c;h=490568bb07b0d2b6dcc35b5310e62a2c457b683d;hp=d48dec0a4561f7acf6574bf6b8f4e8c88a10437a;hb=c0be34ed05267d2145bbbdb05c9ed67a06b4f5ac;hpb=cecffffdd5310e387e8b910735ff77aa329cdb43 diff --git a/gl_rmain.c b/gl_rmain.c index d48dec0a..490568bb 100644 --- a/gl_rmain.c +++ b/gl_rmain.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. @@ -21,174 +21,120 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -entity_t r_worldentity; +// used for dlight push checking and other things +int r_framecount; -qboolean r_cache_thrash; // compatability +mplane_t frustum[4]; -vec3_t modelorg, r_entorigin; -entity_t *currententity; +matrix4x4_t r_identitymatrix; -int r_visframecount; // bumped when going to a new PVS -int r_framecount; // used for dlight push checking +int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights; -mplane_t frustum[4]; +// true during envmap command capture +qboolean envmap; -int c_brush_polys, c_alias_polys; +float r_farclip; -qboolean envmap; // true during envmap command capture - -// LordHavoc: moved all code related to particles into r_part.c -//int particletexture; // little dot for particles -int playertextures; // up to 16 color translated skins - -extern qboolean isG200, isRagePro; // LordHavoc: special card hacks - -// // view origin -// -vec3_t vup; -vec3_t vpn; -vec3_t vright; -vec3_t r_origin; - -float r_world_matrix[16]; -float r_base_world_matrix[16]; +vec3_t r_origin; +vec3_t vpn; +vec3_t vright; +vec3_t vup; // // screen size info // -refdef_t r_refdef; - -mleaf_t *r_viewleaf, *r_oldviewleaf; - -texture_t *r_notexture_mip; - -int d_lightstylevalue[256]; // 8.8 fraction of base light value - - -void R_MarkLeaves (void); - -//cvar_t r_norefresh = {"r_norefresh","0"}; -cvar_t r_drawentities = {"r_drawentities","1"}; -cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; -cvar_t r_speeds = {"r_speeds","0"}; -cvar_t r_speeds2 = {"r_speeds2","0"}; -cvar_t r_fullbright = {"r_fullbright","0"}; -//cvar_t r_lightmap = {"r_lightmap","0"}; -//cvar_t r_shadows = {"r_shadows","0"}; -cvar_t r_wateralpha = {"r_wateralpha","1"}; -//cvar_t r_dynamic = {"r_dynamic","1"}; -cvar_t r_novis = {"r_novis","0"}; -cvar_t r_waterripple = {"r_waterripple","0"}; -cvar_t r_fullbrights = {"r_fullbrights", "1"}; - -//cvar_t gl_cull = {"gl_cull","1"}; -//cvar_t gl_affinemodels = {"gl_affinemodels","0"}; -//cvar_t gl_polyblend = {"gl_polyblend","1"}; -//cvar_t gl_flashblend = {"gl_flashblend","0"}; -cvar_t gl_playermip = {"gl_playermip","0"}; -//cvar_t gl_nocolors = {"gl_nocolors","0"}; -//cvar_t gl_keeptjunctions = {"gl_keeptjunctions","1"}; -//cvar_t gl_reporttjunctions = {"gl_reporttjunctions","0"}; -cvar_t contrast = {"contrast", "1.0", TRUE}; // LordHavoc: a method of operating system independent color correction -cvar_t brightness = {"brightness", "1.0", TRUE}; // LordHavoc: a method of operating system independent color correction -cvar_t gl_lightmode = {"gl_lightmode", "1", TRUE}; // LordHavoc: overbright lighting -//cvar_t r_dynamicwater = {"r_dynamicwater", "1"}; -//cvar_t r_dynamicbothsides = {"r_dynamicbothsides", "1"}; // LordHavoc: can disable dynamic lighting of backfaces, but quake maps are weird so it doesn't always work right... - -cvar_t gl_fogenable = {"gl_fogenable", "0"}; -cvar_t gl_fogdensity = {"gl_fogdensity", "0.25"}; -cvar_t gl_fogred = {"gl_fogred","0.3"}; -cvar_t gl_foggreen = {"gl_foggreen","0.3"}; -cvar_t gl_fogblue = {"gl_fogblue","0.3"}; -cvar_t gl_fogstart = {"gl_fogstart", "0"}; -cvar_t gl_fogend = {"gl_fogend","0"}; -cvar_t glfog = {"glfog", "0"}; - -int chrometexture; - -void makechrometextures() +refdef_t r_refdef; + +// 8.8 fraction of base light value +unsigned short d_lightstylevalue[256]; + +cvar_t r_drawentities = {0, "r_drawentities","1"}; +cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"}; +cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "1"}; +cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"}; +cvar_t r_speeds = {0, "r_speeds","0"}; +cvar_t r_fullbright = {0, "r_fullbright","0"}; +cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"}; +cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"}; +cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"}; + +cvar_t gl_fogenable = {0, "gl_fogenable", "0"}; +cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"}; +cvar_t gl_fogred = {0, "gl_fogred","0.3"}; +cvar_t gl_foggreen = {0, "gl_foggreen","0.3"}; +cvar_t gl_fogblue = {0, "gl_fogblue","0.3"}; +cvar_t gl_fogstart = {0, "gl_fogstart", "0"}; +cvar_t gl_fogend = {0, "gl_fogend","0"}; + +cvar_t r_textureunits = {0, "r_textureunits", "32"}; + +void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) { - int x, y, g, g2, amplitude, noise[64][64], min, max; - byte data[64][64][4]; - // - // particle texture - // - chrometexture = texture_extension_number++; - glBindTexture(GL_TEXTURE_2D, chrometexture); - -#define n(x,y) noise[(y)&63][(x)&63] - - amplitude = 16777215; - g2 = 64; - noise[0][0] = 0; - for (;(g = g2 >> 1) >= 1;g2 >>= 1) + int i; + for (i = 0;i < verts;i++) { - // subdivide, diamond-square algorythm (really this has little to do with squares) - // diamond - for (y = 0;y < 64;y += g2) - for (x = 0;x < 64;x += g2) - n(x+g,y+g) = (n(x,y) + n(x+g2,y) + n(x,y+g2) + n(x+g2,y+g2)) >> 2; - // square - for (y = 0;y < 64;y += g2) - for (x = 0;x < 64;x += g2) - { - n(x+g,y) = (n(x,y) + n(x+g2,y) + n(x+g,y-g) + n(x+g,y+g)) >> 2; - n(x,y+g) = (n(x,y) + n(x,y+g2) + n(x-g,y+g) + n(x+g,y+g)) >> 2; - } - // brownian motion theory - amplitude >>= 1; - for (y = 0;y < 64;y += g) - for (x = 0;x < 64;x += g) - noise[y][x] += rand()&litude; + out[0] = in[0] * r; + out[1] = in[1] * g; + out[2] = in[2] * b; + out[3] = in[3]; + in += 4; + out += 4; } - // normalize the noise range - min = max = 0; - for (y = 0;y < 64;y++) - for (x = 0;x < 64;x++) - { - if (n(x,y) < min) min = n(x,y); - if (n(x,y) > max) max = n(x,y); - } - max -= min; - for (y = 0;y < 64;y++) - for (x = 0;x < 64;x++) - n(x,y) = (n(x,y) - min) * 255 / max; +} -#undef n +void R_FillColors(float *out, int verts, float r, float g, float b, float a) +{ + int i; + for (i = 0;i < verts;i++) + { + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = a; + out += 4; + } +} - // convert to RGBA data - for (y = 0;y < 64;y++) - for (x = 0;x < 64;x++) - { - data[y][x][0] = data[y][x][1] = data[y][x][2] = (byte) noise[y][x]; - data[y][x][3] = 255; - } +/* +==================== +R_TimeRefresh_f - glTexImage2D (GL_TEXTURE_2D, 0, 4, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); +For program optimization +==================== +*/ +qboolean intimerefresh = 0; +static void R_TimeRefresh_f (void) +{ + int i; + float start, stop, time; - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + intimerefresh = 1; + start = Sys_DoubleTime (); + for (i = 0;i < 128;i++) + { + r_refdef.viewangles[0] = 0; + r_refdef.viewangles[1] = i/128.0*360.0; + r_refdef.viewangles[2] = 0; + CL_UpdateScreen(); + } - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + stop = Sys_DoubleTime (); + intimerefresh = 0; + time = stop-start; + Con_Printf ("%f seconds (%f fps)\n", time, 128/time); } -extern qboolean isRagePro; - -qboolean lighthalf; - vec3_t fogcolor; vec_t fogdensity; float fog_density, fog_red, fog_green, fog_blue; qboolean fogenabled; qboolean oldgl_fogenable; -void FOG_framebegin() +void R_SetupFog(void) { - if (nehahra) + if (gamemode == GAME_NEHAHRA) { -// if (!Nehahrademcompatibility) -// gl_fogenable.value = 0; - if (gl_fogenable.value) + if (gl_fogenable.integer) { oldgl_fogenable = true; fog_density = gl_fogdensity.value; @@ -205,62 +151,26 @@ void FOG_framebegin() fog_blue = 0; } } - if (glfog.value) + if (fog_density) { - if(fog_density) - { - // LordHavoc: Borland C++ 5.0 was choking on this line, stupid compiler... - //GLfloat colors[4] = {(GLfloat) gl_fogred.value, (GLfloat) gl_foggreen.value, (GLfloat) gl_fogblue.value, (GLfloat) 1}; - GLfloat colors[4]; - colors[0] = fog_red; - colors[1] = fog_green; - colors[2] = fog_blue; - colors[3] = 1; - if (lighthalf) - { - colors[0] *= 0.5f; - colors[1] *= 0.5f; - colors[2] *= 0.5f; - } - - glFogi (GL_FOG_MODE, GL_EXP2); - glFogf (GL_FOG_DENSITY, (GLfloat) fog_density / 100); - glFogfv (GL_FOG_COLOR, colors); - glEnable (GL_FOG); - } - else - glDisable(GL_FOG); + fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f); + fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f); + fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f); } - else + if (fog_density) { - if (fog_density) - { - fogenabled = true; - fogdensity = -4000.0f / (fog_density * fog_density); - fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f); - fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f); - fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f); - if (lighthalf) - { - fogcolor[0] *= 0.5f; - fogcolor[1] *= 0.5f; - fogcolor[2] *= 0.5f; - } - } - else - fogenabled = false; + fogenabled = true; + fogdensity = -4000.0f / (fog_density * fog_density); + // fog color was already set } + else + fogenabled = false; } -void FOG_frameend() -{ - if (glfog.value) - glDisable(GL_FOG); -} - -void FOG_clear() +// FIXME: move this to client? +void FOG_clear(void) { - if (nehahra) + if (gamemode == GAME_NEHAHRA) { Cvar_Set("gl_fogenable", "0"); Cvar_Set("gl_fogdensity", "0.2"); @@ -271,1328 +181,1252 @@ void FOG_clear() fog_density = fog_red = fog_green = fog_blue = 0.0f; } -void FOG_registercvars() +// FIXME: move this to client? +void FOG_registercvars(void) { - Cvar_RegisterVariable (&glfog); - if (nehahra) + if (gamemode == GAME_NEHAHRA) { Cvar_RegisterVariable (&gl_fogenable); Cvar_RegisterVariable (&gl_fogdensity); Cvar_RegisterVariable (&gl_fogred); - Cvar_RegisterVariable (&gl_foggreen); + Cvar_RegisterVariable (&gl_foggreen); Cvar_RegisterVariable (&gl_fogblue); Cvar_RegisterVariable (&gl_fogstart); Cvar_RegisterVariable (&gl_fogend); } } -void glpoly_init(); -void glrsurf_init(); -void rlight_init(); +void gl_main_start(void) +{ +} -// LordHavoc: vertex array -float *aliasvert; -float *aliasvertnorm; -byte *aliasvertcolor; +void gl_main_shutdown(void) +{ +} -void rmain_registercvars() +extern void CL_ParseEntityLump(char *entitystring); +void gl_main_newmap(void) { - // allocate vertex processing arrays - aliasvert = malloc(sizeof(float[MD2MAX_VERTS][3])); - aliasvertnorm = malloc(sizeof(float[MD2MAX_VERTS][3])); - aliasvertcolor = malloc(sizeof(byte[MD2MAX_VERTS][4])); + if (cl.worldmodel && cl.worldmodel->entities) + CL_ParseEntityLump(cl.worldmodel->entities); + r_framecount = 1; +} +void GL_Main_Init(void) +{ + Matrix4x4_CreateIdentity(&r_identitymatrix); +// FIXME: move this to client? FOG_registercvars(); - Cvar_RegisterVariable (&r_speeds2); - Cvar_RegisterVariable (&contrast); - Cvar_RegisterVariable (&brightness); - Cvar_RegisterVariable (&gl_lightmode); -// Cvar_RegisterVariable (&r_dynamicwater); -// Cvar_RegisterVariable (&r_dynamicbothsides); + Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); + Cvar_RegisterVariable (&r_drawentities); + Cvar_RegisterVariable (&r_drawviewmodel); + Cvar_RegisterVariable (&r_shadows); + Cvar_RegisterVariable (&r_shadow_staticworldlights); + Cvar_RegisterVariable (&r_speeds); Cvar_RegisterVariable (&r_fullbrights); - if (nehahra) - Cvar_SetValue("r_fullbrights", 0); -// if (gl_vendor && strstr(gl_vendor, "3Dfx")) -// gl_lightmode.value = 0; + Cvar_RegisterVariable (&r_wateralpha); + Cvar_RegisterVariable (&r_dynamic); Cvar_RegisterVariable (&r_fullbright); - makechrometextures(); - glpoly_init(); - glrsurf_init(); - rlight_init(); + Cvar_RegisterVariable (&r_textureunits); + if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXIUZ) + Cvar_SetValue("r_fullbrights", 0); + R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap); } -/* -void R_RotateForEntity (entity_t *e) -{ - glTranslatef (e->origin[0], e->origin[1], e->origin[2]); - - glRotatef (e->angles[1], 0, 0, 1); - glRotatef (-e->angles[0], 0, 1, 0); - glRotatef (e->angles[2], 1, 0, 0); +vec3_t r_farclip_origin; +vec3_t r_farclip_direction; +vec_t r_farclip_directiondist; +vec_t r_farclip_meshfarclip; +int r_farclip_directionbit0; +int r_farclip_directionbit1; +int r_farclip_directionbit2; - glScalef (e->scale, e->scale, e->scale); // LordHavoc: model scale +// start a farclip measuring session +void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip) +{ + VectorCopy(origin, r_farclip_origin); + VectorCopy(direction, r_farclip_direction); + r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction); + r_farclip_directionbit0 = r_farclip_direction[0] < 0; + r_farclip_directionbit1 = r_farclip_direction[1] < 0; + r_farclip_directionbit2 = r_farclip_direction[2] < 0; + r_farclip_meshfarclip = r_farclip_directiondist + startfarclip; } -*/ - -// LordHavoc: if not for the fact BRIGHTFIELD particles require this, it would be removed... -#define NUMVERTEXNORMALS 162 - -float r_avertexnormals[NUMVERTEXNORMALS][3] = { -#include "anorms.h" -}; -// LordHavoc: moved this shading stuff up because the sprites need shading stuff -vec3_t shadevector; -vec3_t shadecolor; - -float modelalpha; - -void R_LightPoint (vec3_t color, vec3_t p); -void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits); -void R_DynamicLightPointNoMask(vec3_t color, vec3_t org); +// enlarge farclip to accomodate box +void R_FarClip_Box(vec3_t mins, vec3_t maxs) +{ + float d; + d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0] + + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1] + + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2]; + if (r_farclip_meshfarclip < d) + r_farclip_meshfarclip = d; +} -float R_CalcAnimLerp(int pose, float lerpscale) +// return farclip value +float R_FarClip_Finish(void) { - if (currententity->draw_lastmodel == currententity->model && currententity->draw_lerpstart <= cl.time) - { - if (pose != currententity->draw_pose) - { - currententity->draw_lastpose = currententity->draw_pose; - currententity->draw_pose = pose; - currententity->draw_lerpstart = cl.time; - return 0; - } - else - return ((cl.time - currententity->draw_lerpstart) * lerpscale); - } - else // uninitialized - { - currententity->draw_lastmodel = currententity->model; - currententity->draw_lastpose = currententity->draw_pose = pose; - currententity->draw_lerpstart = cl.time; - return 0; - } + return r_farclip_meshfarclip - r_farclip_directiondist; } /* -============================================================= - - SPRITE MODELS - -============================================================= +=============== +R_NewMap +=============== */ +void R_NewMap (void) +{ + R_Modules_NewMap(); +} + +extern void R_Textures_Init(void); +extern void Mod_RenderInit(void); +extern void GL_Draw_Init(void); +extern void GL_Main_Init(void); +extern void R_Shadow_Init(void); +extern void GL_Models_Init(void); +extern void R_Sky_Init(void); +extern void GL_Surf_Init(void); +extern void R_Crosshairs_Init(void); +extern void R_Light_Init(void); +extern void R_Particles_Init(void); +extern void R_Explosion_Init(void); +extern void ui_init(void); +extern void gl_backend_init(void); +extern void Sbar_Init(void); + +void Render_Init(void) +{ + R_Textures_Init(); + Mod_RenderInit(); + gl_backend_init(); + R_MeshQueue_Init(); + GL_Draw_Init(); + GL_Main_Init(); + R_Shadow_Init(); + GL_Models_Init(); + R_Sky_Init(); + GL_Surf_Init(); + R_Crosshairs_Init(); + R_Light_Init(); + R_Particles_Init(); + R_Explosion_Init(); + ui_init(); + Sbar_Init(); +} /* -================ -R_GetSpriteFrame -================ +=============== +GL_Init +=============== */ -void R_GetSpriteFrame (entity_t *currententity, mspriteframe_t **oldframe, mspriteframe_t **newframe, float *framelerp) +extern char *ENGINE_EXTENSIONS; +void GL_Init (void) { - msprite_t *psprite; - mspritegroup_t *pspritegroup; - int i, j, numframes, frame; - float *pintervals, fullinterval, targettime, time, jtime, jinterval; + VID_CheckExtensions(); - psprite = currententity->model->cache.data; - frame = currententity->frame; + // LordHavoc: report supported extensions + Con_Printf ("\nengine extensions: %s\n", ENGINE_EXTENSIONS); +} - if ((frame >= psprite->numframes) || (frame < 0)) +int R_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int i; + mplane_t *p; + for (i = 0;i < 4;i++) { - Con_Printf ("R_DrawSprite: no such frame %d\n", frame); - frame = 0; + p = frustum + i; + switch(p->signbits) + { + default: + case 0: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 1: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 2: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 3: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) + return true; + break; + case 4: + if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 5: + if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 6: + if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + case 7: + if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) + return true; + break; + } } + return false; +} - if (psprite->frames[frame].type == SPR_SINGLE) +int PVS_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int stackpos, sides; + mnode_t *node, *stack[4096]; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) { - if (currententity->draw_lastmodel == currententity->model && currententity->draw_lerpstart < cl.time) + node = stack[--stackpos]; + if (node->contents < 0) { - if (frame != currententity->draw_pose) - { - currententity->draw_lastpose = currententity->draw_pose; - currententity->draw_pose = frame; - currententity->draw_lerpstart = cl.time; - *framelerp = 0; - } - else - *framelerp = (cl.time - currententity->draw_lerpstart) * 10.0; + if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount) + return false; } - else // uninitialized + else { - currententity->draw_lastmodel = currententity->model; - currententity->draw_lastpose = currententity->draw_pose = frame; - currententity->draw_lerpstart = cl.time; - *framelerp = 0; + sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides & 2 && stackpos < 4096) + stack[stackpos++] = node->children[1]; + if (sides & 1 && stackpos < 4096) + stack[stackpos++] = node->children[0]; } - *oldframe = psprite->frames[currententity->draw_lastpose].frameptr; - *newframe = psprite->frames[frame].frameptr; } - else - { - pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; - pintervals = pspritegroup->intervals; - numframes = pspritegroup->numframes; - fullinterval = pintervals[numframes-1]; - - time = cl.time + currententity->syncbase; - - // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values - // are positive, so we don't have to worry about division by 0 - targettime = time - ((int)(time / fullinterval)) * fullinterval; + return true; +} - // LordHavoc: since I can't measure the time properly when it loops from numframes-1 to 0, - // I instead measure the time of the first frame, hoping it is consistent - j = numframes-1;jtime = 0;jinterval = pintervals[1] - pintervals[0]; - for (i=0 ; i<(numframes-1) ; i++) +int VIS_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int stackpos, sides; + mnode_t *node, *stack[4096]; + if (R_CullBox(mins, maxs)) + return true; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) + { + node = stack[--stackpos]; + if (node->contents < 0) { - if (pintervals[i] > targettime) - break; - j = i;jinterval = pintervals[i] - jtime;jtime = pintervals[i]; + if (((mleaf_t *)node)->visframe == r_framecount) + return false; + } + else + { + sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides & 2 && stackpos < 4096) + stack[stackpos++] = node->children[1]; + if (sides & 1 && stackpos < 4096) + stack[stackpos++] = node->children[0]; } - *framelerp = (targettime - jtime) / jinterval; - - *oldframe = pspritegroup->frames[j]; - *newframe = pspritegroup->frames[i]; } + return true; } -void GL_DrawSpriteImage (mspriteframe_t *frame, vec3_t origin, vec3_t up, vec3_t right, int red, int green, int blue, int alpha) +int R_CullSphere(const vec3_t origin, vec_t radius) { - // LordHavoc: rewrote this to use the transparent poly system - transpolybegin(frame->gl_texturenum, 0, frame->gl_fogtexturenum, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); - transpolyvert(origin[0] + frame->down * up[0] + frame->left * right[0], origin[1] + frame->down * up[1] + frame->left * right[1], origin[2] + frame->down * up[2] + frame->left * right[2], 0, 1, red, green, blue, alpha); - transpolyvert(origin[0] + frame->up * up[0] + frame->left * right[0], origin[1] + frame->up * up[1] + frame->left * right[1], origin[2] + frame->up * up[2] + frame->left * right[2], 0, 0, red, green, blue, alpha); - transpolyvert(origin[0] + frame->up * up[0] + frame->right * right[0], origin[1] + frame->up * up[1] + frame->right * right[1], origin[2] + frame->up * up[2] + frame->right * right[2], 1, 0, red, green, blue, alpha); - transpolyvert(origin[0] + frame->down * up[0] + frame->right * right[0], origin[1] + frame->down * up[1] + frame->right * right[1], origin[2] + frame->down * up[2] + frame->right * right[2], 1, 1, red, green, blue, alpha); - transpolyend(); + return (DotProduct(frustum[0].normal, origin) + radius < frustum[0].dist + || DotProduct(frustum[1].normal, origin) + radius < frustum[1].dist + || DotProduct(frustum[2].normal, origin) + radius < frustum[2].dist + || DotProduct(frustum[3].normal, origin) + radius < frustum[3].dist); } -extern qboolean isG200, isRagePro, lighthalf; - -/* -================= -R_DrawSpriteModel - -================= -*/ -void R_DrawSpriteModel (entity_t *e) +int PVS_CullSphere(const vec3_t origin, vec_t radius) { - mspriteframe_t *oldframe, *newframe; - float *up, *right, lerp, ilerp; - vec3_t v_forward, v_right, v_up, org; - msprite_t *psprite; - - // don't even bother culling, because it's just a single - // polygon without a surface cache - R_GetSpriteFrame (e, &oldframe, &newframe, &lerp); - if (lerp < 0) lerp = 0; - if (lerp > 1) lerp = 1; - if (isRagePro) // LordHavoc: no alpha scaling supported on per pixel alpha images on ATI Rage Pro... ACK! - lerp = 1; - ilerp = 1.0 - lerp; - psprite = e->model->cache.data; - - if (psprite->type == SPR_ORIENTED) - { // bullet marks on walls - AngleVectors (e->angles, v_forward, v_right, v_up); - up = v_up; - right = v_right; - VectorSubtract(e->origin, vpn, org); - } - else - { // normal sprite - up = vup; - right = vright; - VectorCopy(e->origin, org); - } - if (e->scale != 1) - { - VectorScale(up, e->scale, up); - VectorScale(right, e->scale, right); - } - - if (e->model->flags & EF_FULLBRIGHT || e->effects & EF_FULLBRIGHT) + int stackpos; + mnode_t *node, *stack[4096]; + float dist; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) { - if (lighthalf) + node = stack[--stackpos]; + if (node->contents < 0) { - shadecolor[0] = e->colormod[0] * 128; - shadecolor[1] = e->colormod[1] * 128; - shadecolor[2] = e->colormod[2] * 128; + if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount) + return false; } else { - shadecolor[0] = e->colormod[0] * 255; - shadecolor[1] = e->colormod[1] * 255; - shadecolor[2] = e->colormod[2] * 255; + dist = PlaneDiff(origin, node->plane); + if (dist <= radius) + stack[stackpos++] = node->children[1]; + if (dist >= -radius) + stack[stackpos++] = node->children[0]; } } - else + return true; +} + +int VIS_CullSphere(const vec3_t origin, vec_t radius) +{ + int stackpos; + mnode_t *node, *stack[4096]; + float dist; + if (R_CullSphere(origin, radius)) + return true; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) { - R_LightPoint (shadecolor, e->origin); - R_DynamicLightPointNoMask(shadecolor, e->origin); - if (lighthalf) + node = stack[--stackpos]; + if (node->contents < 0) + { + if (((mleaf_t *)node)->visframe == r_framecount) + return false; + } + else { - shadecolor[0] *= e->colormod[0] * 0.5; - shadecolor[1] *= e->colormod[1] * 0.5; - shadecolor[2] *= e->colormod[2] * 0.5; + dist = PlaneDiff(origin, node->plane); + if (dist <= radius) + stack[stackpos++] = node->children[1]; + if (dist >= -radius) + stack[stackpos++] = node->children[0]; } } - - // LordHavoc: interpolated sprite rendering - if (ilerp != 0) - GL_DrawSpriteImage(oldframe, org, up, right, shadecolor[0],shadecolor[1],shadecolor[2],e->alpha*255*ilerp); - if (lerp != 0) - GL_DrawSpriteImage(newframe, org, up, right, shadecolor[0],shadecolor[1],shadecolor[2],e->alpha*255*lerp); + return true; } -/* -============================================================= - - ALIAS MODELS -============================================================= -*/ +//================================================================================== -extern vec3_t softwaretransform_x; -extern vec3_t softwaretransform_y; -extern vec3_t softwaretransform_z; -extern vec_t softwaretransform_scale; -extern vec3_t softwaretransform_offset; -void R_AliasLerpVerts(int vertcount, float lerp, trivert2 *verts1, vec3_t scale1, vec3_t translate1, trivert2 *verts2, vec3_t scale2, vec3_t translate2) +static void R_MarkEntities (void) { int i; - vec3_t point, matrix_x, matrix_y, matrix_z; - float *av, *avn; - av = aliasvert; - avn = aliasvertnorm; - if (lerp < 0) lerp = 0; - if (lerp > 1) lerp = 1; - if (lerp != 0) + vec3_t v; + entity_render_t *ent; + + ent = &cl_entities[0].render; + Matrix4x4_CreateIdentity(&ent->matrix); + Matrix4x4_CreateIdentity(&ent->inversematrix); + + if (cl.worldmodel) + R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs); + + if (!r_drawentities.integer) + return; + + for (i = 0;i < r_refdef.numentities;i++) { - float ilerp, ilerp127, lerp127, scalex1, scalex2, translatex, scaley1, scaley2, translatey, scalez1, scalez2, translatez; - if (lerp < 0) lerp = 0; - if (lerp > 1) lerp = 1; - ilerp = 1 - lerp; - ilerp127 = ilerp * (1.0 / 127.0); - lerp127 = lerp * (1.0 / 127.0); - VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x); - VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y); - VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z); - // calculate combined interpolation variables - scalex1 = scale1[0] * ilerp;scalex2 = scale2[0] * lerp;translatex = translate1[0] * ilerp + translate2[0] * lerp; - scaley1 = scale1[1] * ilerp;scaley2 = scale2[1] * lerp;translatey = translate1[1] * ilerp + translate2[1] * lerp; - scalez1 = scale1[2] * ilerp;scalez2 = scale2[2] * lerp;translatez = translate1[2] * ilerp + translate2[2] * lerp; - // generate vertices - for (i = 0;i < vertcount;i++) + ent = r_refdef.entities[i]; + Mod_CheckLoaded(ent->model); + + // move view-relative models to where they should be + if (ent->flags & RENDER_VIEWMODEL) { - // rotate, scale, and translate the vertex locations - point[0] = verts1->v[0] * scalex1 + verts2->v[0] * scalex2 + translatex; - point[1] = verts1->v[1] * scaley1 + verts2->v[1] * scaley2 + translatey; - point[2] = verts1->v[2] * scalez1 + verts2->v[2] * scalez2 + translatez; - *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0]; - *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1]; - *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2]; - // rotate the normals - point[0] = verts1->n[0] * ilerp127 + verts2->n[0] * lerp127; - point[1] = verts1->n[1] * ilerp127 + verts2->n[1] * lerp127; - point[2] = verts1->n[2] * ilerp127 + verts2->n[2] * lerp127; - *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0]; - *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1]; - *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2]; - verts1++;verts2++; + // remove flag so it will not be repeated incase RelinkEntities is not called again for a while + ent->flags -= RENDER_VIEWMODEL; + // transform origin + VectorCopy(ent->origin, v); + ent->origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_origin[0]; + ent->origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_origin[1]; + ent->origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_origin[2]; + // adjust angles + VectorAdd(ent->angles, r_refdef.viewangles, ent->angles); + } + + VectorCopy(ent->angles, v); + if (!ent->model || ent->model->type != mod_brush) + v[0] = -v[0]; + Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], v[0], v[1], v[2], ent->scale); + Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix); + R_LerpAnimation(ent); + R_UpdateEntLights(ent); + if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL)) + && !VIS_CullSphere(ent->origin, ent->model->radius * ent->scale) + && !VIS_CullBox(ent->mins, ent->maxs)) + { + ent->visframe = r_framecount; + R_FarClip_Box(ent->mins, ent->maxs); } } - else +} + +// only used if skyrendermasked, and normally returns false +int R_DrawBrushModelsSky (void) +{ + int i, sky; + entity_render_t *ent; + + if (!r_drawentities.integer) + return false; + + sky = false; + for (i = 0;i < r_refdef.numentities;i++) { - float i127; - i127 = 1.0f / 127.0f; - VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x); - VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y); - VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z); - // generate vertices - for (i = 0;i < vertcount;i++) + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky) { - // rotate, scale, and translate the vertex locations - point[0] = verts1->v[0] * scale1[0] + translate1[0]; - point[1] = verts1->v[1] * scale1[1] + translate1[1]; - point[2] = verts1->v[2] * scale1[2] + translate1[2]; - *av++ = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0]; - *av++ = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1]; - *av++ = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2]; - // rotate the normals - point[0] = verts1->n[0] * i127; - point[1] = verts1->n[1] * i127; - point[2] = verts1->n[2] * i127; - *avn++ = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0]; - *avn++ = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1]; - *avn++ = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2]; - verts1++; + ent->model->DrawSky(ent); + sky = true; } } + return sky; } /* -================= -R_DrawAliasFrame - -================= +============= +R_DrawViewModel +============= */ -extern vec3_t lightspot; -void R_LightModel(int numverts, vec3_t center); -extern cvar_t gl_vertexarrays; -void R_DrawAliasFrame (aliashdr_t *paliashdr) +/* +void R_DrawViewModel (void) { - int i, pose, frame = currententity->frame; - float lerpscale, lerp; + entity_render_t *ent; - softwaretransformforentity(currententity); + // FIXME: move these checks to client + if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model) + return; - if ((frame >= paliashdr->numframes) || (frame < 0)) - { - Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); - frame = 0; - } + ent = &cl.viewent.render; + Mod_CheckLoaded(ent->model); + R_LerpAnimation(ent); + Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale); + Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix); + R_UpdateEntLights(ent); + ent->model->Draw(ent); +} +*/ - pose = paliashdr->frames[frame].firstpose; +void R_DrawNoModel(entity_render_t *ent); +void R_DrawModels () +{ + int i; + entity_render_t *ent; - if (paliashdr->frames[frame].numposes > 1) + if (!r_drawentities.integer) + return; + + for (i = 0;i < r_refdef.numentities;i++) { - lerpscale = 1.0 / paliashdr->frames[frame].interval; - pose += (int)(cl.time * lerpscale) % paliashdr->frames[frame].numposes; + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount) + { + if (ent->model && ent->model->Draw != NULL) + ent->model->Draw(ent); + else + R_DrawNoModel(ent); + } } - else - lerpscale = 10.0; - - lerp = R_CalcAnimLerp(pose, lerpscale); +} - R_AliasLerpVerts(paliashdr->numverts, lerp, (trivert2 *)((byte *)paliashdr + paliashdr->posedata) + currententity->draw_lastpose * paliashdr->numverts, paliashdr->scale, paliashdr->scale_origin, (trivert2 *)((byte *)paliashdr + paliashdr->posedata) + currententity->draw_pose * paliashdr->numverts, paliashdr->scale, paliashdr->scale_origin); +void R_DrawFakeShadows (void) +{ + int i; + entity_render_t *ent; - R_LightModel(paliashdr->numverts, currententity->origin); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawFakeShadow) + ent->model->DrawFakeShadow(ent); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glShadeModel(GL_SMOOTH); - if (currententity->effects & EF_ADDITIVE) - { - glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering - glEnable(GL_BLEND); - glDepthMask(0); - } - else if (modelalpha != 1.0) - { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glDepthMask(0); - } - else + if (!r_drawentities.integer) + return; + for (i = 0;i < r_refdef.numentities;i++) { - glDisable(GL_BLEND); - glDepthMask(1); + ent = r_refdef.entities[i]; + if (ent->model && ent->model->DrawFakeShadow) + ent->model->DrawFakeShadow(ent); } +} - if (gl_vertexarrays.value) - { - // LordHavoc: I would use InterleavedArrays here, - // but the texture coordinates are a seperate array, - // and it would be wasteful to copy them into the main array... - // glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha); - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - // draw the front faces - qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + (int) paliashdr)); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglDrawElements(GL_TRIANGLES, paliashdr->frontfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr)); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - // draw the back faces - qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) paliashdr->texcoords + sizeof(float[2]) * paliashdr->numverts + (int) paliashdr)); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglDrawElements(GL_TRIANGLES, paliashdr->backfaces * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + sizeof(unsigned short[3]) * paliashdr->frontfaces + (int) paliashdr)); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - } - else +#include "r_shadow.h" + +int shadowframecount = 0; + +int Light_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int stackpos, sides; + mnode_t *node, *stack[4096]; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) { - unsigned short *in, index; - float *tex; - in = (void *)((int) paliashdr->vertindices + (int) paliashdr); - glBegin(GL_TRIANGLES); - // draw the front faces - tex = (void *)((int) paliashdr->texcoords + (int) paliashdr); - //if (isG200) - //{ - for (i = 0;i < paliashdr->frontfaces * 3;i++) - { - index = *in++; - glTexCoord2f(tex[index*2], tex[index*2+1]); - glColor4f(aliasvertcolor[index*4] * (1.0f / 255.0f), aliasvertcolor[index*4+1] * (1.0f / 255.0f), aliasvertcolor[index*4+2] * (1.0f / 255.0f), aliasvertcolor[index*4+3] * (1.0f / 255.0f)); - glVertex3fv(&aliasvert[index*3]); - } - /* - } - else + node = stack[--stackpos]; + if (node->contents < 0) { - for (i = 0;i < paliashdr->frontfaces * 3;i++) - { - index = *in++; - glTexCoord2f(tex[index*2], tex[index*2+1]); - glColor4ub(aliasvertcolor[index*4], aliasvertcolor[index*4+1], aliasvertcolor[index*4+2], aliasvertcolor[index*4+3]); - glVertex3fv(&aliasvert[index*3]); - } - } - */ - // draw the back faces - tex += 2 * paliashdr->numverts; - //if (isG200) - //{ - for (i = 0;i < paliashdr->backfaces * 3;i++) - { - index = *in++; - glTexCoord2f(tex[index*2], tex[index*2+1]); - glColor4f(aliasvertcolor[index*4] * (1.0f / 255.0f), aliasvertcolor[index*4+1] * (1.0f / 255.0f), aliasvertcolor[index*4+2] * (1.0f / 255.0f), aliasvertcolor[index*4+3] * (1.0f / 255.0f)); - glVertex3fv(&aliasvert[index*3]); - } - /* + if (((mleaf_t *)node)->worldnodeframe == shadowframecount) + return false; } else { - for (i = 0;i < paliashdr->backfaces * 3;i++) - { - index = *in++; - glTexCoord2f(tex[index*2], tex[index*2+1]); - glColor4ub(aliasvertcolor[index*4], aliasvertcolor[index*4+1], aliasvertcolor[index*4+2], aliasvertcolor[index*4+3]); - glVertex3fv(&aliasvert[index*3]); - } + sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides & 2 && stackpos < 4096) + stack[stackpos++] = node->children[1]; + if (sides & 1 && stackpos < 4096) + stack[stackpos++] = node->children[0]; } - */ - glEnd(); } + return true; +} - if (fogenabled) +int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs) +{ + int stackpos, sides; + mnode_t *node, *stack[4096]; + if (R_CullBox(mins, maxs)) + return true; + stackpos = 0; + stack[stackpos++] = cl.worldmodel->nodes; + while (stackpos) { - vec3_t diff; - glDisable (GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(0); // disable zbuffer updates - - VectorSubtract(currententity->origin, r_refdef.vieworg, diff); - glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff))); - - if (gl_vertexarrays.value) + node = stack[--stackpos]; + if (node->contents < 0) { - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - glEnableClientState(GL_VERTEX_ARRAY); - qglDrawElements(GL_TRIANGLES, paliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr)); - glDisableClientState(GL_VERTEX_ARRAY); + if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount) + return false; } else { - unsigned short *in; - in = (void *)((int) paliashdr->vertindices + (int) paliashdr); - glBegin(GL_TRIANGLES); - for (i = 0;i < paliashdr->numtris * 3;i++) - glVertex3fv(&aliasvert[*in++ * 3]); - glEnd(); + sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides & 2 && stackpos < 4096) + stack[stackpos++] = node->children[1]; + if (sides & 1 && stackpos < 4096) + stack[stackpos++] = node->children[0]; } - - glEnable (GL_TEXTURE_2D); - glColor3f (1,1,1); } + return true; +} - /* - if (r_shadows.value && !(currententity->effects & EF_ADDITIVE) && currententity != &cl.viewent) + +void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t clipmins, vec3_t clipmaxs) +{ + int i; + vec3_t p, p2, temp, relativelightorigin, mins, maxs; + float dist, projectdistance; + // rough checks + if (ent->model && ent->model->DrawShadowVolume) { - // flatten it to make a shadow - float *av = aliasvert + 2, l = lightspot[2] + 0.125; - av = aliasvert + 2; - for (i = 0;i < paliashdr->numverts;i++, av+=3) - if (*av > l) - *av = l; - glDisable (GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(0); // disable zbuffer updates - glColor4f (0,0,0,0.5 * modelalpha); - - if (gl_vertexarrays.value) + temp[0] = bound(ent->mins[0], lightorigin[0], ent->maxs[0]) - lightorigin[0]; + temp[1] = bound(ent->mins[1], lightorigin[1], ent->maxs[1]) - lightorigin[1]; + temp[2] = bound(ent->mins[2], lightorigin[2], ent->maxs[2]) - lightorigin[2]; + dist = DotProduct(temp, temp); + if (dist < cullradius * cullradius) { - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - glEnableClientState(GL_VERTEX_ARRAY); - qglDrawElements(GL_TRIANGLES, paliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) paliashdr->vertindices + (int) paliashdr)); - glDisableClientState(GL_VERTEX_ARRAY); + if (!Light_CullBox(ent->mins, ent->maxs)) + { + projectdistance = cullradius - sqrt(dist); + // calculate projected bounding box and decide if it is on-screen + VectorCopy(ent->mins, mins); + VectorCopy(ent->maxs, maxs); + for (i = 0;i < 8;i++) + { + p[0] = i & 1 ? ent->maxs[0] : ent->mins[0]; + p[1] = i & 2 ? ent->maxs[1] : ent->mins[1]; + p[2] = i & 4 ? ent->maxs[2] : ent->mins[2]; + VectorSubtract(p, lightorigin, temp); + dist = projectdistance / sqrt(DotProduct(temp, temp)); + VectorMA(p, dist, temp, p2); + if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0]; + if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1]; + if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2]; + } + if (mins[0] < clipmaxs[0] && maxs[0] > clipmins[0] + && mins[1] < clipmaxs[1] && maxs[1] > clipmins[1] + && mins[2] < clipmaxs[2] && maxs[2] > clipmins[2] + && !LightAndVis_CullBox(mins, maxs)) + { + Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin); + ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius); + } + } } - else + } +} + +void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light); + +#define SHADOWSPHERE_SEGMENTS 16 + +shadowmesh_t *shadowsphere; +void R_CreateShadowSphere(void) +{ + int i, j; + vec3_t angles, angles2, angles3, angles4; + float verts[12]; + shadowsphere = Mod_ShadowMesh_Begin(zonemempool, SHADOWSPHERE_SEGMENTS * SHADOWSPHERE_SEGMENTS / 2); + for (i = 0;i < SHADOWSPHERE_SEGMENTS / 2;i++) + { + for (j = 0;j < SHADOWSPHERE_SEGMENTS;j++) { - unsigned short *in; - in = (void *)((int) paliashdr->vertindices + (int) paliashdr); - glBegin(GL_TRIANGLES); - for (i = 0;i < paliashdr->numtris * 3;i++) - glVertex3fv(&aliasvert[*in++ * 3]); - glEnd(); + angles[0] = (i * 360.0f / SHADOWSPHERE_SEGMENTS) + 90.0f; + angles[1] = j * 360.0f / SHADOWSPHERE_SEGMENTS; + angles[2] = 0; + VectorCopy(angles, angles2); + VectorCopy(angles, angles3); + VectorCopy(angles, angles4); + angles2[1] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles3[0] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles3[1] += 360.0f / SHADOWSPHERE_SEGMENTS; + angles4[0] += 360.0f / SHADOWSPHERE_SEGMENTS; + AngleVectorsFLU(angles, verts, NULL, NULL); + AngleVectorsFLU(angles2, verts + 9, NULL, NULL); + AngleVectorsFLU(angles3, verts + 6, NULL, NULL); + AngleVectorsFLU(angles4, verts + 3, NULL, NULL); + VectorScale(&verts[0], 1.0f, &verts[0]); + VectorScale(&verts[3], 1.0f, &verts[3]); + VectorScale(&verts[6], 1.0f, &verts[6]); + VectorScale(&verts[9], 1.0f, &verts[9]); + Mod_ShadowMesh_AddPolygon(zonemempool, shadowsphere, 4, verts); } - - glEnable (GL_TEXTURE_2D); - glColor3f (1,1,1); } - */ - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(1); + shadowsphere = Mod_ShadowMesh_Finish(zonemempool, shadowsphere); } -/* -================= -R_DrawQ2AliasFrame -================= -*/ -void R_DrawQ2AliasFrame (md2mem_t *pheader) +void R_DrawShadowSphere(vec3_t origin, float cullradius, float lightradius) { - int *order, count, frame = currententity->frame; - float lerp; - md2memframe_t *frame1, *frame2; - - softwaretransformforentity(currententity); + shadowmesh_t *mesh; + matrix4x4_t matrix; + if (!shadowsphere) + R_CreateShadowSphere(); + Matrix4x4_CreateScale(&matrix, lightradius); + Matrix4x4_ConcatTranslate(&matrix, origin[0], origin[1], origin[2]); + R_Mesh_Matrix(&matrix); + for (mesh = shadowsphere;mesh;mesh = mesh->next) + { + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements); + } + Matrix4x4_CreateScale(&matrix, -cullradius); + Matrix4x4_ConcatTranslate(&matrix, origin[0], origin[1], origin[2]); + R_Mesh_Matrix(&matrix); + for (mesh = shadowsphere;mesh;mesh = mesh->next) + { + memcpy(varray_vertex, mesh->verts, mesh->numverts * sizeof(float[4])); + R_Shadow_RenderVolume(mesh->numverts, mesh->numtriangles, mesh->elements); + } +} - if ((frame >= pheader->num_frames) || (frame < 0)) +extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces); +void R_ShadowVolumeLighting (int visiblevolumes) +{ + int i; + entity_render_t *ent; + int lnum; + float f, lightradius, cullradius; + vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs; + worldlight_t *wl; + //mlight_t *sl; + rdlight_t *rd; + rmeshstate_t m; + mleaf_t *leaf; + + if (visiblevolumes) { - Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame); - frame = 0; + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ONE; + if (r_shadow_realtime.integer >= 3) + m.depthdisable = true; + R_Mesh_State(&m); + qglDisable(GL_CULL_FACE); + GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1); } + else + R_Shadow_Stage_Begin(); + shadowframecount++; + for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++) + { + if (d_lightstylevalue[wl->style] <= 0) + continue; + cullradius = wl->cullradius; + lightradius = wl->lightradius; + if (R_CullSphere(wl->origin, lightradius)) + continue; + //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius)) + // continue; + //if (VIS_CullBox(wl->mins, wl->maxs) || VIS_CullSphere(wl->origin, lightradius)) + // continue; + if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer) + continue; - lerp = R_CalcAnimLerp(frame, 10); + for (i = 0;i < wl->numleafs;i++) + if (wl->leafs[i]->visframe == r_framecount) + break; + if (i == wl->numleafs) + continue; + leaf = wl->leafs[i]; + VectorCopy(leaf->mins, clipmins); + VectorCopy(leaf->maxs, clipmaxs); + for (i = 0;i < wl->numleafs;i++) + { + leaf = wl->leafs[i]; + if (leaf->visframe == r_framecount) + { + if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0]; + if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0]; + if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1]; + if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1]; + if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2]; + if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2]; + } + } + if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0]; + if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1]; + if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2]; + if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0]; + if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1]; + if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2]; + + if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius)) + continue; - frame1 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * currententity->draw_lastpose)); - frame2 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * currententity->draw_pose)); - R_AliasLerpVerts(pheader->num_xyz, lerp, frame1->verts, frame1->scale, frame1->translate, frame2->verts, frame2->scale, frame2->translate); + // mark the leafs we care about so only things in those leafs will matter + for (i = 0;i < wl->numleafs;i++) + wl->leafs[i]->worldnodeframe = shadowframecount; - R_LightModel(pheader->num_xyz, currententity->origin); - if (gl_vertexarrays.value) - { - // LordHavoc: big mess... - // using arrays only slightly, although it is enough to prevent duplicates - // (saving half the transforms) - //glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha); - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - order = (int *)((int)pheader + pheader->ofs_glcmds); - while(1) + f = d_lightstylevalue[wl->style] * (1.0f / 256.0f); + VectorScale(wl->light, f, lightcolor); + if (wl->selected) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else - { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - do + f = 2 + sin(realtime * M_PI * 4.0); + VectorScale(lightcolor, f, lightcolor); + } + + if (!visiblevolumes) + R_Shadow_Stage_ShadowVolumes(); + ent = &cl_entities[0].render; + if (wl->shadowvolume && r_shadow_staticworldlights.integer) + R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl); + else + R_TestAndDrawShadowVolume(ent, wl->origin, cullradius / ent->scale, lightradius / ent->scale, clipmins, clipmaxs); + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) { - glTexCoord2f(((float *)order)[0], ((float *)order)[1]); - qglArrayElement(order[2]); - order += 3; + ent = r_refdef.entities[i]; + if (ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0] + && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1] + && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2] + && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius / ent->scale, lightradius / ent->scale, clipmins, clipmaxs); } - while (count--); } - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - } - else - { - order = (int *)((int)pheader + pheader->ofs_glcmds); - while(1) + if (!visiblevolumes) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else + R_Shadow_Stage_Light(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - //if (isG200) - //{ - do - { - glTexCoord2f(((float *)order)[0], ((float *)order)[1]); - glColor4f(aliasvertcolor[order[2] * 4] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 1] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 2] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 3] * (1.0f / 255.0f)); - glVertex3fv(&aliasvert[order[2] * 3]); - order += 3; - } - while (count--); - /* + Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + if (wl->numsurfaces) + R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces); + else + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor); } - else + if (r_drawentities.integer) { - do + for (i = 0;i < r_refdef.numentities;i++) { - glTexCoord2f(((float *)order)[0], ((float *)order)[1]); - glColor4ub(aliasvertcolor[order[2] * 4], aliasvertcolor[order[2] * 4 + 1], aliasvertcolor[order[2] * 4 + 2], aliasvertcolor[order[2] * 4 + 3]); - glVertex3fv(&aliasvert[order[2] * 3]); - order += 3; + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && ent->maxs[0] >= wl->mins[0] && ent->mins[0] <= wl->maxs[0] + && ent->maxs[1] >= wl->mins[1] && ent->mins[1] <= wl->maxs[1] + && ent->maxs[2] >= wl->mins[2] && ent->mins[2] <= wl->maxs[2] + && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + { + Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor); + } } - while (count--); } - */ } } - - if (fogenabled) + /* + for (lnum = 0, sl = cl.worldmodel->lights;lnum < cl.worldmodel->numlights;lnum++, sl++) { - glDisable (GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(0); // disable zbuffer updates - { - vec3_t diff; - VectorSubtract(currententity->origin, r_refdef.vieworg, diff); - glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff))); - } + if (d_lightstylevalue[sl->style] <= 0) + continue; + if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer) + continue; + cullradius = sl->cullradius; + lightradius = sl->lightradius; + if (VIS_CullBox(sl->mins, sl->maxs) || VIS_CullSphere(sl->origin, lightradius)) + continue; - if (gl_vertexarrays.value) + f = d_lightstylevalue[sl->style] * (1.0f / 32768.0f); + VectorScale(sl->light, f, lightcolor); + + if (!visiblevolumes) + R_Shadow_Stage_ShadowVolumes(); + if (sl->shadowvolume && r_shadow_staticworldlights.integer) + R_DrawWorldLightShadowVolume(&cl_entities[0].render.matrix, sl->shadowvolume); + else + R_TestAndDrawShadowVolume(&cl_entities[0].render, sl->origin, cullradius, lightradius); + if (r_drawentities.integer) { - // LordHavoc: big mess... - // using arrays only slightly, although it is enough to prevent duplicates - // (saving half the transforms) - //glColor4f(shadecolor[0], shadecolor[1], shadecolor[2], modelalpha); - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - glEnableClientState(GL_VERTEX_ARRAY); - - order = (int *)((int)pheader + pheader->ofs_glcmds); - while(1) + for (i = 0;i < r_refdef.numentities;i++) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else - { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - do - { - qglArrayElement(order[2]); - order += 3; - } - while (count--); + ent = r_refdef.entities[i]; + if (ent->maxs[0] >= sl->mins[0] && ent->mins[0] <= sl->maxs[0] + && ent->maxs[1] >= sl->mins[1] && ent->mins[1] <= sl->maxs[1] + && ent->maxs[2] >= sl->mins[2] && ent->mins[2] <= sl->maxs[2] + && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + R_TestAndDrawShadowVolume(r_refdef.entities[i], sl->origin, cullradius, lightradius); } - - glDisableClientState(GL_VERTEX_ARRAY); } - else + + if (!visiblevolumes) { - order = (int *)((int)pheader + pheader->ofs_glcmds); - while(1) + R_Shadow_Stage_Light(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else - { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - do + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, sl->distbias, sl->subtract, lightcolor); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) { - glVertex3fv(&aliasvert[order[2] * 3]); - order += 3; + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && ent->maxs[0] >= sl->mins[0] && ent->mins[0] <= sl->maxs[0] + && ent->maxs[1] >= sl->mins[1] && ent->mins[1] <= sl->maxs[1] + && ent->maxs[2] >= sl->mins[2] && ent->mins[2] <= sl->maxs[2] + && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + { + Matrix4x4_Transform(&ent->inversematrix, sl->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius, sl->distbias, sl->subtract, lightcolor); + } } - while (count--); } } - - glEnable (GL_TEXTURE_2D); - glColor3f (1,1,1); } - - /* - if (r_shadows.value && !(currententity->effects & EF_ADDITIVE) && currententity != &cl.viewent) + */ + for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++) { - int i; - float *av = aliasvert + 2, l = lightspot[2] + 0.125; - av = aliasvert + 2; - for (i = 0;i < pheader->num_xyz;i++, av+=3) - if (*av > l) - *av = l; - glDisable (GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(0); // disable zbuffer updates - glColor4f (0,0,0,0.5 * modelalpha); - - if (gl_vertexarrays.value) + cullradius = rd->cullradius; + lightradius = rd->cullradius; + if (VIS_CullSphere(rd->origin, lightradius)) + continue; + + VectorScale(rd->light, (1.0f / 8192.0f), lightcolor); + clipmins[0] = rd->origin[0] - cullradius; + clipmins[1] = rd->origin[1] - cullradius; + clipmins[2] = rd->origin[2] - cullradius; + clipmaxs[0] = rd->origin[0] + cullradius; + clipmaxs[1] = rd->origin[1] + cullradius; + clipmaxs[2] = rd->origin[2] + cullradius; + + if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, rd->origin, rd->cullradius)) + continue; + + if (!visiblevolumes) + R_Shadow_Stage_ShadowVolumes(); + ent = &cl_entities[0].render; + R_TestAndDrawShadowVolume(ent, rd->origin, cullradius / ent->scale, lightradius / ent->scale, clipmins, clipmaxs); + if (r_drawentities.integer) { - qglVertexPointer(3, GL_FLOAT, 0, aliasvert); - glEnableClientState(GL_VERTEX_ARRAY); - - while(1) + for (i = 0;i < r_refdef.numentities;i++) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else - { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - do - { - qglArrayElement(order[2]); - order += 3; - } - while (count--); + ent = r_refdef.entities[i]; + if (ent != rd->ent && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + R_TestAndDrawShadowVolume(ent, rd->origin, cullradius / ent->scale, lightradius / ent->scale, clipmins, clipmaxs); } - - glDisableClientState(GL_VERTEX_ARRAY); } - else + + if (!visiblevolumes) { - while(1) + R_Shadow_Stage_Light(); + ent = &cl_entities[0].render; + if (ent->model && ent->model->DrawLight) { - if (!(count = *order++)) - break; - if (count > 0) - glBegin(GL_TRIANGLE_STRIP); - else - { - glBegin(GL_TRIANGLE_FAN); - count = -count; - } - do + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor); + } + if (r_drawentities.integer) + { + for (i = 0;i < r_refdef.numentities;i++) { - glVertex3fv(&aliasvert[order[2] * 3]); - order += 3; + ent = r_refdef.entities[i]; + if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight + && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1) + { + Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin); + Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin); + ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor); + } } - while (count--); } } - - glEnable (GL_TEXTURE_2D); - glColor3f (1,1,1); } - */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_BLEND); - glDepthMask(1); + if (!visiblevolumes) + R_Shadow_Stage_End(); + qglEnable(GL_CULL_FACE); + qglDisable(GL_SCISSOR_TEST); } -/* -================= -R_DrawAliasModel - -================= -*/ -void R_DrawAliasModel (entity_t *e, int cull) +static void R_SetFrustum (void) { - int i; - model_t *clmodel; - vec3_t mins, maxs; - aliashdr_t *paliashdr = NULL; - md2mem_t *pheader = NULL; - int anim; - - if (modelalpha < (1.0 / 64.0)) - return; // basically completely transparent - - clmodel = currententity->model; - - VectorAdd (currententity->origin, clmodel->mins, mins); - VectorAdd (currententity->origin, clmodel->maxs, maxs); - - if (cull && R_CullBox (mins, maxs)) - return; - - VectorCopy (currententity->origin, r_entorigin); - VectorSubtract (r_origin, r_entorigin, modelorg); - - // get lighting information + int i; - if (currententity->model->flags & EF_FULLBRIGHT || currententity->effects & EF_FULLBRIGHT) + // LordHavoc: note to all quake engine coders, the special case for 90 + // degrees assumed a square view (wrong), so I removed it, Quake2 has it + // disabled as well. + // rotate VPN right by FOV_X/2 degrees + RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); + // rotate VPN left by FOV_X/2 degrees + RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); + // rotate VPN up by FOV_X/2 degrees + RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); + // rotate VPN down by FOV_X/2 degrees + RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); + + for (i = 0;i < 4;i++) { - shadecolor[0] = currententity->colormod[0] * 256; - shadecolor[1] = currententity->colormod[1] * 256; - shadecolor[2] = currententity->colormod[2] * 256; - } - else - { - R_LightPoint (shadecolor, currententity->origin); - - // HACK HACK HACK -- no fullbright colors, so make torches full light - if (!strcmp (currententity->model->name, "progs/flame2.mdl") || !strcmp (currententity->model->name, "progs/flame.mdl") ) - shadecolor[0] = shadecolor[1] = shadecolor[2] = 128; - - shadecolor[0] *= currententity->colormod[0]; - shadecolor[1] *= currententity->colormod[1]; - shadecolor[2] *= currententity->colormod[2]; + frustum[i].type = PLANE_ANYZ; + frustum[i].dist = DotProduct (r_origin, frustum[i].normal); + PlaneClassify(&frustum[i]); } +} - // locate the proper data - if (clmodel->aliastype == ALIASTYPE_MD2) - { - pheader = (void *)Mod_Extradata (currententity->model); - c_alias_polys += pheader->num_tris; - } - else +/* +=============== +R_SetupFrame +=============== +*/ +static void R_SetupFrame (void) +{ +// don't allow cheats in multiplayer + if (cl.maxclients > 1) { - paliashdr = (void *)Mod_Extradata (currententity->model); - c_alias_polys += paliashdr->numtris; + if (r_fullbright.integer != 0) + Cvar_Set ("r_fullbright", "0"); + if (r_ambient.value != 0) + Cvar_Set ("r_ambient", "0"); } - // draw all the triangles - - if (clmodel->aliastype == ALIASTYPE_MD2) - { - if (currententity->skinnum < 0 || currententity->skinnum >= pheader->num_skins) - { - currententity->skinnum = 0; - Con_DPrintf("invalid skin number %d for model %s\n", currententity->skinnum, clmodel->name); - } - glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[currententity->skinnum]); - } - else - { - if (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) - { - currententity->skinnum = 0; - Con_DPrintf("invalid skin number %d for model %s\n", currententity->skinnum, clmodel->name); - } - anim = (int)(cl.time*10) & 3; - glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[currententity->skinnum][anim]); - } - glDisable(GL_ALPHA_TEST); - glEnable (GL_TEXTURE_2D); + r_framecount++; - // we can't dynamically colormap textures, so they are cached - // seperately for the players. Heads are just uncolored. - if (currententity->colormap != vid.colormap/* && !gl_nocolors.value*/) - { - i = currententity - cl_entities; - if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) - glBindTexture(GL_TEXTURE_2D, playertextures - 1 + i); - } +// build the transformation matrix for the given view angles + VectorCopy (r_refdef.vieworg, r_origin); -// if (gl_affinemodels.value) -// glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - if (clmodel->aliastype == ALIASTYPE_MD2) - R_DrawQ2AliasFrame (pheader); - else - R_DrawAliasFrame (paliashdr); + AngleVectors (r_refdef.viewangles, vpn, vright, vup); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + R_AnimateLight (); } -//================================================================================== -void R_DrawBrushModel (entity_t *e); - -/* -============= -R_DrawEntitiesOnList -============= -*/ -// LordHavoc: split so bmodels are rendered before any other objects -void R_DrawEntitiesOnList1 (void) +static void R_BlendView(void) { - int i; + rmeshstate_t m; + float r; - if (!r_drawentities.value) + if (r_refdef.viewblend[3] < 0.01f) return; - for (i=0 ; imodel->type != mod_brush) - continue; - currententity = cl_visedicts[i]; - modelalpha = currententity->alpha; - - R_DrawBrushModel (currententity); - } + memset(&m, 0, sizeof(m)); + m.blendfunc1 = GL_SRC_ALPHA; + m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA; + m.depthdisable = true; // magic + R_Mesh_Matrix(&r_identitymatrix); + R_Mesh_State(&m); + + r = 64000; + varray_vertex[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r; + varray_vertex[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r; + varray_vertex[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r; + r *= 3; + varray_vertex[4] = varray_vertex[0] + vup[0] * r; + varray_vertex[5] = varray_vertex[1] + vup[1] * r; + varray_vertex[6] = varray_vertex[2] + vup[2] * r; + varray_vertex[8] = varray_vertex[0] + vright[0] * r; + varray_vertex[9] = varray_vertex[1] + vright[1] * r; + varray_vertex[10] = varray_vertex[2] + vright[2] * r; + GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + R_Mesh_Draw(3, 1, polygonelements); } -void R_DrawEntitiesOnList2 (void) -{ - int i; +/* +================ +R_RenderView - if (!r_drawentities.value) - return; +r_refdef must be set before the first call +================ +*/ +void R_RenderView (void) +{ + entity_render_t *world; + if (!r_refdef.entities/* || !cl.worldmodel*/) + return; //Host_Error ("R_RenderView: NULL worldmodel"); - for (i=0 ; ialpha; - - switch (currententity->model->type) + if (!gl_texturecubemap) { - case mod_alias: - R_DrawAliasModel (currententity, true); - break; - - case mod_sprite: - R_DrawSpriteModel (currententity); - break; - - default: - break; + Con_Printf("Cubemap texture support not detected, turning off r_shadow_realtime\n"); + Cvar_SetValueQuick(&r_shadow_realtime, 0); + } + else if (!gl_dot3arb) + { + Con_Printf("Bumpmapping support not detected, turning off r_shadow_realtime\n"); + Cvar_SetValueQuick(&r_shadow_realtime, 0); + } + else if (!gl_stencil) + { + Con_Printf("Stencil not enabled, turning off r_shadow_realtime, please type vid_stencil 1;vid_bitsperpixel 32;vid_restart and try again\n"); + Cvar_SetValueQuick(&r_shadow_realtime, 0); + } + else if (!gl_combine.integer) + { + Con_Printf("Combine disabled, please turn on gl_combine, turning off r_shadow_realtime\n"); + Cvar_SetValueQuick(&r_shadow_realtime, 0); } } -} -/* -============= -R_DrawViewModel -============= -*/ -void R_DrawViewModel (void) -{ - if (!r_drawviewmodel.value || chase_active.value || envmap || !r_drawentities.value || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.model) - return; + R_Shadow_UpdateLightingMode(); - currententity = &cl.viewent; - currententity->alpha = modelalpha = cl_entities[cl.viewentity].alpha; // LordHavoc: if the player is transparent, so is his gun - currententity->effects = cl_entities[cl.viewentity].effects; - currententity->scale = 1; - VectorCopy(cl_entities[cl.viewentity].colormod, currententity->colormod); + world = &cl_entities[0].render; - // hack the depth range to prevent view model from poking into walls - glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); - R_DrawAliasModel (currententity, FALSE); - glDepthRange (gldepthmin, gldepthmax); -} + // FIXME: move to client + R_MoveExplosions(); + R_TimeReport("mexplosion"); -void R_DrawBrushModel (entity_t *e); + R_Textures_Frame(); + R_SetupFrame(); + R_SetFrustum(); + R_SetupFog(); + R_SkyStartFrame(); + R_BuildLightList(); + R_TimeReport("setup"); -void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); + R_WorldVisibility(world); + R_TimeReport("worldvis"); -void R_SetFrustum (void) -{ - int i; - - if (r_refdef.fov_x == 90) - { - // front side is visible - - VectorAdd (vpn, vright, frustum[0].normal); - VectorSubtract (vpn, vright, frustum[1].normal); + R_FarClip_Start(r_origin, vpn, 768.0f); + R_MarkEntities(); + r_farclip = R_FarClip_Finish() + 256.0f; + R_TimeReport("markentity"); - VectorAdd (vpn, vup, frustum[2].normal); - VectorSubtract (vpn, vup, frustum[3].normal); - } + GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height); + if (r_shadow_lightingmode > 0) + GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f); else - { - // rotate VPN right by FOV_X/2 degrees - RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); - // rotate VPN left by FOV_X/2 degrees - RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); - // rotate VPN up by FOV_X/2 degrees - RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); - // rotate VPN down by FOV_X/2 degrees - RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); - } + GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip); + GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles); + qglDepthFunc(GL_LEQUAL); - for (i=0 ; i<4 ; i++) - { - frustum[i].type = PLANE_ANYZ; - frustum[i].dist = DotProduct (r_origin, frustum[i].normal); -// frustum[i].signbits = SignbitsForPlane (&frustum[i]); - BoxOnPlaneSideClassify(&frustum[i]); - } -} + R_Mesh_Start(); + R_MeshQueue_BeginScene(); -void R_AnimateLight (void); -void V_CalcBlend (void); + if (r_shadow_lightingmode) + R_Shadow_UpdateWorldLightSelection(); -/* -=============== -R_SetupFrame -=============== -*/ -void R_SetupFrame (void) -{ -// don't allow cheats in multiplayer - if (cl.maxclients > 1) - Cvar_Set ("r_fullbright", "0"); + if (R_DrawBrushModelsSky()) + R_TimeReport("bmodelsky"); - R_AnimateLight (); + // must occur early because it can draw sky + R_DrawWorld(world); + R_TimeReport("world"); - r_framecount++; + // don't let sound skip if going slow + if (!intimerefresh && !r_speeds.integer) + S_ExtraUpdate (); -// build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, r_origin); - - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + R_DrawModels(r_shadow_lightingmode > 0); + R_TimeReport("models"); -// current viewleaf - r_oldviewleaf = r_viewleaf; - r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); - - V_SetContentsColor (r_viewleaf->contents); - V_CalcBlend (); + if (r_shadows.integer == 1 && r_shadow_lightingmode <= 0) + { + R_DrawFakeShadows(); + R_TimeReport("fakeshadow"); + } - r_cache_thrash = false; + if (r_shadow_lightingmode > 0) + { + R_ShadowVolumeLighting(false); + R_TimeReport("dynlight"); + } - c_brush_polys = 0; - c_alias_polys = 0; + R_DrawParticles(); + R_TimeReport("particles"); -} + R_DrawExplosions(); + R_TimeReport("explosions"); + R_MeshQueue_RenderTransparent(); + R_TimeReport("drawtrans"); -void MYgluPerspective( GLdouble fovy, GLdouble aspect, - GLdouble zNear, GLdouble zFar ) -{ - GLdouble xmin, xmax, ymin, ymax; + R_DrawCoronas(); + R_TimeReport("coronas"); - ymax = zNear * tan( fovy * M_PI / 360.0 ); - ymin = -ymax; + R_DrawWorldCrosshair(); + R_TimeReport("crosshair"); - xmin = ymin * aspect; - xmax = ymax * aspect; + R_BlendView(); + R_TimeReport("blendview"); - glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); + R_MeshQueue_Render(); + R_MeshQueue_EndScene(); + if (r_shadow_realtime.integer >= 2) + { + R_ShadowVolumeLighting(true); + R_TimeReport("shadowvolume"); + } + R_Mesh_Finish(); + R_TimeReport("meshfinish"); } - -extern char skyname[]; - /* -============= -R_SetupGL -============= -*/ -void R_SetupGL (void) +void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca) { - float screenaspect; - extern int glwidth, glheight; - int x, x2, y2, y, w, h; - - // - // set up viewpoint - // - glMatrixMode(GL_PROJECTION); - glLoadIdentity (); - x = r_refdef.vrect.x * glwidth/vid.width; - x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width; - y = (vid.height-r_refdef.vrect.y) * glheight/vid.height; - y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height; - - // fudge around because of frac screen scale - if (x > 0) - x--; - if (x2 < glwidth) - x2++; - if (y2 < 0) - y2--; - if (y < glheight) - y++; - - w = x2 - x; - h = y - y2; - - if (envmap) + int i; + float *v, *c, f1, f2, diff[3]; + rmeshstate_t m; + m.blendfunc1 = GL_SRC_ALPHA; + m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA; + R_Mesh_Matrix(&r_identitymatrix); + R_Mesh_State(&m); + + varray_vertex[ 0] = mins[0];varray_vertex[ 1] = mins[1];varray_vertex[ 2] = mins[2]; + varray_vertex[ 4] = maxs[0];varray_vertex[ 5] = mins[1];varray_vertex[ 6] = mins[2]; + varray_vertex[ 8] = mins[0];varray_vertex[ 9] = maxs[1];varray_vertex[10] = mins[2]; + varray_vertex[12] = maxs[0];varray_vertex[13] = maxs[1];varray_vertex[14] = mins[2]; + varray_vertex[16] = mins[0];varray_vertex[17] = mins[1];varray_vertex[18] = maxs[2]; + varray_vertex[20] = maxs[0];varray_vertex[21] = mins[1];varray_vertex[22] = maxs[2]; + varray_vertex[24] = mins[0];varray_vertex[25] = maxs[1];varray_vertex[26] = maxs[2]; + varray_vertex[28] = maxs[0];varray_vertex[29] = maxs[1];varray_vertex[30] = maxs[2]; + R_FillColors(varray_color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca); + if (fogenabled) { - x = y2 = 0; - w = h = 256; + for (i = 0, v = varray_vertex, c = varray_color;i < 8;i++, v += 4, c += 4) + { + VectorSubtract(v, r_origin, diff); + f2 = exp(fogdensity/DotProduct(diff, diff)); + f1 = 1 - f2; + f2 *= r_colorscale; + c[0] = c[0] * f1 + fogcolor[0] * f2; + c[1] = c[1] * f1 + fogcolor[1] * f2; + c[2] = c[2] * f1 + fogcolor[2] * f2; + } } - - glViewport (glx + x, gly + y2, w, h); - screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; -// yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; -// if (skyname[0]) // skybox enabled? -// MYgluPerspective (r_refdef.fov_y, screenaspect, 4, r_skyboxsize.value*1.732050807569 + 256); // this is size*sqrt(3) + 256 -// else - MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 6144); - - glCullFace(GL_FRONT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity (); - - glRotatef (-90, 1, 0, 0); // put Z going up - glRotatef (90, 0, 0, 1); // put Z going up - glRotatef (-r_refdef.viewangles[2], 1, 0, 0); - glRotatef (-r_refdef.viewangles[0], 0, 1, 0); - glRotatef (-r_refdef.viewangles[1], 0, 0, 1); - glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); - - glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); - - // - // set drawing parms - // -// if (gl_cull.value) - glEnable(GL_CULL_FACE); -// else -// glDisable(GL_CULL_FACE); - - glEnable(GL_BLEND); // was Disable - glDisable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5); - glEnable(GL_DEPTH_TEST); - glDepthMask(1); - glShadeModel(GL_SMOOTH); + GL_UseColorArray(); + R_Mesh_Draw(8, 12); } - -void R_DrawWorld (void); -//void R_RenderDlights (void); -void R_DrawParticles (void); - -/* -============= -R_Clear -============= */ -void R_Clear (void) -{ -// glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: moved to SCR_UpdateScreen - gldepthmin = 0; - gldepthmax = 1; - glDepthFunc (GL_LEQUAL); - - glDepthRange (gldepthmin, gldepthmax); -} - -// LordHavoc: my trick to *FIX* GLQuake lighting once and for all :) -void GL_Brighten() -{ - glMatrixMode(GL_PROJECTION); - glLoadIdentity (); - glOrtho (0, vid.width, vid.height, 0, -99999, 99999); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity (); - glDisable (GL_DEPTH_TEST); - glDisable (GL_CULL_FACE); - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc (GL_DST_COLOR, GL_ONE); - glBegin (GL_TRIANGLES); - glColor3f (1, 1, 1); - glVertex2f (-5000, -5000); - glVertex2f (10000, -5000); - glVertex2f (-5000, 10000); - glEnd (); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); - glEnable (GL_DEPTH_TEST); - glEnable (GL_CULL_FACE); -} -extern cvar_t contrast; -extern cvar_t brightness; -extern cvar_t gl_lightmode; - -void GL_BlendView() +void R_DrawNoModelCallback(const void *calldata1, int calldata2) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity (); - glOrtho (0, vid.width, vid.height, 0, -99999, 99999); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity (); - glDisable (GL_DEPTH_TEST); - glDisable (GL_CULL_FACE); - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - if (lighthalf) + const entity_render_t *ent = calldata1; + int i, element[24]; + float f1, f2, *c, diff[3]; + rmeshstate_t m; + memset(&m, 0, sizeof(m)); + if (ent->flags & EF_ADDITIVE) { - glBlendFunc (GL_DST_COLOR, GL_ONE); - glBegin (GL_TRIANGLES); - glColor3f (1, 1, 1); - glVertex2f (-5000, -5000); - glVertex2f (10000, -5000); - glVertex2f (-5000, 10000); - glEnd (); + m.blendfunc1 = GL_SRC_ALPHA; + m.blendfunc2 = GL_ONE; } - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - contrast.value = bound(0.2, contrast.value, 1.0); - if (/*gl_polyblend.value && */v_blend[3]) + else if (ent->alpha < 1) { - glBegin (GL_TRIANGLES); - glColor4fv (v_blend); - glVertex2f (-5000, -5000); - glVertex2f (10000, -5000); - glVertex2f (-5000, 10000); - glEnd (); + m.blendfunc1 = GL_SRC_ALPHA; + m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA; } - - glEnable (GL_CULL_FACE); - glEnable (GL_DEPTH_TEST); - glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); -} - -#define TIMEREPORT(DESC) \ - if (r_speeds2.value)\ - {\ - temptime = -currtime;\ - currtime = Sys_FloatTime();\ - temptime += currtime;\ - Con_Printf(DESC " %.4fms ", temptime * 1000.0);\ + else + { + m.blendfunc1 = GL_ONE; + m.blendfunc2 = GL_ZERO; + } + R_Mesh_Matrix(&ent->matrix); + R_Mesh_State(&m); + + element[ 0] = 5;element[ 1] = 2;element[ 2] = 0; + element[ 3] = 5;element[ 4] = 1;element[ 5] = 2; + element[ 6] = 5;element[ 7] = 0;element[ 8] = 3; + element[ 9] = 5;element[10] = 3;element[11] = 1; + element[12] = 0;element[13] = 2;element[14] = 4; + element[15] = 2;element[16] = 1;element[17] = 4; + element[18] = 3;element[19] = 0;element[20] = 4; + element[21] = 1;element[22] = 3;element[23] = 4; + varray_vertex[ 0] = -16;varray_vertex[ 1] = 0;varray_vertex[ 2] = 0; + varray_vertex[ 4] = 16;varray_vertex[ 5] = 0;varray_vertex[ 6] = 0; + varray_vertex[ 8] = 0;varray_vertex[ 9] = -16;varray_vertex[10] = 0; + varray_vertex[12] = 0;varray_vertex[13] = 16;varray_vertex[14] = 0; + varray_vertex[16] = 0;varray_vertex[17] = 0;varray_vertex[18] = -16; + varray_vertex[20] = 0;varray_vertex[21] = 0;varray_vertex[22] = 16; + varray_color[ 0] = 0.00f * r_colorscale;varray_color[ 1] = 0.00f * r_colorscale;varray_color[ 2] = 0.50f * r_colorscale;varray_color[ 3] = ent->alpha; + varray_color[ 4] = 0.00f * r_colorscale;varray_color[ 5] = 0.00f * r_colorscale;varray_color[ 6] = 0.50f * r_colorscale;varray_color[ 7] = ent->alpha; + varray_color[ 8] = 0.00f * r_colorscale;varray_color[ 9] = 0.50f * r_colorscale;varray_color[10] = 0.00f * r_colorscale;varray_color[11] = ent->alpha; + varray_color[12] = 0.00f * r_colorscale;varray_color[13] = 0.50f * r_colorscale;varray_color[14] = 0.00f * r_colorscale;varray_color[15] = ent->alpha; + varray_color[16] = 0.50f * r_colorscale;varray_color[17] = 0.00f * r_colorscale;varray_color[18] = 0.00f * r_colorscale;varray_color[19] = ent->alpha; + varray_color[20] = 0.50f * r_colorscale;varray_color[21] = 0.00f * r_colorscale;varray_color[22] = 0.00f * r_colorscale;varray_color[23] = ent->alpha; + if (fogenabled) + { + VectorSubtract(ent->origin, r_origin, diff); + f2 = exp(fogdensity/DotProduct(diff, diff)); + f1 = 1 - f2; + for (i = 0, c = varray_color;i < 6;i++, c += 4) + { + c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale; + c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale; + c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale; + } } + else + { + for (i = 0, c = varray_color;i < 6;i++, c += 4) + { + c[0] *= r_colorscale; + c[1] *= r_colorscale; + c[2] *= r_colorscale; + } + } + GL_UseColorArray(); + R_Mesh_Draw(6, 8, element); +} -/* -================ -R_RenderView +void R_DrawNoModel(entity_render_t *ent) +{ + //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1)) + R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0); + //else + // R_DrawNoModelCallback(ent, 0); +} -r_refdef must be set before the first call -================ -*/ -void R_RenderView (void) +void R_CalcBeamVerts (float *vert, const vec3_t org1, const vec3_t org2, float width) { -// double currtime, temptime; -// if (r_norefresh.value) -// return; - - if (!r_worldentity.model || !cl.worldmodel) - Sys_Error ("R_RenderView: NULL worldmodel"); - - lighthalf = gl_lightmode.value; - - FOG_framebegin(); - transpolyclear(); - -// if (r_speeds2.value) -// { -// currtime = Sys_FloatTime(); -// Con_Printf("render time: "); -// } - R_Clear(); -// TIMEREPORT("R_Clear") - - // render normal view - - R_SetupFrame (); - R_SetFrustum (); - R_SetupGL (); - R_MarkLeaves (); // done here so we know if we're in water - R_DrawWorld (); // adds static entities to the list - S_ExtraUpdate (); // don't let sound get messed up if going slow - wallpolyclear(); - R_DrawEntitiesOnList1 (); // BSP models - wallpolyrender(); - R_DrawEntitiesOnList2 (); // other models -// R_RenderDlights (); - R_DrawViewModel (); - R_DrawParticles (); - transpolyrender(); - - FOG_frameend(); - GL_BlendView(); -// if (r_speeds2.value) -// Con_Printf("\n"); + vec3_t right1, right2, diff, normal; + + VectorSubtract (org2, org1, normal); + VectorNormalizeFast (normal); + + // calculate 'right' vector for start + VectorSubtract (r_origin, org1, diff); + VectorNormalizeFast (diff); + CrossProduct (normal, diff, right1); + + // calculate 'right' vector for end + VectorSubtract (r_origin, org2, diff); + VectorNormalizeFast (diff); + CrossProduct (normal, diff, right2); + + vert[ 0] = org1[0] + width * right1[0]; + vert[ 1] = org1[1] + width * right1[1]; + vert[ 2] = org1[2] + width * right1[2]; + vert[ 4] = org1[0] - width * right1[0]; + vert[ 5] = org1[1] - width * right1[1]; + vert[ 6] = org1[2] - width * right1[2]; + vert[ 8] = org2[0] - width * right2[0]; + vert[ 9] = org2[1] - width * right2[1]; + vert[10] = org2[2] - width * right2[2]; + vert[12] = org2[0] + width * right2[0]; + vert[13] = org2[1] + width * right2[1]; + vert[14] = org2[2] + width * right2[2]; }