//FIXME: Light visibility is decided from weather the light's pvs overlaps the view pvs. //This doesn't take light radius into account. This means that lights around corners that will never be visible are drawn in full per-pixel goodness. //This is bad. lights*3, 33% framerate for no worthwhile effect. #include "quakedef.h" #ifdef RGLQUAKE #include "glquake.h" #include "shader.h" #define qglGetError() 0 //these are shared with gl_rsurf - move to header void R_MirrorChain (msurface_t *s); void GL_SelectTexture (GLenum target); void R_RenderDynamicLightmaps (msurface_t *fa, int shift); void R_BlendLightmaps (void); void PPL_BeginShadowMesh(dlight_t *dl); void PPL_FinishShadowMesh(dlight_t *dl); void PPL_FlushShadowMesh(dlight_t *dl); void PPL_Shadow_Cache_Surface(msurface_t *surf); //only caches for lighting void PPL_Shadow_Cache_Leaf(mleaf_t *leaf); extern qboolean r_inmirror; extern int gldepthfunc; extern int *lightmap_textures; extern int lightmap_bytes; // 1, 2, or 4 extern cvar_t gl_detail; extern cvar_t gl_detailscale; extern cvar_t gl_overbright, gl_overbright_all; extern cvar_t r_fb_bmodels; extern cvar_t gl_part_flame; extern cvar_t gl_maxshadowlights; extern cvar_t r_shadow_realtime_world; extern cvar_t r_shadow_realtime_world_lightmaps; extern cvar_t r_shadow_glsl_offsetmapping; extern cvar_t r_shadow_glsl_offsetmapping_scale; extern cvar_t r_shadow_glsl_offsetmapping_bias; extern int detailtexture; extern cvar_t gl_bump; extern cvar_t gl_specular; extern cvar_t gl_mylumassuck; //end header confict extern cvar_t gl_schematics; extern cvar_t r_drawflat; extern cvar_t r_wallcolour; extern cvar_t r_floorcolour; float r_lightmapintensity; //1 or r_shadow_realtime_world_lightmaps int overbright; extern lightmapinfo_t **lightmap; extern model_t *currentmodel; extern int *deluxmap_textures; extern int normalisationCubeMap; int r_shadowframe; int shadowsurfcount; int shadowedgecount; int shadowlightfaces; int shadowemittedeges; int ppl_specular_shader; int ppl_specular_shader_vieworg; int ppl_specular_shader_texr; int ppl_specular_shader_texu; int ppl_specular_shader_texf; int GLR_LightmapShift (model_t *model); //#define glBegin glEnd qboolean PPL_ShouldDraw(void) { if (r_inmirror) { if (currententity->flags & Q2RF_WEAPONMODEL) return false; } else { if (currententity->flags & Q2RF_EXTERNALMODEL) return false; if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1))) return false; // if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum]) // continue; if (!Cam_DrawPlayer(0, currententity->keynum-1)) return false; } return true; } typedef struct { int count; msurface_t **s; } shadowmeshsurfs_t; typedef struct shadowmesh_s { int numindicies; int numverts; int *indicies; vec3_t *verts; //we also have a list of all the surfaces that this light lights. int numsurftextures; shadowmeshsurfs_t *litsurfs; unsigned char *litleaves; } shadowmesh_t; #define Q2RF_WEAPONMODEL 4 // only draw through eyes struct { short count; short count2; int next; int prev; } edge[MAX_MAP_EDGES]; int firstedge; vec3_t lightorg = {0, 0, 0}; float lightradius; typedef struct { float xyz[3]; //xyz world coordinates float stw[2]; //base texture/normalmap/specular map st coords float stl[3]; //lightmap/deluxmap st coords (or attenuated distance*colour) float ncm[3]; //normalisation cube map (reflected light dir) } surfvertexarray_t; #define MAXARRAYVERTS 2048 static surfvertexarray_t varray_v[MAXARRAYVERTS]; static unsigned int varray_i[MAXARRAYVERTS]; //static unsigned int varray_i_forward[MAXARRAYVERTS]; //static unsigned int varray_i_polytotri[MAXARRAYVERTS]; //012 023 034 045... int varray_ic; int varray_vc; #define inline static extern qboolean varrayactive; //used by the backend inline void PPL_EnableVertexArrays(void) { varrayactive = false; qglDisableClientState(GL_COLOR_ARRAY); qglEnableClientState(GL_VERTEX_ARRAY); qglVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->xyz); } inline void PPL_FlushArrays(void) { if (varray_ic) qglDrawElements(GL_TRIANGLES, varray_ic, GL_UNSIGNED_INT, varray_i); varray_ic = 0; varray_vc = 0; } static void PPL_GenerateArrays(msurface_t *surf) { int vi; if (!surf->mesh) return; if (surf->mesh->numindexes > MAXARRAYVERTS) return; if (surf->mesh->numvertexes > MAXARRAYVERTS) return; if (!surf->mesh->st_array) return; if (!surf->mesh->lmst_array) return; if (varray_ic) //FIXME: go muuuch faster please PPL_FlushArrays(); for (vi = 0; vi < surf->mesh->numindexes; vi++) varray_i[vi] = surf->mesh->indexes[vi]; for (vi = 0; vi < surf->mesh->numvertexes; vi++) { VectorCopy(surf->mesh->xyz_array[vi], varray_v[vi].xyz); varray_v[vi].stw[0] = surf->mesh->st_array[vi][0]; varray_v[vi].stw[1] = surf->mesh->st_array[vi][1]; varray_v[vi].stl[0] = surf->mesh->lmst_array[vi][0]; varray_v[vi].stl[1] = surf->mesh->lmst_array[vi][1]; } varray_vc = surf->mesh->numvertexes; varray_ic = surf->mesh->numindexes; } static void PPL_GenerateDetailArrays(msurface_t *surf) { int vi; if (!surf->mesh) return; if (surf->mesh->numindexes > MAXARRAYVERTS) return; if (surf->mesh->numvertexes > MAXARRAYVERTS) return; if (!surf->mesh->st_array) return; if (!surf->mesh->lmst_array) return; if (varray_ic) //FIXME: go muuuch faster please PPL_FlushArrays(); for (vi = 0; vi < surf->mesh->numindexes; vi++) varray_i[vi] = surf->mesh->indexes[vi]; for (vi = 0; vi < surf->mesh->numvertexes; vi++) { VectorCopy(surf->mesh->xyz_array[vi], varray_v[vi].xyz); varray_v[vi].stw[0] = surf->mesh->st_array[vi][0]*gl_detailscale.value; varray_v[vi].stw[1] = surf->mesh->st_array[vi][1]*gl_detailscale.value; } varray_vc = surf->mesh->numvertexes; varray_ic = surf->mesh->numindexes; } /* static void PPL_BaseChain_NoLightmap(msurface_t *first, texture_t *tex) { Sys_Error("1 TMU is disabled for now (surface has no lightmap)\n"); } */ static void PPL_BaseChain_NoBump_1TMU(msurface_t *first, texture_t *tex) { int vi; glRect_t *theRect; msurface_t *s; PPL_EnableVertexArrays(); qglDisable(GL_BLEND); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_TexEnv(GL_REPLACE); GL_Bind (tex->gl_texturenum); for (s=first; s ; s=s->texturechain) { PPL_GenerateArrays(s); } PPL_FlushArrays(); qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); if (gl_lightmap_format == GL_LUMINANCE || gl_lightmap_format == GL_RGB) qglBlendFunc (GL_ZERO, GL_SRC_COLOR); else if (gl_lightmap_format == GL_INTENSITY) { qglColor4f (0,0,0,1); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else if (gl_lightmap_format == GL_RGBA) qglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); vi = -1; for (s=first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } PPL_GenerateArrays(s); } PPL_FlushArrays(); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } /*static void PPL_BaseChain_NoBump_2TMU(msurface_t *s, texture_t *tex) { //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying. int vi; glRect_t *theRect; PPL_EnableVertexArrays(); if (tex->alphaed) { qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); } else { qglDisable(GL_BLEND); GL_TexEnv(GL_REPLACE); } GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); vi = -1; for (; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { if (vi<0) qglEnable(GL_TEXTURE_2D); vi = s->lightmaptexturenum; if (vi>=0) { GL_Bind(lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } else qglDisable(GL_TEXTURE_2D); } qglClientActiveTextureARB(GL_TEXTURE0_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglClientActiveTextureARB(GL_TEXTURE1_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); //qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); }*/ static void PPL_BaseChain_NoBump_2TMU_Overbright(msurface_t *s, texture_t *tex) { //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying. int vi; glRect_t *theRect; PPL_EnableVertexArrays(); if (tex->alphaed || currententity->shaderRGBAf[3]<1) { qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); } else { qglDisable(GL_BLEND); GL_TexEnv(GL_REPLACE); } GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE1_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_TexEnv(GL_MODULATE); if (overbright != 1) { GL_TexEnv(GL_COMBINE_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, overbright); //this is the key } vi = -1; for (; s ; s=s->texturechain) { if (!s->mesh) //urm. continue; if (vi != s->lightmaptexturenum) { if (vi<0) qglEnable(GL_TEXTURE_2D); vi = s->lightmaptexturenum; if (vi>=0) { GL_Bind(lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } else qglDisable(GL_TEXTURE_2D); } qglClientActiveTextureARB(GL_TEXTURE0_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglClientActiveTextureARB(GL_TEXTURE1_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } if (overbright != 1) { qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1); //just in case GL_TexEnv(GL_MODULATE); } qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } /* static void PPL_BaseChain_NoBump_2TMU_TEST(msurface_t *s, texture_t *tex) { //this was just me testing efficiency between arrays/glbegin. int vi, i; glRect_t *theRect; PPL_EnableVertexArrays(); if (tex->alphaed) { qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); } else { qglDisable(GL_BLEND); GL_TexEnv(GL_REPLACE); } qglCullFace(GL_BACK); GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); vi = -1; for (; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { if (vi<0) qglEnable(GL_TEXTURE_2D); vi = s->lightmaptexturenum; if (vi>=0) { GL_Bind(lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } else qglDisable(GL_TEXTURE_2D); } qglBegin(GL_POLYGON); switch(s->mesh->numvertexes) { default: for (i = s->mesh->numvertexes-1; i >= 6; i--) { qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[i][0], s->mesh->st_array[i][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[i][0], s->mesh->lmst_array[i][1]); qglVertex3fv(s->mesh->xyz_array[i]); } case 6: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[5][0], s->mesh->st_array[5][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[5][0], s->mesh->lmst_array[5][1]); qglVertex3fv(s->mesh->xyz_array[5]); case 5: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[4][0], s->mesh->st_array[4][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[4][0], s->mesh->lmst_array[4][1]); qglVertex3fv(s->mesh->xyz_array[4]); case 4: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[3][0], s->mesh->st_array[3][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[3][0], s->mesh->lmst_array[3][1]); qglVertex3fv(s->mesh->xyz_array[3]); case 3: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[2][0], s->mesh->st_array[2][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[2][0], s->mesh->lmst_array[2][1]); qglVertex3fv(s->mesh->xyz_array[2]); case 2: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[1][0], s->mesh->st_array[1][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[1][0], s->mesh->lmst_array[1][1]); qglVertex3fv(s->mesh->xyz_array[1]); case 1: qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[0][0], s->mesh->st_array[0][1]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[0][0], s->mesh->lmst_array[0][1]); qglVertex3fv(s->mesh->xyz_array[0]); case 0: break; } qglEnd(); } qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE0_ARB); } */ static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex) { int vi; glRect_t *theRect; msurface_t *s; PPL_EnableVertexArrays(); if (tex->alphaed) { qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); } else { qglDisable(GL_BLEND); GL_TexEnv(GL_REPLACE); } //Bind normal map to texture unit 0 GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); vi = -1; for (s=first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; GL_Bind(deluxmap_textures[vi] ); if (lightmap[vi]->deluxmodified) { lightmap[vi]->deluxmodified = false; theRect = &lightmap[vi]->deluxrectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } PPL_GenerateArrays(s); } PPL_FlushArrays(); GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); GL_SelectTexture(GL_TEXTURE1_ARB); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_MODULATE); vi = -1; for (s=first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; GL_Bind(lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } PPL_GenerateArrays(s); } PPL_FlushArrays(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); } static void PPL_BaseChain_Bump_4TMU(msurface_t *s, texture_t *tex) { int vi; glRect_t *theRect; PPL_EnableVertexArrays(); //Bind normal map to texture unit 0 GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_REPLACE); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); //1 gets the deluxmap GL_SelectTexture(GL_TEXTURE1_ARB); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); //2 gets the diffusemap GL_MBind(GL_TEXTURE2_ARB, tex->gl_texturenum); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_MODULATE); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); //3 gets the lightmap GL_SelectTexture(GL_TEXTURE3_ARB); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_MODULATE); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); vi = -1; for (; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; GL_MBind(GL_TEXTURE1_ARB, deluxmap_textures[vi] ); if (lightmap[vi]->deluxmodified) { lightmap[vi]->deluxmodified = false; theRect = &lightmap[vi]->deluxrectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE, lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } GL_MBind(GL_TEXTURE3_ARB, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } PPL_GenerateArrays(s); } PPL_FlushArrays(); GL_SelectTexture(GL_TEXTURE3_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_TexEnv(GL_MODULATE); } #ifdef SPECULAR //Draw a texture chain with specular exponant 1. //erm... //this uses the wrong stuff to work on gf4tis. /* static void PPL_BaseChain_Specular_4TMU(msurface_t *first, texture_t *tex) { //if I ever do write this function, It'll take a couple of passes. int vi; glRect_t *theRect; msurface_t *s; glColorMask(1,1,1,0); PPL_EnableVertexArrays(); if (qglGetError()) Con_Printf("Error before PPL_BaseChain_Specular\n"); //first 4 texture units: (N.((L+V)/2))^2 glDisable(GL_BLEND); qglActiveTextureARB(GL_TEXTURE0_ARB); GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap); glEnable(GL_TEXTURE_2D); GL_TexEnv(GL_REPLACE); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); if (qglGetError()) Con_Printf("Error binding dot3 tmu1\n"); qglActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap); glEnable(GL_TEXTURE_CUBE_MAP_ARB); if (qglGetError()) Con_Printf("Error binding dot3 cubemap\n"); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); if (qglGetError()) Con_Printf("Error binding dot3 combine\n"); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm); if (qglGetError()) Con_Printf("Error binding dot3 tmu2\n"); //prev*prev (the exponential) qglActiveTextureARB(GL_TEXTURE2_ARB); GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap); //need to bind something. glEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); if (qglGetError()) Con_Printf("Error binding prev*prev\n"); qglActiveTextureARB(GL_TEXTURE3_ARB); GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumspec); glEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); qglClientActiveTextureARB(GL_TEXTURE3_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); if (qglGetError()) Con_Printf("Error binding specular in PPL_BaseChain_Specular\n"); for (s = first; s ; s=s->texturechain) { PPL_GenerateArraysBlinnCubeMap(s); } PPL_FlushArrays(); glEnable(GL_BLEND); glBlendFunc(GL_DST_COLOR, GL_ZERO); // Add normal dot delux times diffusemap then multiple the entire lot by the lightmap. qglActiveTextureARB(GL_TEXTURE0_ARB); GL_TexEnv(GL_REPLACE); qglActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_CUBE_MAP_ARB); glEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); qglActiveTextureARB(GL_TEXTURE2_ARB); glEnable(GL_TEXTURE_2D); GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); qglClientActiveTextureARB(GL_TEXTURE2_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); qglActiveTextureARB(GL_TEXTURE3_ARB); glEnable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); qglClientActiveTextureARB(GL_TEXTURE3_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); vi = -1; for (s = first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; qglActiveTextureARB(GL_TEXTURE1_ARB); GL_BindType(GL_TEXTURE_2D, deluxmap_textures[vi] ); if (lightmap[vi]->deluxmodified) { lightmap[vi]->deluxmodified = false; theRect = &lightmap[vi]->deluxrectchange; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE, lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } qglActiveTextureARB(GL_TEXTURE3_ARB); GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } PPL_GenerateArrays(s); } PPL_FlushArrays(); glColorMask(1,1,1,0); if (qglGetError()) Con_Printf("Error drawing in PPL_BaseChain_Specular\n"); glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE2_ARB); glDisable(GL_TEXTURE_2D); glDisableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); } */ void PPL_LoadSpecularFragmentProgram(void) { //#define SMOOOOOTH //define this to calculate everything per-pixel as opposed to interpolating the halfdir char *vert = "varying vec2 tcbase;\n" "varying vec2 tclm;\n" "uniform vec3 vieworg;\n" #ifdef SMOOOOOTH "varying vec3 fragpos;\n" "varying vec3 norm;\n" #else "uniform vec3 texr, texu, texf;\n" "varying vec3 halfnorm;\n" #endif "void main (void)\n" "{\n" " gl_Position = ftransform();\n" " tcbase = gl_MultiTexCoord0.xy;\n" //pass the texture coords straight through " tclm = gl_MultiTexCoord1.xy;\n" #ifdef SMOOOOOTH " fragpos = vec3(gl_Vertex.xyz);\n" "norm = gl_Normal;\n" #else " vec3 eye = normalize(vieworg - vec3(gl_Vertex.xyz));\n" " vec3 halfdir = (eye + texf) / 2.0;\n" " halfnorm.x = dot(texr, halfdir);\n" //put halfnorm into object space " halfnorm.y = dot(texu, halfdir);\n" " halfnorm.z = dot(texf, halfdir);\n" #endif "}\n" ; /* VectorSubtract(r_refdef.vieworg, v, eye); VectorNormalize(eye); VectorAdd(eye, (v+7), halfdir); //v+7 is the light dir (or plane normal) varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir); varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir); if (surf->flags & SURF_PLANEBACK) varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir); else varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir); */ char *frag = "uniform sampler2D baset;\n" "uniform sampler2D bumpt;\n" "uniform sampler2D lightmapt;\n" "uniform sampler2D deluxt;\n" "uniform sampler2D speculart;\n" "varying vec2 tcbase;\n" "varying vec2 tclm;\n" #ifdef SMOOOOOTH "uniform vec3 vieworg;\n" "varying vec3 fragpos;\n" "uniform vec3 texr, texu, texf;\n" #else "varying vec3 halfnorm;\n" #endif "void main (void)\n" "{\n" " vec3 bases = vec3(texture2D(baset, tcbase));\n" " vec3 bumps = vec3(texture2D(bumpt, tcbase)) * 2.0 - 1.0;\n" " vec3 deluxs = vec3(texture2D(deluxt, tclm)) * 2.0 - 1.0;\n" " vec3 lms = vec3(texture2D(lightmapt, tclm));\n" " vec3 specs = vec3(texture2D(speculart, tcbase));\n" " vec3 diff, spec;\n" #ifdef SMOOOOOTH " vec3 eye = normalize(vieworg - fragpos);\n" " vec3 halfdir = (eye + texf) / 2.0;\n" " vec3 halfnorm;\n" " halfnorm.x = dot(texr, halfdir);\n" //put halfnorm into object space " halfnorm.y = dot(texu, halfdir);\n" " halfnorm.z = dot(texf, halfdir);\n" #endif " diff = bases * dot(bumps, deluxs);\n" " float dv = dot(normalize(halfnorm), bumps);\n" " spec = pow(dv, 8.0) * specs;\n" " gl_FragColor = vec4((diff+spec)*lms, 1.0);\n" "}\n" ; ppl_specular_shader = GLSlang_CreateProgram(NULL, vert, frag); if (ppl_specular_shader) { GLSlang_UseProgram(ppl_specular_shader); qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "baset"), 0); qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "bumpt"), 1); qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "lightmapt"), 2); qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "deluxt"), 3); qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "speculart"), 4); ppl_specular_shader_vieworg = qglGetUniformLocationARB(ppl_specular_shader, "vieworg"); ppl_specular_shader_texr = qglGetUniformLocationARB(ppl_specular_shader, "texr"); ppl_specular_shader_texu = qglGetUniformLocationARB(ppl_specular_shader, "texu"); ppl_specular_shader_texf = qglGetUniformLocationARB(ppl_specular_shader, "texf"); GLSlang_UseProgram(0); } } static void PPL_BaseChain_Specular_FP(msurface_t *s, texture_t *tex) { int vi; glRect_t *theRect; PPL_EnableVertexArrays(); GLSlang_UseProgram(ppl_specular_shader); if (qglGetError()) Con_Printf("GL Error on shadow lighting\n"); GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); // GL_MBind(GL_TEXTURE2_ARB, lightmap_textures[vi] ); // GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] ); GL_MBind(GL_TEXTURE4_ARB, tex->gl_texturenumspec); qglUniform3fvARB(ppl_specular_shader_vieworg, 1, r_refdef.vieworg); if (qglGetError()) Con_Printf("GL Error early during PPL_BaseChain_Specular_FP\n"); vi = -1; for (; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { vi = s->lightmaptexturenum; GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] ); if (lightmap[vi]->deluxmodified) { lightmap[vi]->deluxmodified = false; theRect = &lightmap[vi]->deluxrectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE, lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } GL_MBind(GL_TEXTURE2_ARB, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } qglUniform3fvARB(ppl_specular_shader_texr, 1, s->texinfo->vecs[0]); qglUniform3fvARB(ppl_specular_shader_texu, 1, s->texinfo->vecs[1]); if (s->flags & SURF_PLANEBACK) qglUniform3fARB(ppl_specular_shader_texf, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]); else qglUniform3fvARB(ppl_specular_shader_texf, 1, s->plane->normal); qglClientActiveTextureARB(GL_TEXTURE0_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglClientActiveTextureARB(GL_TEXTURE1_ARB); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } GLSlang_UseProgram(0); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE1_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); if (qglGetError()) Con_Printf("GL Error on specular lighting\n"); } #endif static vec_t wallcolour[4] = {0,0,0,1}; static vec_t floorcolour[4] = {0,0,0,1}; static int walltexture = 0; static int floortexture = 0; static qboolean simpletextures = false; //single textured. void GLR_Wallcolour_Callback(struct cvar_s *var, char *oldvalue) { SCR_StringToRGB(var->string, wallcolour, 255); } void GLR_Floorcolour_Callback(struct cvar_s *var, char *oldvalue) { SCR_StringToRGB(var->string, floorcolour, 255); } void GLR_Walltexture_Callback(struct cvar_s *var, char *oldvalue) { if (!var->string[0]) { walltexture = 0; if (!floortexture) simpletextures = false; return; } walltexture = Mod_LoadHiResTexture(var->string, NULL, true, false, true); if (walltexture) simpletextures = true; } void GLR_Floortexture_Callback(struct cvar_s *var, char *oldvalue) { if (!var->string[0]) { floortexture = 0; if (!walltexture) simpletextures = false; return; } floortexture = Mod_LoadHiResTexture(var->string, NULL, true, false, true); if (floortexture) simpletextures = true; } static void PPL_BaseChain_Flat(msurface_t *first) { msurface_t *s; int iswall = -1; int vi=-10; glRect_t *theRect; if (!r_lightmapintensity) { //these are bad. :( PPL_EnableVertexArrays(); qglColor4f(0,0,0,1); qglDisable(GL_TEXTURE_2D); //texturing? who wants texturing?!?! for (s = first; s ; s=s->texturechain) PPL_GenerateArrays(s); PPL_FlushArrays(); qglEnable(GL_TEXTURE_2D); return; } PPL_EnableVertexArrays(); GL_TexEnv(GL_MODULATE); for (s = first; s ; s=s->texturechain) { if (s->mesh->numvertexes < 3) continue; if (vi != s->lightmaptexturenum) { if (vi < 0) { qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); } vi = s->lightmaptexturenum; if (s->lightmaptexturenum < 0) { qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (vi>=0) { GL_Bind(lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } } if (s->plane->normal[2] <= 0.5) { if (iswall != 0) { iswall=0; qglColor4fv(wallcolour); } } else if (iswall != 1) { iswall=1; qglColor4fv(floorcolour); } qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglColor3f(1,1,1); } static int nprtextures[10]; void GLR_Drawflat_Callback(struct cvar_s *var, char *oldvalue) { int i; if (var->value != 2) return; for (i = 0; i < sizeof(nprtextures)/sizeof(nprtextures[0]); i++) { nprtextures[i] = Mod_LoadHiResTexture(va("sketch%i", i+1), "sketch", true, false, false); if (!nprtextures[i]) { int data[128*128]; FILE *file; unsigned char *f; int p; file = fopen(va("nprtextures/tex%i_3_128_128.raw", i+1), "rb"); if (file) { f = Hunk_TempAlloc(128*128*3); if (fread(f, 128*3, 128, file) == 128) { for (p = 0; p < 128*128; p++) data[p] = LittleLong(f[p*3] + (f[p*3+1]<<8) + (f[p*3+2]<<16) + (255<<24)); nprtextures[i] = GL_LoadTexture32 (va("textures/tex%i_3_128_128.raw", i+1), 128, 128, data, true, false); } fclose(file); } } } } static void PPL_BaseChain_SimpleTexture(msurface_t *first) { msurface_t *s; int vi=-10; int iswall; int oldwall=-1; glRect_t *theRect; GL_SelectTexture(GL_TEXTURE0_ARB); PPL_EnableVertexArrays(); //draw the surface properly qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_TexEnv(GL_MODULATE); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); for (s = first; s ; s=s->texturechain) { if (s->plane->normal[2] <= 0.5) iswall = 1; else iswall = 0; if (vi != s->lightmaptexturenum || iswall != oldwall) { PPL_FlushArrays(); vi = s->lightmaptexturenum; oldwall = iswall; if (iswall) { GL_MBind(GL_TEXTURE0_ARB, walltexture); qglColor4fv(wallcolour); } else { GL_MBind(GL_TEXTURE0_ARB, floortexture); qglColor4fv(floorcolour); } if (vi < 0) GL_MBind(GL_TEXTURE1_ARB, 0 ); else { GL_MBind(GL_TEXTURE1_ARB, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } } PPL_GenerateArrays(s); } PPL_FlushArrays(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisableClientState(GL_VERTEX_ARRAY); qglDisable(GL_TEXTURE_2D); qglColor3f(1,1,1); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisableClientState(GL_VERTEX_ARRAY); qglEnable(GL_TEXTURE_2D); qglColor3f(1,1,1); } static void PPL_BaseChain_NPR_Sketch(msurface_t *first) { msurface_t *s; int vi=-10; int i; glRect_t *theRect; GL_SelectTexture(GL_TEXTURE0_ARB); PPL_EnableVertexArrays(); //draw the surface properly qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_TexEnv(GL_MODULATE); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); qglColor3f(1,1,1); for (s = first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { PPL_FlushArrays(); vi = s->lightmaptexturenum; GL_MBind(GL_TEXTURE0_ARB, nprtextures[rand()%10]); if (vi < 0) GL_MBind(GL_TEXTURE1_ARB, 0 ); else { GL_MBind(GL_TEXTURE1_ARB, lightmap_textures[vi] ); if (lightmap[vi]->modified) { lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } } PPL_GenerateArrays(s); } PPL_FlushArrays(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_COLOR_ARRAY); //draw some extra lines around the edge for added coolness. qglColor3f(0,0,0); for (vi = 0; vi < 2; vi++) { for (s = first; s ; s=s->texturechain) { if (!s->mesh) continue; for (i=0; imesh->numindexes; i+=3) { qglBegin(GL_LINE_LOOP); qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+0]][0]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+0]][1]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+0]][2]+5*(rand()/(float)RAND_MAX-0.5)); qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+1]][0]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+1]][1]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+1]][2]+5*(rand()/(float)RAND_MAX-0.5)); qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+2]][0]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+2]][1]+5*(rand()/(float)RAND_MAX-0.5), s->mesh->xyz_array[s->mesh->indexes[i+2]][2]+5*(rand()/(float)RAND_MAX-0.5)); qglEnd(); } } } qglEnable(GL_TEXTURE_2D); } static void PPL_BaseTextureChain(msurface_t *first) { texture_t *t; if (r_drawflat.value||!r_lightmapintensity) { if (r_drawflat.value == 2) { if (gl_mtexarbable >= 2) //shiesh!. { PPL_BaseChain_NPR_Sketch(first); return; } } else { if (gl_mtexarbable >= 2 && simpletextures) PPL_BaseChain_SimpleTexture(first); else PPL_BaseChain_Flat(first); //who cares about texture? :/ return; } } #ifdef Q3SHADERS if (first->texinfo->texture->shader) { meshbuffer_t mb; msurface_t *s; int vi=-1; int redraw = false; int dlb; glRect_t *theRect; if (first->texinfo->texture->shader->flags & SHADER_FLARE ) { dlight_t *dl; while(first) { //a quick hack to convert to a dlight dl = CL_AllocDlight(0); VectorCopy(first->mesh->xyz_array[0], dl->origin); dl->color[0] = 0.2; dl->color[1] = 0.2; dl->color[2] = 0.2; dl->radius = 50; //flashblend only dl->noppl = true; dl->nodynamic = true; first = first->texturechain; } return; } if (!varrayactive) R_IBrokeTheArrays(); mb.entity = &r_worldentity; mb.shader = first->texinfo->texture->shader; mb.mesh = NULL; mb.fog = NULL; mb.infokey = -2; if (first->dlightframe == r_framecount) mb.dlightbits = first->dlightbits; else mb.dlightbits = 0; GL_DisableMultitexture(); qglShadeModel(GL_SMOOTH); { for (s = first; s ; s=s->texturechain) { if (vi != s->lightmaptexturenum) { vi = s->lightmaptexturenum; if (vi >= 0) { if (gl_bump.value) if (lightmap[vi]->deluxmodified) { GL_BindType(GL_TEXTURE_2D, deluxmap_textures[vi] ); lightmap[vi]->deluxmodified = false; theRect = &lightmap[vi]->deluxrectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE, lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } if (lightmap[vi]->modified) { GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] ); lightmap[vi]->modified = false; theRect = &lightmap[vi]->rectchange; qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE, lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes); theRect->l = LMBLOCK_WIDTH; theRect->t = LMBLOCK_HEIGHT; theRect->h = 0; theRect->w = 0; } } } if (s->mesh) { if (s->dlightframe == r_framecount) dlb = s->dlightbits; else dlb = 0; redraw = mb.dlightbits != dlb || mb.fog != s->fog || mb.infokey != vi||R_MeshWillExceed(s->mesh); if (redraw) { if (mb.mesh) R_RenderMeshBuffer ( &mb, false ); redraw = false; } mb.infokey = vi; mb.mesh = s->mesh; mb.fog = s->fog; mb.dlightbits = dlb; R_PushMesh(s->mesh, mb.shader->features); } } } if (mb.mesh) R_RenderMeshBuffer ( &mb, false ); return; } #endif qglEnable(GL_TEXTURE_2D); t = GLR_TextureAnimation (first->texinfo->texture); if (first->flags & SURF_DRAWTURB) { GL_DisableMultitexture(); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Bind (t->gl_texturenum); for (; first ; first=first->texturechain) EmitWaterPolys (first, currententity->shaderRGBAf[3]); qglDisable(GL_BLEND); qglColor4f(1,1,1, 1); t->texturechain = NULL; //no lighting effects. (good job these don't animate eh?) return; } /* else if (s->lightmaptexturenum < 0) //no lightmap { PPL_BaseChain_NoLightmap(first, t); }*/ else if (gl_mtexarbable < 2) { //multitexture isn't supported. PPL_BaseChain_NoBump_1TMU(first, t); } else { if (gl_bump.value && currentmodel->deluxdata && t->gl_texturenumbumpmap) { if (gl_mtexarbable>=4) { if (t->gl_texturenumspec && gl_specular.value) { if (ppl_specular_shader) PPL_BaseChain_Specular_FP(first, t); // else if (gl_mtexarbable>=8) // PPL_BaseChain_Specular_8TMU(first, t); else PPL_BaseChain_Bump_4TMU(first, t); //can't do specular. } else PPL_BaseChain_Bump_4TMU(first, t); } else PPL_BaseChain_Bump_2TMU(first, t); } else { // PPL_BaseChain_NoBump_2TMU_TEST(first, t); // PPL_BaseChain_NoBump_2TMU(first, t); PPL_BaseChain_NoBump_2TMU_Overbright(first, t); } } } static void PPL_FullBrightTextureChain(msurface_t *first) { texture_t *t; msurface_t *s; t = GLR_TextureAnimation (first->texinfo->texture); if (detailtexture && gl_detail.value) { GL_Bind(detailtexture); qglBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); PPL_EnableVertexArrays(); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); for (s = first; s ; s=s->texturechain) { PPL_GenerateDetailArrays(s); } PPL_FlushArrays(); } if (t->gl_texturenumfb && r_fb_bmodels.value && cls.allow_luma) { GL_Bind(t->gl_texturenumfb); qglBlendFunc(GL_SRC_ALPHA, GL_ONE); if (gl_mylumassuck.value) qglEnable(GL_ALPHA_TEST); PPL_EnableVertexArrays(); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); for (s = first; s ; s=s->texturechain) { PPL_GenerateArrays(s); } PPL_FlushArrays(); if (gl_mylumassuck.value) qglDisable(GL_ALPHA_TEST); } } //requires multitexture void PPL_BaseTextures(model_t *model) { int i; msurface_t *s; texture_t *t; currententity = &r_worldentity; GL_DoSwap(); currententity->shaderRGBAf[0] = 1; currententity->shaderRGBAf[1] = 1; currententity->shaderRGBAf[2] = 1; currententity->shaderRGBAf[3] = 1; qglDisable(GL_BLEND); qglDisable(GL_ALPHA_TEST); qglColor4fv(currententity->shaderRGBAf); // qglDepthFunc(GL_LESS); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglShadeModel(GL_FLAT); overbright = 1; if (gl_overbright_all.value || (model->engineflags & MDLF_NEEDOVERBRIGHT)) { if (gl_overbright.value>=2) overbright = 4; else if (gl_overbright.value) overbright = 2; } currentmodel = model; if (model == cl.worldmodel && skytexturenum>=0) { t = model->textures[skytexturenum]; if (t) { s = t->texturechain; if (s) { t->texturechain = NULL; R_DrawSkyChain (s); } } } if (mirrortexturenum>=0 && model == cl.worldmodel && r_mirroralpha.value != 1.0) { t = model->textures[mirrortexturenum]; if (t) { s = t->texturechain; if (s) { t->texturechain = NULL; if (!r_inmirror) R_MirrorChain (s); } } } for (i=0 ; inumtextures ; i++) { t = model->textures[i]; if (!t) continue; s = t->texturechain; if (!s) continue; if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) continue; // draw translucent water later PPL_BaseTextureChain(s); } GL_DisableMultitexture(); } void PPL_BaseBModelTextures(entity_t *e) { extern msurface_t *r_alpha_surfaces; int i, k; int shift; model_t *model; msurface_t *s; msurface_t *chain = NULL; qglPushMatrix(); R_RotateForEntity(e); currentmodel = model = e->model; s = model->surfaces+model->firstmodelsurface; shift = GLR_LightmapShift(currentmodel); if (currententity->drawflags & DRF_TRANSLUCENT) currententity->shaderRGBAf[3]=0.5; if ((currententity->drawflags & MLS_ABSLIGHT) == MLS_ABSLIGHT) { currententity->shaderRGBAf[0] = currententity->shaderRGBAf[1] = currententity->shaderRGBAf[2] = currententity->abslight/255.0f; } if (currententity->shaderRGBAf[3]<1) { GL_TexEnv(GL_MODULATE); qglEnable(GL_BLEND); } else { GL_TexEnv(GL_REPLACE); qglDisable(GL_BLEND); } qglColor4fv(currententity->shaderRGBAf); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // calculate dynamic lighting for bmodel if it's not an // instanced model if (model->fromgame != fg_quake3) { if (currentmodel->nummodelsurfaces != 0 && r_dynamic.value) { for (k=0 ; kfuncs.MarkLights (&cl_dlights[k], 1<nodes + currentmodel->hulls[0].firstclipnode); } } //update lightmaps. for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) R_RenderDynamicLightmaps (s, shift); } for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) { if (s->texinfo->flags & SURF_TRANS33 || s->texinfo->flags & SURF_TRANS66) { s->ownerent = currententity; s->nextalphasurface = r_alpha_surfaces; r_alpha_surfaces = s; continue; } else if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next { PPL_BaseTextureChain(chain); chain = NULL; } s->texturechain = chain; chain = s; } if (chain) PPL_BaseTextureChain(chain); qglPopMatrix(); GL_DisableMultitexture(); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (!varrayactive) R_IBrokeTheArrays(); } #ifdef Q3SHADERS void R_DrawLightning(entity_t *e) { vec3_t v; vec3_t dir, cr; float scale = e->scale; float length; vec3_t points[4]; vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; int indexarray[6] = {0, 1, 2, 0, 2, 3}; mesh_t mesh; meshbuffer_t mb; if (!e->forcedshader) return; if (!scale) scale = 10; VectorSubtract(e->origin, e->oldorigin, dir); length = Length(dir); //this seems to be about right. texcoords[2][0] = length/128; texcoords[3][0] = length/128; VectorSubtract(r_refdef.vieworg, e->origin, v); CrossProduct(v, dir, cr); VectorNormalize(cr); VectorMA(e->origin, -scale/2, cr, points[0]); VectorMA(e->origin, scale/2, cr, points[1]); VectorSubtract(r_refdef.vieworg, e->oldorigin, v); CrossProduct(v, dir, cr); VectorNormalize(cr); VectorMA(e->oldorigin, scale/2, cr, points[2]); VectorMA(e->oldorigin, -scale/2, cr, points[3]); mesh.xyz_array = points; mesh.indexes = indexarray; mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]); mesh.colors_array = NULL; mesh.lmst_array = NULL; mesh.normals_array = NULL; mesh.numvertexes = 4; mesh.st_array = texcoords; mb.entity = e; mb.mesh = &mesh; mb.shader = e->forcedshader; mb.infokey = 0; mb.fog = NULL; mb.infokey = currententity->keynum; mb.dlightbits = 0; R_IBrokeTheArrays(); R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED); R_RenderMeshBuffer ( &mb, false ); } void R_DrawRailCore(entity_t *e) { vec3_t v; vec3_t dir, cr; float scale = e->scale; float length; mesh_t mesh; meshbuffer_t mb; vec3_t points[4]; vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; int indexarray[6] = {0, 1, 2, 0, 2, 3}; int colors[4]; qbyte colorsb[4]; if (!e->forcedshader) return; if (!scale) scale = 10; VectorSubtract(e->origin, e->oldorigin, dir); length = Length(dir); //this seems to be about right. texcoords[2][0] = length/128; texcoords[3][0] = length/128; VectorSubtract(r_refdef.vieworg, e->origin, v); CrossProduct(v, dir, cr); VectorNormalize(cr); VectorMA(e->origin, -scale/2, cr, points[0]); VectorMA(e->origin, scale/2, cr, points[1]); VectorSubtract(r_refdef.vieworg, e->oldorigin, v); CrossProduct(v, dir, cr); VectorNormalize(cr); VectorMA(e->oldorigin, scale/2, cr, points[2]); VectorMA(e->oldorigin, -scale/2, cr, points[3]); colorsb[0] = e->shaderRGBAf[0]*255; colorsb[1] = e->shaderRGBAf[1]*255; colorsb[2] = e->shaderRGBAf[2]*255; colorsb[3] = e->shaderRGBAf[3]*255; colors[0] = colors[1] = colors[2] = colors[3] = *(int*)colorsb; mesh.xyz_array = points; mesh.indexes = indexarray; mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]); mesh.colors_array = (byte_vec4_t*)colors; mesh.lmst_array = NULL; mesh.normals_array = NULL; mesh.numvertexes = 4; mesh.st_array = texcoords; mb.entity = e; mb.mesh = &mesh; mb.shader = e->forcedshader; mb.infokey = 0; mb.fog = NULL; mb.infokey = currententity->keynum; mb.dlightbits = 0; R_IBrokeTheArrays(); R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED | MF_COLORS); R_RenderMeshBuffer ( &mb, false ); } #endif void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); void PerpendicularVector( vec3_t dst, const vec3_t src ); void R_DrawBeam( entity_t *e ) { #define NUM_BEAM_SEGS 6 int i; float r, g, b; vec3_t perpvec; vec3_t direction, normalized_direction; vec3_t points[NUM_BEAM_SEGS*2]; vec3_t oldorigin, origin; float scale; oldorigin[0] = e->oldorigin[0]; oldorigin[1] = e->oldorigin[1]; oldorigin[2] = e->oldorigin[2]; origin[0] = e->origin[0]; origin[1] = e->origin[1]; origin[2] = e->origin[2]; normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; if ( VectorNormalize( normalized_direction ) == 0 ) return; PerpendicularVector( perpvec, normalized_direction ); scale = e->scale; if (!scale) scale = e->frame; if (!scale) scale = 6; VectorScale( perpvec, scale / 2, perpvec ); for ( i = 0; i < 6; i++ ) { RotatePointAroundVector( points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); VectorAdd( points[i], origin, points[i] ); VectorAdd( points[i], direction, points[i+NUM_BEAM_SEGS] ); } #ifdef Q3SHADERS if (e->forcedshader) { int indexarray[NUM_BEAM_SEGS*6]; vec2_t texcoords[NUM_BEAM_SEGS*2]; mesh_t mesh; meshbuffer_t mb; mesh.xyz_array = points; mesh.indexes = indexarray; mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]); mesh.colors_array = NULL; mesh.lmst_array = NULL; mesh.normals_array = NULL; mesh.numvertexes = NUM_BEAM_SEGS*2; mesh.st_array = texcoords; mb.entity = e; mb.mesh = &mesh; mb.shader = e->forcedshader; mb.infokey = 0; mb.fog = NULL; mb.infokey = currententity->keynum; mb.dlightbits = 0; for (i = 0; i < NUM_BEAM_SEGS; i++) { indexarray[i*6+0] = i+0; indexarray[i*6+1] = (i+1)%NUM_BEAM_SEGS; indexarray[i*6+2] = indexarray[i*6+1]+NUM_BEAM_SEGS; indexarray[i*6+3] = indexarray[i*6+0]; indexarray[i*6+4] = indexarray[i*6+2]; indexarray[i*6+5] = i+0+NUM_BEAM_SEGS; texcoords[i][1] = (float)i/NUM_BEAM_SEGS+0.35; texcoords[i][0] = 0; texcoords[i+NUM_BEAM_SEGS][1] = (float)i/NUM_BEAM_SEGS+0.35; texcoords[i+NUM_BEAM_SEGS][0] = 1; } R_IBrokeTheArrays(); R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED); R_RenderMeshBuffer ( &mb, false ); } else #endif { qglDisable( GL_TEXTURE_2D ); qglEnable( GL_BLEND ); qglDepthMask( GL_FALSE ); qglDisable(GL_ALPHA_TEST); r = ( d_8to24rgbtable[e->skinnum & 0xFF] ) & 0xFF; g = ( d_8to24rgbtable[e->skinnum & 0xFF] >> 8 ) & 0xFF; b = ( d_8to24rgbtable[e->skinnum & 0xFF] >> 16 ) & 0xFF; r *= e->shaderRGBAf[0]/255.0F; g *= e->shaderRGBAf[1]/255.0F; b *= e->shaderRGBAf[2]/255.0F; qglColor4f( r, g, b, e->shaderRGBAf[3] ); qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < NUM_BEAM_SEGS; i++ ) { qglVertex3fv( points[i] ); qglVertex3fv( points[i+NUM_BEAM_SEGS] ); qglVertex3fv( points[((i+1)%NUM_BEAM_SEGS)] ); qglVertex3fv( points[((i+1)%NUM_BEAM_SEGS)+NUM_BEAM_SEGS] ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglDepthMask( GL_TRUE ); } } void PPL_DrawEnt(entity_t *e, void *parm) { qglEnd(); currententity = e; qglDepthMask(1); qglDisable(GL_POLYGON_OFFSET_FILL); R_IBrokeTheArrays(); R_DrawGAliasModel (currententity); P_FlushRenderer(); qglBegin(GL_QUADS); } void PPL_BaseEntTextures(void) { extern model_t *currentmodel; int i; if (!r_drawentities.value) return; // draw sprites seperately, because of alpha blending for (i=0 ; irtype) continue; if (currententity->flags & Q2RF_BEAM) { R_DrawBeam(currententity); continue; } if (!currententity->model) continue; if (cls.allow_anyparticles || currententity->visframe) //allowed or static { if (currententity->model->engineflags & MDLF_ENGULPHS) { if (gl_part_flame.value) continue; } } switch (currententity->model->type) { //FIXME: We want to depth sort with particles, but we also want depth. :( //Until then, we have broken model lighting. case mod_alias: R_DrawGAliasModel (currententity); // if (currententity->flags & Q2RF_WEAPONMODEL) // RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, r_refdef.vieworg); // else // RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, currententity->origin); break; case mod_brush: qglDepthFunc ( gldepthfunc ); qglEnable(GL_DEPTH_TEST); qglDepthMask(1); PPL_BaseBModelTextures (currententity); break; default: break; } } currentmodel = cl.worldmodel; } #ifdef PPL static void PPL_GenerateLightArrays(msurface_t *surf, vec3_t relativelightorigin, dlight_t *light, vec3_t colour) { int vi; float *v, *stw; surfvertexarray_t *out; vec3_t lightdir; float dist; shadowlightfaces++; v = surf->mesh->xyz_array[0]; stw = surf->mesh->st_array[0]; out = &varray_v[0]; for (vi=0 ; vimesh->numvertexes ; vi++, v+=3, stw+=2, out++) { out->stw[0] = stw[0]; out->stw[1] = stw[1]; lightdir[0] = relativelightorigin[0] - v[0]; lightdir[1] = relativelightorigin[1] - v[1]; lightdir[2] = relativelightorigin[2] - v[2]; dist = 1-(sqrt( (lightdir[0])*(lightdir[0]) + (lightdir[1])*(lightdir[1]) + (lightdir[2])*(lightdir[2])) / light->radius); VectorNormalize(lightdir); out->stl[0] = colour[0]*dist; out->stl[1] = colour[1]*dist; out->stl[2] = colour[2]*dist; out->ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]); out->ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]); if (surf->flags & SURF_PLANEBACK) out->ncm[2] = -DotProduct(lightdir, surf->plane->normal); else out->ncm[2] = DotProduct(lightdir, surf->plane->normal); } } //flags enum{ PERMUTATION_GENERIC = 0, PERMUTATION_BUMPMAP = 1, PERMUTATION_SPECULAR = 2, PERMUTATION_BUMP_SPEC = 3, PERMUTATION_OFFSET = 4, PERMUTATION_OFFSET_BUMP = 5, PERMUTATION_OFFSET_SPEC = 6, PERMUTATION_OFFSET_BUMP_SPEC = 7, PERMUTATIONS }; int ppl_light_shader[PERMUTATIONS]; int ppl_light_shader_eyeposition[PERMUTATIONS]; int ppl_light_shader_lightposition[PERMUTATIONS]; int ppl_light_shader_lightcolour[PERMUTATIONS]; int ppl_light_shader_lightradius[PERMUTATIONS]; int ppl_light_shader_offset_scale[PERMUTATIONS]; int ppl_light_shader_offset_bias[PERMUTATIONS]; void PPL_CreateLightTexturesProgram(void) { int i; char *permutation[PERMUTATIONS] = { "", "#define BUMP\n", "#define SPECULAR\n", "#define SPECULAR\n#define BUMP\n", "#define USEOFFSETMAPPING\n", "#define USEOFFSETMAPPING\n#define BUMP\n", "#define USEOFFSETMAPPING\n#define SPECULAR\n", "#define USEOFFSETMAPPING\n#define SPECULAR\n#define BUMP\n" }; char *vert = "varying vec2 tcbase;\n" "uniform vec3 texr, texu, texf;\n" "varying vec3 LightVector;\n" "uniform vec3 LightPosition;\n" "#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "uniform vec3 EyePosition;\n" "varying vec3 EyeVector;\n" "#endif\n" "void main (void)\n" "{\n" " gl_Position = ftransform();\n" " tcbase = gl_MultiTexCoord0.xy;\n" //pass the texture coords straight through " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n" " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n" " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n" " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n" "#if defined(SPECULAR)||defined(USEOFFSETMAPPING)\n" " vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n" " EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n" " EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n" " EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n" "#endif\n" "}\n" ; char *frag = "uniform sampler2D baset;\n" "#if defined(BUMP) || defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "uniform sampler2D bumpt;\n" "#endif\n" "#ifdef SPECULAR\n" "uniform sampler2D speculart;\n" "#endif\n" "varying vec2 tcbase;\n" "varying vec3 LightVector;\n" "uniform float lightradius;\n" "uniform vec3 LightColour;\n" "#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n" "varying vec3 EyeVector;\n" "#endif\n" "#ifdef USEOFFSETMAPPING\n" "uniform float OffsetMapping_Scale;\n" "uniform float OffsetMapping_Bias;\n" "#endif\n" "void main (void)\n" "{\n" "#ifdef USEOFFSETMAPPING\n" " // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n" " vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n" " vec2 TexCoordOffset = tcbase + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, tcbase).w);\n" " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n" " TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n" "#define tcbase TexCoordOffset\n" "#endif\n" "#ifdef BUMP\n" " vec3 bases = vec3(texture2D(baset, tcbase));\n" "#else\n" " vec3 diff = vec3(texture2D(baset, tcbase));\n" "#endif\n" "#if defined(BUMP) || defined(SPECULAR)\n" " vec3 bumps = vec3(texture2D(bumpt, tcbase)) * 2.0 - 1.0;\n" "#endif\n" "#ifdef SPECULAR\n" " vec3 specs = vec3(texture2D(speculart, tcbase));\n" "#endif\n" " vec3 nl = normalize(LightVector);\n" " float colorscale = max(1.0 - dot(LightVector, LightVector)/(lightradius*lightradius), 0.0);\n" "#ifdef BUMP\n" " vec3 diff;\n" " diff = bases * max(dot(bumps, nl), 0.0);\n" "#endif\n" "#ifdef SPECULAR\n" " vec3 halfdir = (normalize(EyeVector) + normalize(LightVector))/2.0;\n" " float dv = dot(halfdir, bumps);\n" " diff += pow(dv, 8.0) * specs;\n" "#endif\n" " gl_FragColor.rgb = diff*colorscale*LightColour;\n" "}\n" ; for (i = 0; i < PERMUTATIONS; i++) { ppl_light_shader[i] = GLSlang_CreateProgram(permutation[i], vert, frag); if (ppl_light_shader[i]) { GLSlang_UseProgram(ppl_light_shader[i]); qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "baset"), 0); qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "bumpt"), 1); qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "speculart"), 2); ppl_light_shader_eyeposition[i] = qglGetUniformLocationARB(ppl_light_shader[i], "EyePosition"); ppl_light_shader_lightposition [i]= qglGetUniformLocationARB(ppl_light_shader[i], "LightPosition"); ppl_light_shader_lightcolour[i] = qglGetUniformLocationARB(ppl_light_shader[i], "LightColour"); ppl_light_shader_lightradius[i] = qglGetUniformLocationARB(ppl_light_shader[i], "lightradius"); ppl_light_shader_offset_scale[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Scale"); ppl_light_shader_offset_bias[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Bias"); GLSlang_UseProgram(0); } } }; void PPL_LightTexturesFP_Cached(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour) { int i, j; texture_t *t; msurface_t *s; int p, lp=-1; extern cvar_t gl_specular; shadowmesh_t *shm = light->worldshadowmesh; vec3_t relativelightorigin; vec3_t relativeeyeorigin; if (qglGetError()) Con_Printf("GL Error before lighttextures\n"); VectorSubtract(light->origin, modelorigin, relativelightorigin); VectorSubtract(r_refdef.vieworg, modelorigin, relativeeyeorigin); qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); qglBlendFunc(GL_ONE, GL_ONE); qglDisableClientState(GL_COLOR_ARRAY); if (qglGetError()) Con_Printf("GL Error early in lighttextures\n"); for (j=0 ; jnumsurftextures ; j++) { if (!shm->litsurfs[j].count) continue; s = shm->litsurfs[j].s[0]; t = s->texinfo->texture; t = GLR_TextureAnimation (t); for (i=0 ; ilitsurfs[j].count ; i++) { s = shm->litsurfs[j].s[i]; if (s->visframe != r_framecount) continue; if (s->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius) continue; } else { if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius) continue; } // if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) // continue; // draw translucent water later p = 0; if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP]) p |= PERMUTATION_BUMPMAP; if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR]) p |= PERMUTATION_SPECULAR; if (r_shadow_glsl_offsetmapping.value && t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_OFFSET]) p |= PERMUTATION_OFFSET; if (p != lp) { lp = p; GLSlang_UseProgram(ppl_light_shader[p]); if (ppl_light_shader_eyeposition[p] != -1) qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin); qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin); qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour); qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius); if (ppl_light_shader_offset_scale[p]!=-1) qglUniform1fARB(ppl_light_shader_offset_scale[p], r_shadow_glsl_offsetmapping_scale.value); if (ppl_light_shader_offset_bias[p]!=-1) qglUniform1fARB(ppl_light_shader_offset_bias[p], r_shadow_glsl_offsetmapping_bias.value); } if (p & PERMUTATION_BUMPMAP) GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap); if (p & PERMUTATION_SPECULAR) GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec); GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, s->texinfo->vecs[0][0], s->texinfo->vecs[0][1], s->texinfo->vecs[0][2]); qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, -s->texinfo->vecs[1][0], -s->texinfo->vecs[1][1], -s->texinfo->vecs[1][2]); if (s->flags & SURF_PLANEBACK) qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]); else qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } } GLSlang_UseProgram(0); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); if (qglGetError()) Con_Printf("GL Error during lighttextures\n"); } void PPL_LightTexturesFP(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour) { int i; texture_t *t; msurface_t *s; int p, lp=-1; extern cvar_t gl_specular; vec3_t relativelightorigin; vec3_t relativeeyeorigin; if (qglGetError()) Con_Printf("GL Error before lighttextures\n"); VectorSubtract(light->origin, modelorigin, relativelightorigin); VectorSubtract(r_refdef.vieworg, modelorigin, relativeeyeorigin); qglEnable(GL_BLEND); GL_TexEnv(GL_MODULATE); qglBlendFunc(GL_ONE, GL_ONE); qglDisableClientState(GL_COLOR_ARRAY); if (qglGetError()) Con_Printf("GL Error early in lighttextures\n"); for (i=0 ; inumtextures ; i++) { t = model->textures[i]; if (!t) continue; s = t->texturechain; if (!s) continue; // if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) // continue; // draw translucent water later t = GLR_TextureAnimation (t); p = 0; if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP]) p |= PERMUTATION_BUMPMAP; if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR]) p |= PERMUTATION_SPECULAR; if (p != lp) { lp = p; GLSlang_UseProgram(ppl_light_shader[p]); if (ppl_light_shader_eyeposition[p] != -1) qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin); qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin); qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour); qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius); } if (p & PERMUTATION_BUMPMAP) GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap); if (p & PERMUTATION_SPECULAR) GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec); GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); for (; s; s=s->texturechain) { if (s->shadowframe != r_shadowframe) continue; if (s->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius) continue; } else { if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius) continue; } qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, s->texinfo->vecs[0][0], s->texinfo->vecs[0][1], s->texinfo->vecs[0][2]); qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, -s->texinfo->vecs[1][0], -s->texinfo->vecs[1][1], -s->texinfo->vecs[1][2]); if (s->flags & SURF_PLANEBACK) qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]); else qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } } GLSlang_UseProgram(0); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); if (qglGetError()) Con_Printf("GL Error during lighttextures\n"); } void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour) { int i; msurface_t *s; texture_t *t; vec3_t relativelightorigin; if (ppl_light_shader[0]) { if (model == cl.worldmodel && light->worldshadowmesh) PPL_LightTexturesFP_Cached(model, modelorigin, light, colour); else PPL_LightTexturesFP(model, modelorigin, light, colour); return; } PPL_EnableVertexArrays(); VectorSubtract(light->origin, modelorigin, relativelightorigin); qglShadeModel(GL_SMOOTH); for (i=0 ; inumtextures ; i++) { t = model->textures[i]; if (!t) continue; s = t->texturechain; if (!s) continue; if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) continue; // draw translucent water later { extern int normalisationCubeMap; t = GLR_TextureAnimation (t); qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); if (t->gl_texturenumbumpmap && gl_mtexarbable>3) { GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); //Set up texture environment to do (tex0 dot tex1)*color GL_TexEnv(GL_REPLACE); //make texture normalmap available. qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_SelectTexture(GL_TEXTURE1_ARB); GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap); qglEnable(GL_TEXTURE_CUBE_MAP_ARB); GL_TexEnv(GL_COMBINE_ARB); //normalisation cubemap . normalmap qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm); GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap); //a dummy qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); //bumps * color (the attenuation) qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture) qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum); qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); } else { if (gl_mtexarbable>3) { GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_CUBE_MAP_ARB); GL_SelectTexture(GL_TEXTURE0_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); qglDisable(GL_TEXTURE_2D); } for (; s; s=s->texturechain) { if (s->shadowframe != r_shadowframe) continue; if (s->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius) continue; } else { if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius) continue; } PPL_GenerateLightArrays(s, relativelightorigin, light, colour); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); varray_ic = 0; varray_vc = 0; } } } if (gl_mtexarbable>2) { GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_CUBE_MAP_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); } void PPL_LightBModelTexturesFP(entity_t *e, dlight_t *light, vec3_t colour) { int i; texture_t *t; msurface_t *s; model_t *model = e->model; texture_t *tnum = NULL; int p, lp = -1; vec3_t relativelightorigin; vec3_t relativeeyeorigin; if (qglGetError()) Con_Printf("GL Error before lighttextures\n"); //Fixme: rotate VectorSubtract(light->origin, e->origin, relativelightorigin); VectorSubtract(r_refdef.vieworg, e->origin, relativeeyeorigin); qglEnable(GL_BLEND); qglBlendFunc(GL_ONE, GL_ONE); if (qglGetError()) Con_Printf("GL Error early in lighttextures\n"); for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) { if (tnum != s->texinfo->texture) { tnum = s->texinfo->texture; t = GLR_TextureAnimation (tnum); p = 0; if (t->gl_texturenumbumpmap && ppl_light_shader[p|PERMUTATION_BUMPMAP]) p |= PERMUTATION_BUMPMAP; if (gl_specular.value && t->gl_texturenumspec && ppl_light_shader[p|PERMUTATION_SPECULAR]) p |= PERMUTATION_SPECULAR; if (p != lp) { lp = p; GLSlang_UseProgram(ppl_light_shader[p]); if (ppl_light_shader_eyeposition[p] != -1) qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin); qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin); qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour); qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius); } GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenum); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_MBind(GL_TEXTURE1_ARB, t->gl_texturenumbumpmap); GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumspec); GL_SelectTexture(GL_TEXTURE0_ARB); } qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, -s->texinfo->vecs[0][0], -s->texinfo->vecs[0][1], -s->texinfo->vecs[0][2]); qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, s->texinfo->vecs[1][0], s->texinfo->vecs[1][1], s->texinfo->vecs[1][2]); if (s->flags & SURF_PLANEBACK) qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]); else qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]); qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); } GLSlang_UseProgram(0); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); if (qglGetError()) Con_Printf("GL Error during lighttextures\n"); } void PPL_LightBModelTextures(entity_t *e, dlight_t *light, vec3_t colour) { int i; model_t *model = e->model; msurface_t *s; texture_t *t; vec3_t relativelightorigin; qglPushMatrix(); R_RotateForEntity(e); if (ppl_light_shader[0]) { PPL_LightBModelTexturesFP(e, light, colour); qglPopMatrix(); return; } qglColor4f(1, 1, 1, 1); PPL_EnableVertexArrays(); VectorSubtract(light->origin, e->origin, relativelightorigin); qglShadeModel(GL_SMOOTH); for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) { t = GLR_TextureAnimation (s->texinfo->texture); qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl); if (t->gl_texturenumbumpmap && gl_mtexarbable>3) { GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); //Set up texture environment to do (tex0 dot tex1)*color GL_TexEnv(GL_REPLACE); //make texture normalmap available. qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); GL_SelectTexture(GL_TEXTURE1_ARB); GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap); qglEnable(GL_TEXTURE_CUBE_MAP_ARB); GL_TexEnv(GL_COMBINE_ARB); //normalisation cubemap * normalmap qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm); GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap); qglEnable(GL_TEXTURE_2D); GL_TexEnv(GL_COMBINE_ARB); //bumps * color (the attenuation) qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture) qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum); qglEnable(GL_TEXTURE_2D); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); } else { if (gl_mtexarbable>3) { GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE1_ARB); GL_TexEnv(GL_MODULATE); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_CUBE_MAP_ARB); GL_SelectTexture(GL_TEXTURE0_ARB); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw); } // for (; s; s=s->texturechain) { // if (s->shadowframe != r_shadowframe) // continue; /* if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius || fabs(s->center[1] - lightorg[1]) > lightradius+s->radius || fabs(s->center[2] - lightorg[2]) > lightradius+s->radius) continue;*/ if (s->flags & SURF_PLANEBACK) {//inverted normal. if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius) continue; } else { if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius) continue; } PPL_GenerateLightArrays(s, relativelightorigin, light, colour); qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_UNSIGNED_INT, s->mesh->indexes); varray_ic = 0; varray_vc = 0; } PPL_FlushArrays(); } if (gl_mtexarbable>2) { GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE2_ARB); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE1_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_TexEnv(GL_MODULATE); qglDisable(GL_TEXTURE_CUBE_MAP_ARB); GL_SelectTexture(GL_TEXTURE0_ARB); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_TEXTURE_2D); qglPopMatrix(); } //draw the bumps on the models for each light. void PPL_DrawEntLighting(dlight_t *light, vec3_t colour) { int i; PPL_LightTextures(cl.worldmodel, r_worldentity.origin, light, colour); if (!r_drawentities.value) return; for (i=0 ; iflags & Q2RF_WEAPONMODEL) continue; } else { if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1))) continue; // if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum]) // continue; if (!Cam_DrawPlayer(0, currententity->keynum-1)) continue; } if (currententity->flags & Q2RF_BEAM) { continue; } if (!currententity->model) continue; switch (currententity->model->type) { case mod_alias: if (!varrayactive) R_IBrokeTheArrays(); R_DrawGAliasModelLighting (currententity, light->origin, colour, light->radius); break; case mod_brush: PPL_LightBModelTextures (currententity, light, colour); break; default: break; } } } #endif void PPL_FullBrights(model_t *model) { int tn; msurface_t *s; texture_t *t; qglColor3f(1,1,1); qglDepthMask(0); //don't bother writing depth GL_TexEnv(GL_MODULATE); qglShadeModel(GL_FLAT); qglEnable(GL_BLEND); qglEnable(GL_TEXTURE_2D); for (tn=0 ; tnnumtextures ; tn++) { t = model->textures[tn]; if (!t) continue; s = t->texturechain; if (!s) continue; if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0) continue; // draw translucent water later PPL_FullBrightTextureChain(s); t->texturechain=NULL; } GL_TexEnv(GL_REPLACE); qglDepthMask(1); } void PPL_FullBrightBModelTextures(entity_t *e) { int i; model_t *model; msurface_t *s; msurface_t *chain = NULL; qglPushMatrix(); R_RotateForEntity(e); currentmodel = model = e->model; s = model->surfaces+model->firstmodelsurface; qglColor4f(1, 1, 1, 1); qglDepthMask(0); //don't bother writing depth GL_TexEnv(GL_MODULATE); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglShadeModel(GL_FLAT); qglEnable(GL_BLEND); qglEnable(GL_TEXTURE_2D); for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++) { if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next { PPL_FullBrightTextureChain(chain); chain = NULL; } s->texturechain = chain; chain = s; } if (chain) PPL_FullBrightTextureChain(chain); qglPopMatrix(); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); qglDepthMask(1); } //draw the bumps on the models for each light. void PPL_DrawEntFullBrights(void) { int i; currententity = &r_worldentity; // if (gl_detail.value || (r_fb_bmodels.value && cls.allow_luma)) PPL_FullBrights(cl.worldmodel); if (!r_drawentities.value) return; for (i=0 ; ikeynum == cl.viewentity[r_refdef.currentplayernum]) continue; if (!Cam_DrawPlayer(0, currententity->keynum-1)) continue; if (currententity->flags & Q2RF_BEAM) continue; if (!currententity->model) continue; if (cls.allow_anyparticles || currententity->visframe) //allowed or static { if (currententity->model->engineflags & MDLF_ENGULPHS) { if (gl_part_flame.value) continue; } } switch (currententity->model->type) { case mod_alias: // R_DrawGAliasModelLighting (currententity); break; case mod_brush: PPL_FullBrightBModelTextures (currententity); break; default: break; } } } void PPL_SchematicsTextureChain(msurface_t *first) { extern int char_texture; msurface_t *s; float *v1, *v2; float len; unsigned char str[64]; int sl, c; vec3_t dir; vec3_t pos, v; const float size = 0.0625; float frow, fcol; int e, en; if (!cl.worldmodel->surfedges) return; qglEnable(GL_ALPHA_TEST); if (qglPolygonOffset) qglPolygonOffset(-1, 0); frow = rand()/(float)RAND_MAX; frow=frow/2+0.5; qglColor3f(frow, frow, 0); //draw the distances if (gl_schematics.value != 2) { qglEnable(GL_POLYGON_OFFSET_FILL); qglEnable(GL_TEXTURE_2D); GL_Bind(char_texture); qglBegin(GL_QUADS); for (s = first; s ; s=s->texturechain) { for (e = s->numedges; e >= 0; e--) { en = cl.worldmodel->surfedges[e+s->firstedge]; if (en<0) //backwards { en = -en; v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position; v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position; } else { v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position; v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position; } VectorSubtract(v1, v2, dir); len = Length(dir); VectorNormalize(dir); sprintf(str, "%i", (len<1)?1:(int)len); sl = strlen(str); VectorMA(v2, len/2 + sl*4, dir, pos); for (c = 0; c < sl; c++) { frow = (str[c]>>4)*size; fcol = (str[c]&15)*size; qglTexCoord2f (fcol, frow + size); qglVertex3fv(pos); if (s->flags & SURF_PLANEBACK) VectorMA(pos, -8, s->plane->normal, v); else VectorMA(pos, 8, s->plane->normal, v); qglTexCoord2f (fcol, frow); qglVertex3fv(v); VectorMA(pos, -8, dir, pos); if (s->flags & SURF_PLANEBACK) VectorMA(pos, -8, s->plane->normal, v); else VectorMA(pos, 8, s->plane->normal, v); qglTexCoord2f (fcol + size, frow); qglVertex3fv(v); qglTexCoord2f (fcol + size, frow + size); qglVertex3fv(pos); } } } qglEnd(); qglDisable(GL_POLYGON_OFFSET_FILL); } qglEnable(GL_POLYGON_OFFSET_LINE); qglDisable(GL_TEXTURE_2D); qglBegin(GL_LINES); for (s = first; s ; s=s->texturechain) { for (e = s->numedges; e >= 0; e--) { en = cl.worldmodel->surfedges[e+s->firstedge]; if (en<0) //backwards en = -en; v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position; v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position; VectorSubtract(v2, v1, dir); len = Length(dir); VectorNormalize(dir); if (gl_schematics.value != 2) { sprintf(str, "%i", (len<1)?1:(int)len); sl = strlen(str); } else sl = 0; //left side. (find arrowhead part) if (s->flags & SURF_PLANEBACK) VectorMA(v1, -4, s->plane->normal, pos); else VectorMA(v1, 4, s->plane->normal, pos); VectorMA(pos, 4, dir, v); if (s->flags & SURF_PLANEBACK) VectorMA(v, 4, s->plane->normal, v); else VectorMA(v, -4, s->plane->normal, v); qglVertex3fv(v); qglVertex3fv(pos); if (s->flags & SURF_PLANEBACK) VectorMA(v, -8, s->plane->normal, v); else VectorMA(v, 8, s->plane->normal, v); qglVertex3fv(v); qglVertex3fv(pos); //the line qglVertex3fv(pos); VectorMA(pos, len/2 - sl*4, dir, pos); qglVertex3fv(pos); //right hand side. if (s->flags & SURF_PLANEBACK) VectorMA(v2, -4, s->plane->normal, pos); else VectorMA(v2, 4, s->plane->normal, pos); VectorMA(pos, -4, dir, v); if (s->flags & SURF_PLANEBACK) VectorMA(v, 4, s->plane->normal, v); else VectorMA(v, -4, s->plane->normal, v); qglVertex3fv(v); qglVertex3fv(pos); if (s->flags & SURF_PLANEBACK) VectorMA(v, -8, s->plane->normal, v); else VectorMA(v, 8, s->plane->normal, v); qglVertex3fv(v); qglVertex3fv(pos); //the line qglVertex3fv(pos); VectorMA(pos, -(len/2 - sl*4), dir, pos); qglVertex3fv(pos); } } qglEnd(); qglDisable(GL_POLYGON_OFFSET_LINE); qglEnable(GL_TEXTURE_2D); } // :) void PPL_Schematics(void) { int tn; msurface_t *s; texture_t *t; model_t *model; qglColor3f(1,1,1); qglDepthMask(0); //don't bother writing depth GL_TexEnv(GL_MODULATE); qglShadeModel(GL_FLAT); qglEnable(GL_BLEND); qglDisable(GL_TEXTURE_2D); model = cl.worldmodel; for (tn=0 ; tnnumtextures ; tn++) { t = model->textures[tn]; if (!t) continue; s = t->texturechain; if (!s) continue; PPL_SchematicsTextureChain(s); t->texturechain=NULL; } GL_TexEnv(GL_REPLACE); qglDepthMask(1); } #ifdef PPL qboolean PPL_VisOverlaps(qbyte *v1, qbyte *v2) { int i, m; m = (cl.worldmodel->numleafs-1)>>3; for (i=0 ; inumleafs+7)/8; mleaf_t *wl = cl.worldmodel->leafs; unsigned char lv; for (i = 0; i < m; i++) { lv = lightvis[i]; if (lv&1 && wl[(i<<3)+0].visframe == r_visframecount) return true; if (lv&2 && wl[(i<<3)+1].visframe == r_visframecount) return true; if (lv&4 && wl[(i<<3)+2].visframe == r_visframecount) return true; if (lv&8 && wl[(i<<3)+3].visframe == r_visframecount) return true; if (lv&16 && wl[(i<<3)+4].visframe == r_visframecount) return true; if (lv&32 && wl[(i<<3)+5].visframe == r_visframecount) return true; if (lv&64 && wl[(i<<3)+6].visframe == r_visframecount) return true; if (lv&128 && wl[(i<<3)+7].visframe == r_visframecount) return true; } return false; } void PPL_RecursiveWorldNode_r (mnode_t *node) { int c, side; mplane_t *plane; msurface_t *surf, **mark; mleaf_t *pleaf; double dot; int v; float *v1; vec3_t v3; if (node->shadowframe != r_shadowframe) return; if (node->contents == Q1CONTENTS_SOLID) return; // solid //if light areabox is outside node, ignore node + children for (c = 0; c < 3; c++) { if (lightorg[c] + lightradius < node->minmaxs[c]) return; if (lightorg[c] - lightradius > node->minmaxs[3+c]) return; } // if a leaf node, draw stuff if (node->contents < 0) { pleaf = (mleaf_t *)node; PPL_Shadow_Cache_Leaf(pleaf); mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; if (c) { do { (*mark++)->shadowframe = r_shadowframe; } while (--c); } return; } // node is just a decision point, so go down the apropriate sides // find which side of the node we are on plane = node->plane; switch (plane->type) { case PLANE_X: dot = modelorg[0] - plane->dist; break; case PLANE_Y: dot = modelorg[1] - plane->dist; break; case PLANE_Z: dot = modelorg[2] - plane->dist; break; default: dot = DotProduct (modelorg, plane->normal) - plane->dist; break; } if (dot >= 0) side = 0; else side = 1; // recurse down the children, front side first PPL_RecursiveWorldNode_r (node->children[side]); // draw stuff c = node->numsurfaces; if (c) { surf = cl.worldmodel->surfaces + node->firstsurface; { for ( ; c ; c--, surf++) { if (surf->shadowframe != r_shadowframe) continue; // if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) // continue; // wrong side // if (surf->flags & SURF_PLANEBACK) // continue; if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED)) { // no shadows continue; } //is the light on the right side? if (surf->flags & SURF_PLANEBACK) {//inverted normal. if (-DotProduct(surf->plane->normal, lightorg)+surf->plane->dist >= lightradius) continue; } else { if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= lightradius) continue; } /* if (fabs(surf->center[0] - lightorg[0]) > lightradius+surf->radius || fabs(surf->center[1] - lightorg[1]) > lightradius+surf->radius || fabs(surf->center[2] - lightorg[2]) > lightradius+surf->radius) continue; */ PPL_Shadow_Cache_Surface(surf); #define PROJECTION_DISTANCE (float)(lightradius*2)//0x7fffffff //build a list of the edges that are to be drawn. for (v = 0; v < surf->numedges; v++) { int e, delta; shadowemittedeges++; e = cl.worldmodel->surfedges[surf->firstedge+v]; //negative edge means backwards edge. if (e < 0) { e=-e; delta = -1; } else { delta = 1; } if (!edge[e].count) { if (firstedge) edge[firstedge].prev = e; edge[e].next = firstedge; edge[e].prev = 0; firstedge = e; edge[e].count = delta; } else { edge[e].count += delta; if (!edge[e].count) //unlink { if (edge[e].next) { edge[edge[e].next].prev = edge[e].prev; } if (edge[e].prev) edge[edge[e].prev].next = edge[e].next; else firstedge = edge[e].next; } } } shadowsurfcount++; qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, surf->mesh->numindexes, GL_UNSIGNED_INT, surf->mesh->indexes); //fixme:this only works becuse q1bsps don't have combined meshes yet... //back (depth precision doesn't matter) qglBegin(GL_POLYGON); for (v = surf->mesh->numvertexes-1; v >=0; v--) { v1 = surf->mesh->xyz_array[v]; v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] ); } qglEnd(); } } } // recurse down the back side PPL_RecursiveWorldNode_r (node->children[!side]); } //2 changes, but otherwise the same void PPL_RecursiveWorldNodeQ2_r (mnode_t *node) { int c, side; mplane_t *plane; msurface_t *surf, **mark; mleaf_t *pleaf; double dot; int v; float *v1; vec3_t v3; if (node->contents == Q2CONTENTS_SOLID) return; // solid if (node->shadowframe != r_shadowframe) return; // if (R_CullBox (node->minmaxs, node->minmaxs+3)) // return; // if a leaf node, draw stuff if (node->contents != -1) { pleaf = (mleaf_t *)node; mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; if (c) { do { (*mark++)->shadowframe = r_shadowframe; } while (--c); } return; } // node is just a decision point, so go down the apropriate sides // find which side of the node we are on plane = node->plane; switch (plane->type) { case PLANE_X: dot = modelorg[0] - plane->dist; break; case PLANE_Y: dot = modelorg[1] - plane->dist; break; case PLANE_Z: dot = modelorg[2] - plane->dist; break; default: dot = DotProduct (modelorg, plane->normal) - plane->dist; break; } if (dot >= 0) side = 0; else side = 1; // recurse down the children, front side first PPL_RecursiveWorldNodeQ2_r (node->children[side]); // draw stuff c = node->numsurfaces; if (c) { surf = cl.worldmodel->surfaces + node->firstsurface; { for ( ; c ; c--, surf++) { if (surf->shadowframe != r_shadowframe) continue; /* if (surf->lightframe == r_shadowframe) //done this one! continue; surf->lightframe = r_shadowframe; */ // if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) // continue; // wrong side // if (surf->flags & SURF_PLANEBACK) // continue; if (surf->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= 0) continue; } else { if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= 0) continue; } //#define PROJECTION_DISTANCE (float)0x7fffffff if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED)) { // no shadows continue; } //build a list of the edges that are to be drawn. for (v = 0; v < surf->numedges; v++) { int e, delta; e = cl.worldmodel->surfedges[surf->firstedge+v]; //negative edge means backwards edge. if (e < 0) { e=-e; delta = -1; } else { delta = 1; } if (!edge[e].count) { if (firstedge) edge[firstedge].prev = e; edge[e].next = firstedge; edge[e].prev = 0; firstedge = e; edge[e].count = delta; } else { edge[e].count += delta; if (!edge[e].count) //unlink { if (edge[e].next) { edge[edge[e].next].prev = edge[e].prev; } if (edge[e].prev) edge[edge[e].prev].next = edge[e].next; else firstedge = edge[e].next; } } } //front face qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array); qglDrawElements(GL_TRIANGLES, surf->mesh->numindexes, GL_UNSIGNED_INT, surf->mesh->indexes); //fixme:this only works becuse q1bsps don't have combined meshes yet... //back (depth precision doesn't matter) qglBegin(GL_POLYGON); for (v = surf->mesh->numvertexes-1; v >=0; v--) { v1 = surf->mesh->xyz_array[v]; v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] ); } qglEnd(); } } } // recurse down the back side PPL_RecursiveWorldNodeQ2_r (node->children[!side]); } void PPL_RecursiveWorldNodeQ3_r (mnode_t *node) { int c, side; mplane_t *plane; msurface_t *surf, **mark; mleaf_t *pleaf; double dot; // glpoly_t *p; // int v; // float *v2; // vec3_t v4; // vec3_t v3; if (node->contents == Q2CONTENTS_SOLID) return; // solid if (node->shadowframe != r_shadowframe) return; // if (R_CullBox (node->minmaxs, node->minmaxs+3)) // return; // if a leaf node, draw stuff if (node->contents != -1) { pleaf = (mleaf_t *)node; mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; if (c) { do { surf = *mark; (*mark++)->shadowframe = r_shadowframe; /* if (surf->shadowframe != r_shadowframe) continue; */ // if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) // continue; // wrong side // if (surf->flags & SURF_PLANEBACK) // continue; if (surf->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= -lightradius) continue; } else { if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= lightradius) continue; } //#define PROJECTION_DISTANCE (float)0x7fffffff /*if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED)) { // no shadows continue; }*/ Sys_Error("PPL_RecursiveWorldNodeQ3_r needs work"); /* for (p = surf->polys; p; p=p->next) { //front face qglVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts); qglDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri); //fixme... for (v = 0; v < p->numverts; v++) { //border v1 = p->verts[v]; v2 = p->verts[( v+1 )%p->numverts]; //get positions of v3 and v4 based on the light position v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE; v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE; v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE; //Now draw the quad from the two verts to the projected light //verts qglBegin( GL_QUAD_STRIP ); qglVertex3f( v1[0], v1[1], v1[2] ); qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] ); qglVertex3f( v2[0], v2[1], v2[2] ); qglVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] ); qglEnd(); } //back qglBegin(GL_POLYGON); for (v = p->numverts-1; v >=0; v--) { v1 = p->verts[v]; v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] ); } qglEnd(); } */ } while (--c); } return; } // node is just a decision point, so go down the apropriate sides // find which side of the node we are on plane = node->plane; switch (plane->type) { case PLANE_X: dot = modelorg[0] - plane->dist; break; case PLANE_Y: dot = modelorg[1] - plane->dist; break; case PLANE_Z: dot = modelorg[2] - plane->dist; break; default: dot = DotProduct (modelorg, plane->normal) - plane->dist; break; } if (dot >= 0) side = 0; else side = 1; // recurse down the children, front side first PPL_RecursiveWorldNodeQ3_r (node->children[side]); // draw stuff /* c = node->numsurfaces; if (c) { surf = cl.worldmodel->surfaces + node->firstsurface; { for ( ; c ; c--, surf++) { } } } */ // recurse down the back side PPL_RecursiveWorldNodeQ3_r (node->children[!side]); } void PPL_RecursiveWorldNode (dlight_t *dl) { float *v1, *v2; vec3_t v3, v4; lightradius = dl->radius; lightorg[0] = dl->origin[0]+0.5; lightorg[1] = dl->origin[1]+0.5; lightorg[2] = dl->origin[2]+0.5; modelorg[0] = lightorg[0]; modelorg[1] = lightorg[1]; modelorg[2] = lightorg[2]; if (dl->worldshadowmesh) { qglEnableClientState(GL_VERTEX_ARRAY); qglVertexPointer(3, GL_FLOAT, 0, dl->worldshadowmesh->verts); qglDrawRangeElements(GL_TRIANGLES, 0, dl->worldshadowmesh->numverts, dl->worldshadowmesh->numindicies, GL_UNSIGNED_INT, dl->worldshadowmesh->indicies); return; } PPL_BeginShadowMesh(dl); qglEnableClientState(GL_VERTEX_ARRAY); if (qglGetError()) Con_Printf("GL Error on entities\n"); if (cl.worldmodel->fromgame == fg_quake3) PPL_RecursiveWorldNodeQ3_r(cl.worldmodel->nodes); else if (cl.worldmodel->fromgame == fg_quake2) PPL_RecursiveWorldNodeQ2_r(cl.worldmodel->nodes); else PPL_RecursiveWorldNode_r(cl.worldmodel->nodes); if (qglGetError()) Con_Printf("GL Error on entities\n"); qglVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v[0].xyz); if (qglGetError()) Con_Printf("GL Error on entities\n"); while(firstedge) { //border v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[firstedge].v[0]].position; v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[firstedge].v[1]].position; //get positions of v3 and v4 based on the light position v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE; v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE; v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE; if (varray_vc + 4>MAXARRAYVERTS) { qglDrawArrays(GL_QUADS, 0, varray_vc); if (qglGetError()) Con_Printf("GL Error on entities\n"); varray_vc=0; } if (edge[firstedge].count > 0) { varray_v[varray_vc].xyz[0] = v1[0]+v3[0]; varray_v[varray_vc].xyz[1] = v1[1]+v3[1]; varray_v[varray_vc].xyz[2] = v1[2]+v3[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v2[0]+v4[0]; varray_v[varray_vc].xyz[1] = v2[1]+v4[1]; varray_v[varray_vc].xyz[2] = v2[2]+v4[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v2[0]; varray_v[varray_vc].xyz[1] = v2[1]; varray_v[varray_vc].xyz[2] = v2[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v1[0]; varray_v[varray_vc].xyz[1] = v1[1]; varray_v[varray_vc].xyz[2] = v1[2]; varray_vc++; } else { varray_v[varray_vc].xyz[0] = v1[0]; varray_v[varray_vc].xyz[1] = v1[1]; varray_v[varray_vc].xyz[2] = v1[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v2[0]; varray_v[varray_vc].xyz[1] = v2[1]; varray_v[varray_vc].xyz[2] = v2[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v2[0]+v4[0]; varray_v[varray_vc].xyz[1] = v2[1]+v4[1]; varray_v[varray_vc].xyz[2] = v2[2]+v4[2]; varray_vc++; varray_v[varray_vc].xyz[0] = v1[0]+v3[0]; varray_v[varray_vc].xyz[1] = v1[1]+v3[1]; varray_v[varray_vc].xyz[2] = v1[2]+v3[2]; varray_vc++; } edge[firstedge].count=0; firstedge = edge[firstedge].next; shadowedgecount++; } qglDrawArrays(GL_QUADS, 0, varray_vc); if (qglGetError()) Con_Printf("GL Error on entities\n"); varray_vc=0; firstedge=0; PPL_FinishShadowMesh(dl); } void PPL_DrawBrushModelShadow(dlight_t *dl, entity_t *e) { int v; float *v1, *v2; vec3_t v3, v4; int i; model_t *model; msurface_t *surf; RotateLightVector(e->axis, e->origin, dl->origin, lightorg); qglPushMatrix(); R_RotateForEntity(e); model = e->model; surf = model->surfaces+model->firstmodelsurface; for (i = 0; i < model->nummodelsurfaces; i++, surf++) { if (surf->flags & SURF_PLANEBACK) {//inverted normal. if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= -0.1) continue; } else { if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= 0.1) continue; } //#define PROJECTION_DISTANCE (float)0x7fffffff if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED)) { // no shadows continue; } //front face qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array); qglDrawArrays(GL_POLYGON, 0, surf->mesh->numvertexes); for (v = 0; v < surf->mesh->numvertexes; v++) { //border v1 = surf->mesh->xyz_array[v]; v2 = surf->mesh->xyz_array[( v+1 )%surf->mesh->numvertexes]; //get positions of v3 and v4 based on the light position v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE; v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE; v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE; v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE; v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE; v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE; //Now draw the quad from the two verts to the projected light //verts qglBegin( GL_QUAD_STRIP ); qglVertex3fv(v1); qglVertex3f (v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2]); qglVertex3fv(v2); qglVertex3f (v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2]); qglEnd(); } //back //the same applies as earlier qglBegin(GL_POLYGON); for (v = surf->mesh->numvertexes-1; v >=0; v--) { v1 = surf->mesh->xyz_array[v]; v3[0] = (v1[0]-lightorg[0])*PROJECTION_DISTANCE; v3[1] = (v1[1]-lightorg[1])*PROJECTION_DISTANCE; v3[2] = (v1[2]-lightorg[2])*PROJECTION_DISTANCE; qglVertex3f(v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2]); } qglEnd(); } qglPopMatrix(); } void PPL_DrawShadowMeshes(dlight_t *dl) { int i; if (!r_drawentities.value) return; // draw sprites seperately, because of alpha blending for (i=0 ; iflags & Q2RF_WEAPONMODEL) continue; } else { if (currententity->keynum == dl->key) continue; } if (currententity->flags & Q2RF_BEAM) { R_DrawBeam(currententity); continue; } if (!currententity->model) continue; if (cls.allow_anyparticles || currententity->visframe) //allowed or static { if (currententity->model->engineflags & MDLF_ENGULPHS) { if (gl_part_flame.value) continue; } } switch (currententity->model->type) { case mod_alias: R_DrawGAliasShadowVolume (currententity, dl->origin, dl->radius); break; case mod_brush: PPL_DrawBrushModelShadow (dl, currententity); break; default: break; } } } void PPL_UpdateNodeShadowFrames(qbyte *lvis) { int i; mnode_t *node; if (!lvis) //using a cached light, we don't need shadowframes return; #ifdef Q3BSPS if (cl.worldmodel->fromgame == fg_quake3) { mleaf_t *leaf; r_shadowframe++; for (i=0, leaf=cl.worldmodel->leafs; inumleafs ; i++, leaf++) { node = (mnode_t *)leaf; while (node) { if (node->shadowframe == r_shadowframe) break; node->shadowframe = r_shadowframe; node = node->parent; } } } else #endif #ifdef Q2BSPS if (cl.worldmodel->fromgame == fg_quake2) { mleaf_t *leaf; int cluster; r_shadowframe++; for (i=0, leaf=cl.worldmodel->leafs; inumleafs ; i++, leaf++) { cluster = leaf->cluster; if (cluster == -1) continue; if (lvis[cluster>>3] & (1<<(cluster&7))) { node = (mnode_t *)leaf; do { if (node->shadowframe == r_shadowframe) break; node->shadowframe = r_shadowframe; node = node->parent; } while (node); } } } else #endif { if (r_novis.value != 2) { r_shadowframe++; //variation on mark leaves for (i=0 ; inumleafs ; i++) { if (lvis[i>>3] & (1<<(i&7)))// && vvis[i>>3] & (1<<(i&7))) { node = (mnode_t *)&cl.worldmodel->leafs[i+1]; do { if (node->shadowframe == r_shadowframe) break; node->shadowframe = r_shadowframe; node = node->parent; } while (node); } } } } } #if 1 //DP's stolen code static void GL_Scissor (int x, int y, int width, int height) { #if 0 //visible scissors glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho (0, glwidth, glheight, 0, -99999, 99999); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // GL_Set2D(); glColor4f(1,1,1,1); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE ); glDisable(GL_TEXTURE_2D); GL_TexEnv(GL_REPLACE); glBegin(GL_LINE_LOOP); glVertex2f(x, y); glVertex2f(x+glwidth, y); glVertex2f(x+glwidth, y+glheight); glVertex2f(x, y+glheight); glEnd(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); #endif qglScissor(x, glheight - (y + height),width,height); } #define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2]) qboolean PPL_ScissorForBox(vec3_t mins, vec3_t maxs) { int i, ix1, iy1, ix2, iy2; float x1, y1, x2, y2, x, y, f; vec3_t smins, smaxs; vec4_t v, v2; int r_view_x = 0; int r_view_y = 0; int r_view_width = glwidth; int r_view_height = glheight; if (0)//!r_shadow_scissor.integer) { GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height); return false; } // if view is inside the box, just say yes it's visible if (BoxesOverlap(r_refdef.vieworg, r_refdef.vieworg, mins, maxs)) { GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height); return false; } for (i = 0;i < 3;i++) { if (vpn[i] >= 0) { v[i] = mins[i]; v2[i] = maxs[i]; } else { v[i] = maxs[i]; v2[i] = mins[i]; } } f = DotProduct(vpn, r_refdef.vieworg) + 1; if (DotProduct(vpn, v2) <= f) { // entirely behind nearclip plane GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height); return true; } if (DotProduct(vpn, v) >= f) { // entirely infront of nearclip plane x1 = y1 = x2 = y2 = 0; for (i = 0;i < 8;i++) { v[0] = (i & 1) ? mins[0] : maxs[0]; v[1] = (i & 2) ? mins[1] : maxs[1]; v[2] = (i & 4) ? mins[2] : maxs[2]; v[3] = 1.0f; ML_Project(v, v2, r_refdef.viewangles, r_refdef.vieworg, (float)vid.width/vid.height, r_refdef.fov_y); v2[0]*=r_view_width; v2[1]*=r_view_height; // GL_TransformToScreen(v, v2); //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); x = v2[0]; y = v2[1]; if (i) { if (x1 > x) x1 = x; if (x2 < x) x2 = x; if (y1 > y) y1 = y; if (y2 < y) y2 = y; } else { x1 = x2 = x; y1 = y2 = y; } } } else { // clipped by nearclip plane // this is nasty and crude... // create viewspace bbox for (i = 0;i < 8;i++) { v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_refdef.vieworg[0]; v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_refdef.vieworg[1]; v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_refdef.vieworg[2]; v2[0] = DotProduct(v, vright); v2[1] = DotProduct(v, vup); v2[2] = DotProduct(v, vpn); if (i) { if (smins[0] > v2[0]) smins[0] = v2[0]; if (smaxs[0] < v2[0]) smaxs[0] = v2[0]; if (smins[1] > v2[1]) smins[1] = v2[1]; if (smaxs[1] < v2[1]) smaxs[1] = v2[1]; if (smins[2] > v2[2]) smins[2] = v2[2]; if (smaxs[2] < v2[2]) smaxs[2] = v2[2]; } else { smins[0] = smaxs[0] = v2[0]; smins[1] = smaxs[1] = v2[1]; smins[2] = smaxs[2] = v2[2]; } } // now we have a bbox in viewspace // clip it to the view plane if (smins[2] < 1) smins[2] = 1; // return true if that culled the box if (smins[2] >= smaxs[2]) return true; // ok some of it is infront of the view, transform each corner back to // worldspace and then to screenspace and make screen rect // initialize these variables just to avoid compiler warnings x1 = y1 = x2 = y2 = 0; for (i = 0;i < 8;i++) { v2[0] = (i & 1) ? smins[0] : smaxs[0]; v2[1] = (i & 2) ? smins[1] : smaxs[1]; v2[2] = (i & 4) ? smins[2] : smaxs[2]; v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_refdef.vieworg[0]; v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_refdef.vieworg[1]; v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_refdef.vieworg[2]; v[3] = 1.0f; ML_Project(v, v2, r_refdef.viewangles, r_refdef.vieworg, vid.width/vid.height, r_refdef.fov_y); v2[0]*=r_view_width; v2[1]*=r_view_height; // GL_TransformToScreen(v, v2); //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); x = v2[0]; y = v2[1]; if (i) { if (x1 > x) x1 = x; if (x2 < x) x2 = x; if (y1 > y) y1 = y; if (y2 < y) y2 = y; } else { x1 = x2 = x; y1 = y2 = y; } } #if 0 // this code doesn't handle boxes with any points behind view properly x1 = 1000;x2 = -1000; y1 = 1000;y2 = -1000; for (i = 0;i < 8;i++) { v[0] = (i & 1) ? mins[0] : maxs[0]; v[1] = (i & 2) ? mins[1] : maxs[1]; v[2] = (i & 4) ? mins[2] : maxs[2]; v[3] = 1.0f; GL_TransformToScreen(v, v2); v2[0]*=r_view_width; v2[1]*=r_view_height; //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]); if (v2[2] > 0) { x = v2[0]; y = v2[1]; if (x1 > x) x1 = x; if (x2 < x) x2 = x; if (y1 > y) y1 = y; if (y2 < y) y2 = y; } } #endif } ix1 = x1 - 1.0f; iy1 = y1 - 1.0f; ix2 = x2 + 1.0f; iy2 = y2 + 1.0f; //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); if (ix1 < r_view_x) ix1 = r_view_x; if (iy1 < r_view_y) iy1 = r_view_y; if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width; if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height; if (ix2 <= ix1 || iy2 <= iy1) return true; // set up the scissor rectangle qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1); //qglEnable(GL_SCISSOR_TEST); return false; } #endif void CL_NewDlight (int key, float x, float y, float z, float radius, float time, int type); //generates stencil shadows of the world geometry. //redraws world geometry qboolean PPL_AddLight(dlight_t *dl) { int i; int sdecrw; int sincrw; int leaf; qbyte *lvis; qbyte *vvis; vec3_t colour; qbyte lvisb[MAX_MAP_LEAFS/8]; qbyte vvisb[MAX_MAP_LEAFS/8]; vec3_t mins; vec3_t maxs; mins[0] = dl->origin[0] - dl->radius; mins[1] = dl->origin[1] - dl->radius; mins[2] = dl->origin[2] - dl->radius; maxs[0] = dl->origin[0] + dl->radius; maxs[1] = dl->origin[1] + dl->radius; maxs[2] = dl->origin[2] + dl->radius; colour[0] = dl->color[0]; colour[1] = dl->color[1]; colour[2] = dl->color[2]; if (dl->style) { if (cl_lightstyle[dl->style-1].colour & 1) colour[0] *= d_lightstylevalue[dl->style-1]/255.0f; else colour[0] = 0; if (cl_lightstyle[dl->style-1].colour & 2) colour[1] *= d_lightstylevalue[dl->style-1]/255.0f; else colour[1] = 0; if (cl_lightstyle[dl->style-1].colour & 4) colour[2] *= d_lightstylevalue[dl->style-1]/255.0f; else colour[2] = 0; } if (colour[0] < 0.1 && colour[1] < 0.1 && colour[2] < 0.1) return false; //just switch these off. if (PPL_ScissorForBox(mins, maxs)) return false; //was culled. if (dl->worldshadowmesh) { if (!PPL_LeafInView(dl->worldshadowmesh->litleaves)) return false; /* if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) i = cl.worldmodel->funcs.LeafForPoint(r_refdef.vieworg, cl.worldmodel); else i = r_viewleaf - cl.worldmodel->leafs; vvis = cl.worldmodel->funcs.LeafPVS(i, cl.worldmodel, vvisb); // if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be. // return; if (!PPL_VisOverlaps(dl->worldshadowmesh->litleaves, vvis)) //The two viewing areas do not intersect. return; */ lvis = NULL; } else { if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3) i = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, r_refdef.vieworg); else i = r_viewleaf - cl.worldmodel->leafs; leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin); lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb); vvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, i, vvisb); // if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be. // return; if (!PPL_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. return false; } PPL_EnableVertexArrays(); qglDisable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); qglEnable(GL_SCISSOR_TEST); if (!((int)r_shadows.value & 4)) { qglDisable(GL_BLEND); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglDepthMask(0); if (gldepthfunc==GL_LEQUAL) qglDepthFunc(GL_LESS); else qglDepthFunc(GL_GREATER); qglEnable(GL_DEPTH_TEST); qglEnable(GL_STENCIL_TEST); sincrw = GL_INCR; sdecrw = GL_DECR; if (gl_config.ext_stencil_wrap) { //minamlise damage... sincrw = GL_INCR_WRAP_EXT; sdecrw = GL_DECR_WRAP_EXT; } //our stencil writes. #ifdef _DEBUG if (r_shadows.value == 666) //testing (visible shadow volumes) { if (qglGetError()) Con_Printf("GL Error on entities\n"); qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); qglColor3f(dl->color[0], dl->color[1], dl->color[2]); qglDisable(GL_STENCIL_TEST); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (qglGetError()) Con_Printf("GL Error on entities\n"); PPL_RecursiveWorldNode(dl); if (qglGetError()) Con_Printf("GL Error on entities\n"); PPL_DrawShadowMeshes(dl); if (qglGetError()) Con_Printf("GL Error on entities\n"); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else #endif if (qglStencilOpSeparateATI && !((int)r_shadows.value & 2))//GL_ATI_separate_stencil { qglClearStencil(0); qglClear(GL_STENCIL_BUFFER_BIT); qglDisable(GL_CULL_FACE); qglStencilFunc( GL_ALWAYS, 1, ~0 ); qglStencilOpSeparateATI(GL_BACK, GL_KEEP, sincrw, GL_KEEP); qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, sdecrw, GL_KEEP); PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); qglStencilOpSeparateATI(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP); qglEnable(GL_CULL_FACE); qglStencilFunc( GL_EQUAL, 0, ~0 ); } else if (qglActiveStencilFaceEXT && !((int)r_shadows.value & 2)) //NVidias variation on a theme. (GFFX class) { qglClearStencil(0); qglClear(GL_STENCIL_BUFFER_BIT); qglDisable(GL_CULL_FACE); qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); qglActiveStencilFaceEXT(GL_BACK); qglStencilOp(GL_KEEP, sincrw, GL_KEEP); qglStencilFunc( GL_ALWAYS, 1, ~0 ); qglActiveStencilFaceEXT(GL_FRONT); qglStencilOp(GL_KEEP, sdecrw, GL_KEEP); qglStencilFunc( GL_ALWAYS, 1, ~0 ); PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); qglActiveStencilFaceEXT(GL_BACK); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglActiveStencilFaceEXT(GL_FRONT); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); qglEnable(GL_CULL_FACE); qglActiveStencilFaceEXT(GL_BACK); qglStencilFunc( GL_EQUAL, 0, ~0 ); } else //your graphics card sucks and lacks efficient stencil shadow techniques. { //centered around 0. Will only be increased then decreased less. qglClearStencil(0); qglClear(GL_STENCIL_BUFFER_BIT); qglEnable(GL_CULL_FACE); qglStencilFunc( GL_ALWAYS, 0, ~0 ); shadowsurfcount = 0; qglCullFace(GL_BACK); qglStencilOp(GL_KEEP, sincrw, GL_KEEP); PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); shadowsurfcount=0; qglCullFace(GL_FRONT); qglStencilOp(GL_KEEP, sdecrw, GL_KEEP); PPL_UpdateNodeShadowFrames(lvis); PPL_RecursiveWorldNode(dl); PPL_DrawShadowMeshes(dl); qglStencilFunc( GL_EQUAL, 0, ~0 ); } //end stencil writing. qglEnable(GL_DEPTH_TEST); qglDepthMask(0); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); qglCullFace(GL_FRONT); #if 0 //draw the stencil stuff to the red channel /* { #pragma comment(lib, "opengl32.lib"); static char buffer[1024*1024*8]; glReadPixels(0, 0, vid.width, vid.height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer); glDrawPixels(vid.width, vid.height, GL_GREEN, GL_UNSIGNED_BYTE, buffer); } */ qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); GL_Set2D(); qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); qglStencilFunc( GL_GREATER, 1, ~0 ); Draw_ConsoleBackground(480); qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); qglStencilFunc( GL_LESS, 1, ~0 ); Draw_ConsoleBackground(480); qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); #endif qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); } qglColor3f(1,1,1); qglEnable(GL_BLEND); qglBlendFunc(GL_ONE, GL_ONE); qglColor4f(dl->color[0], dl->color[1], dl->color[2], 1); qglDepthFunc(GL_EQUAL); lightorg[0] = dl->origin[0]+0.5; lightorg[1] = dl->origin[1]+0.5; lightorg[2] = dl->origin[2]+0.5; PPL_DrawEntLighting(dl, colour); qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDepthMask(1); qglDepthFunc(gldepthfunc); qglEnable(GL_DEPTH_TEST); qglDisable(GL_STENCIL_TEST); qglStencilFunc( GL_ALWAYS, 0, ~0 ); qglDisable(GL_SCISSOR_TEST); qglDisable(GL_BLEND); GL_TexEnv(GL_REPLACE); return true; } #endif void GL_CheckTMUIs0(void); void PPL_DrawWorld (void) { RSpeedLocals(); dlight_t *l; #if 0 dlight_t *lc, *furthestprev; float furthest; #endif int i; int numlights; vec3_t mins, maxs; int maxshadowlights = gl_maxshadowlights.value; if (!r_shadow_realtime_world.value) r_lightmapintensity = 1; else r_lightmapintensity = r_shadow_realtime_world_lightmaps.value; /* if (!lightmap) { R_PreNewMap(); R_NewMap(); return; // :/ } */ if (maxshadowlights < 1) maxshadowlights = 1; // if (qglGetError()) // Con_Printf("GL Error before world\n"); //glColorMask(0,0,0,0); RSpeedRemark(); TRACE(("dbg: calling PPL_BaseTextures\n")); PPL_BaseTextures(cl.worldmodel); RSpeedEnd(RSPEED_WORLD); // if (qglGetError()) // Con_Printf("GL Error during base textures\n"); //glColorMask(1,1,1,1); RSpeedRemark(); TRACE(("dbg: calling PPL_BaseEntTextures\n")); PPL_BaseEntTextures(); RSpeedEnd(RSPEED_DRAWENTITIES); // CL_NewDlightRGB(1, r_refdef.vieworg[0], r_refdef.vieworg[1]-16, r_refdef.vieworg[2]-24, 128, 1, 1, 1, 1); // if (qglGetError()) // Con_Printf("GL Error on entities\n"); #ifdef PPL numlights = 0; RSpeedRemark(); if (r_shadows.value && qglStencilFunc && gl_canstencil) { if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife || cl.worldmodel->fromgame == fg_quake2 /*|| cl.worldmodel->fromgame == fg_quake3*/) { // lc = NULL; for (l = cl_dlights, i=0 ; iradius || l->noppl) continue; if (l->color[0]<0) continue; //quick check for darklight if (l->isstatic) { if (!r_shadow_realtime_world.value) continue; } mins[0] = l->origin[0] - l->radius; mins[1] = l->origin[1] - l->radius; mins[2] = l->origin[2] - l->radius; maxs[0] = l->origin[0] + l->radius; maxs[1] = l->origin[1] + l->radius; maxs[2] = l->origin[2] + l->radius; if (R_CullBox(mins, maxs)) continue; if (R_CullSphere(l->origin, l->radius)) continue; #if 1 if (maxshadowlights-- <= 0) continue; #else VectorSubtract(l->origin, r_refdef.vieworg, mins) l->dist = Length(mins); VectorNormalize(mins); l->dist*=1-sqrt(DotProduct(vpn, mins)*DotProduct(vpn, mins)); l->next = lc; lc = l; maxshadowlights--; } while (maxshadowlights<0)//ooer... we exceeded our quota... strip the furthest ones out. { furthest = lc->dist; furthestprev=NULL; for (l = lc; l->next; l = l->next) { if (l->next->dist > furthest) { furthest = l->next->dist; furthestprev = l; } } if (furthestprev) furthestprev->next = furthestprev->next->next; else lc = lc->next; maxshadowlights++; } for (l = lc; l; l = l->next) //we now have our quotaed list { #endif if(!l->isstatic) { l->color[0]*=10; l->color[1]*=10; l->color[2]*=10; } TRACE(("dbg: calling PPL_AddLight\n")); if (PPL_AddLight(l)) numlights++; if(!l->isstatic) { l->color[0]/=10; l->color[1]/=10; l->color[2]/=10; } } qglEnable(GL_TEXTURE_2D); } qglDisableClientState(GL_COLOR_ARRAY); } RSpeedEnd(RSPEED_STENCILSHADOWS); #endif // Con_Printf("%i lights\n", numlights); // if (qglGetError()) // Con_Printf("GL Error on shadow lighting\n"); RSpeedRemark(); if (gl_schematics.value) PPL_Schematics(); TRACE(("dbg: calling PPL_DrawEntFullBrights\n")); PPL_DrawEntFullBrights(); RSpeedEnd(RSPEED_FULLBRIGHTS); // if (qglGetError()) // Con_Printf("GL Error on fullbrights/details\n"); // Con_Printf("%i %i(%i) %i\n", shadowsurfcount, shadowedgecount, shadowemittedeges, shadowlightfaces); RQuantAdd(RQUANT_SHADOWFACES, shadowsurfcount); RQuantAdd(RQUANT_SHADOWEDGES, shadowedgecount); RQuantAdd(RQUANT_LITFACES, shadowlightfaces); shadowsurfcount = 0; shadowedgecount = 0; shadowlightfaces = 0; shadowemittedeges = 0; GL_CheckTMUIs0(); R_IBrokeTheArrays(); } void PPL_CreateShaderObjects(void) { #ifdef PPL PPL_CreateLightTexturesProgram(); #endif PPL_LoadSpecularFragmentProgram(); } void PPL_FlushShadowMesh(dlight_t *dl) { int tn; shadowmesh_t *sm; sm = dl->worldshadowmesh; if (sm) { dl->worldshadowmesh = NULL; for (tn = 0; tn < sm->numsurftextures; tn++) if (sm->litsurfs[tn].count) BZ_Free(sm->litsurfs); BZ_Free(sm->indicies); BZ_Free(sm->verts); BZ_Free(sm); } } //okay, so this is a bit of a hack... qboolean buildingmesh; void (APIENTRY *realBegin) (GLenum); void (APIENTRY *realEnd) (void); void (APIENTRY *realVertex3f) (GLfloat x, GLfloat y, GLfloat z); void (APIENTRY *realVertex3fv) (const GLfloat *v); void (APIENTRY *realVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); void (APIENTRY *realDrawArrays) (GLenum mode, GLint first, GLsizei count); void (APIENTRY *realDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); #define inc 128 int sh_type; int sh_index[64*64]; int sh_vertnum; //vertex number (set to 0 at SH_Begin) int sh_maxverts; int sh_numverts; //total emitted int sh_maxindicies; int sh_numindicies; const float *sh_vertexpointer; int sh_vpstride; shadowmesh_t *sh_shmesh; void APIENTRY SH_Begin (GLenum e) { sh_type = e; } void APIENTRY SH_End (void) { int i; int v1, v2; switch(sh_type) { case GL_POLYGON: i = (sh_numindicies+(sh_vertnum-2)*3+inc+5)&~(inc-1); //and a bit of padding if (sh_maxindicies != i) { sh_maxindicies = i; sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); } //decompose the poly into a triangle fan. v1 = sh_index[0]; v2 = sh_index[1]; for (i = 2; i < sh_vertnum; i++) { sh_shmesh->indicies[sh_numindicies++] = v1; sh_shmesh->indicies[sh_numindicies++] = v2; sh_shmesh->indicies[sh_numindicies++] = v2 = sh_index[i]; } sh_vertnum = 0; break; case GL_TRIANGLES: i = (sh_numindicies+(sh_vertnum)+inc+5)&~(inc-1); //and a bit of padding if (sh_maxindicies != i) { sh_maxindicies = i; sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); } //add the extra triangles for (i = 0; i < sh_vertnum; i+=3) { sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; } sh_vertnum = 0; break; case GL_QUADS: i = (sh_numindicies+(sh_vertnum/4)*6+inc+5)&~(inc-1); //and a bit of padding if (sh_maxindicies != i) { sh_maxindicies = i; sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies)); } //add the extra triangles for (i = 0; i < sh_vertnum; i+=4) { sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2]; sh_shmesh->indicies[sh_numindicies++] = sh_index[i+3]; } sh_vertnum = 0; break; default: if (sh_vertnum) Sys_Error("SH_End: verticies were left"); } } void APIENTRY SH_Vertex3f (GLfloat x, GLfloat y, GLfloat z) { int i; if (sh_vertnum > sizeof(sh_index)/sizeof(sh_index[0])) Sys_Error("SH_End: too many verticies"); //add the verts as we go i = (sh_numverts+inc+5)&~(inc-1); //and a bit of padding if (sh_maxverts != i) { sh_maxverts = i; sh_shmesh->verts = BZ_Realloc(sh_shmesh->verts, i * sizeof(*sh_shmesh->verts)); } sh_shmesh->verts[sh_numverts][0] = x; sh_shmesh->verts[sh_numverts][1] = y; sh_shmesh->verts[sh_numverts][2] = z; sh_index[sh_vertnum] = sh_numverts; sh_vertnum++; sh_numverts++; switch(sh_type) { case GL_POLYGON: break; case GL_TRIANGLES: if (sh_vertnum == 3) SH_End(); break; case GL_QUADS: if (sh_vertnum == 4) SH_End(); break; default: Sys_Error("SH_Vertex3f: bad type"); } } void APIENTRY SH_Vertex3fv (const GLfloat *v) { SH_Vertex3f(v[0], v[1], v[2]); } void APIENTRY SH_VertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { sh_vertexpointer = pointer; sh_vpstride = stride/4; if (!sh_vpstride) sh_vpstride = 3; } void APIENTRY SH_DrawArrays (GLenum mode, GLint first, GLsizei count) { int i; SH_Begin(mode); count+=first; for (i = first; i < count; i++) SH_Vertex3fv(sh_vertexpointer + i*sh_vpstride); SH_End(); } void APIENTRY SH_DrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { int i; SH_Begin(mode); for (i = 0; i < count; i++) SH_Vertex3fv(sh_vertexpointer + (((int*)indices)[i])*sh_vpstride); SH_End(); } void PPL_Shadow_Cache_Surface(msurface_t *surf) { int i; if (!buildingmesh) return; for (i = 0; i < cl.worldmodel->numtextures; i++) if (surf->texinfo->texture == cl.worldmodel->textures[i]) break; sh_shmesh->litsurfs[i].s = BZ_Realloc(sh_shmesh->litsurfs[i].s, sizeof(void*)*(sh_shmesh->litsurfs[i].count+1)); sh_shmesh->litsurfs[i].s[sh_shmesh->litsurfs[i].count] = surf; sh_shmesh->litsurfs[i].count++; } void PPL_Shadow_Cache_Leaf(mleaf_t *leaf) { int i; if (!buildingmesh) return; i = leaf - cl.worldmodel->leafs; sh_shmesh->litleaves[i>>3] = 1<<(i&7); } void PPL_BeginShadowMesh(dlight_t *dl) { PPL_FlushShadowMesh(dl); if (buildingmesh) return; if (!dl->isstatic) return; sh_maxverts = 0; sh_numverts = 0; sh_vertnum = 0; sh_maxindicies = 0; sh_numindicies = 0; buildingmesh = true; realBegin = qglBegin; realEnd = qglEnd; realVertex3f = qglVertex3f; realVertex3fv = qglVertex3fv; realVertexPointer = qglVertexPointer; realDrawArrays = qglDrawArrays; realDrawElements = qglDrawElements; qglBegin = SH_Begin; qglEnd = SH_End; qglVertex3f = SH_Vertex3f; qglVertex3fv = SH_Vertex3fv; qglVertexPointer = SH_VertexPointer; qglDrawArrays = SH_DrawArrays; qglDrawElements = SH_DrawElements; sh_shmesh = Z_Malloc(sizeof(*sh_shmesh) + (cl.worldmodel->numleafs+7)/8); sh_shmesh->litsurfs = Z_Malloc(sizeof(shadowmeshsurfs_t)*cl.worldmodel->numtextures); sh_shmesh->numsurftextures=cl.worldmodel->numtextures; sh_shmesh->litleaves = (unsigned char*)(sh_shmesh+1); } void PPL_FinishShadowMesh(dlight_t *dl) { if (!buildingmesh) return; qglBegin = realBegin; qglEnd = realEnd; qglVertex3f = realVertex3f; qglVertex3fv = realVertex3fv; qglVertexPointer = realVertexPointer; qglDrawArrays = realDrawArrays; qglDrawElements = realDrawElements; buildingmesh = false; dl->worldshadowmesh = sh_shmesh; sh_shmesh->numindicies = sh_numindicies; sh_shmesh->numverts = sh_numverts; sh_shmesh = NULL; } #endif //ifdef GLQUAKE