/* Copyright (C) 2001-2002 Charles Hollemeersch This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. PENTA: the whole file is freakin penta... All code conserning the drawing of bump mapped polygons. Per vertex setup, shaders and the passes. This is the general/gf2 approach for the gf3 code see gumpgf.c */ #include "quakedef.h" //view origin in object space vec3_t object_vieworg; /************************************************************** PART1: Gl state management ***************************************************************/ void GL_EnableDiffuseShader () { //ordinary combiners = compatible with everything //texture coords for unit 0: Tangent space light vector //texture coords for unit 1: Normal map texture coords GL_SelectTexture(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); GL_EnableMultitexture(); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB); } void GL_DisableDiffuseShader () { GL_DisableMultitexture(); glEnable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP_ARB); } void GL_EnableSpecularShader () { vec3_t scaler = {0.75f, 0.75f, 0.75f}; if ( gl_cardtype == GEFORCE || gl_cardtype == GEFORCE3 ) { GL_SelectTexture(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_CUBE_MAP_ARB); //GL_Bind(normcube_texture_object); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object); GL_EnableMultitexture(); //setup and enable the register combiners qglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 2); qglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &scaler[0]); //combiner0 RGB: calculate N'dotH -> store in Spare0 RGB qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE); //combiner0 Alpha: ignore all qglCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner1 RGB: ignore all qglCombinerOutputNV(GL_COMBINER1_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner1 Alpha: calculate 4*((N'dotH)^2 - 0.75f) -> store in Spare0 Alpha qglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_CONSTANT_COLOR0_NV, GL_SIGNED_NEGATE_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); qglCombinerOutputNV(GL_COMBINER1_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //final combiner RGB: who cares // Alpha: specular value of 4*((N'dotH)^2 - 0.75f) qglFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); glEnable(GL_REGISTER_COMBINERS_NV); } else { GL_EnableDiffuseShader (); } } void GL_DisableSpecularShader () { //not supported? if ( gl_cardtype == GEFORCE || gl_cardtype == GEFORCE3 ) { GL_DisableMultitexture(); glDisable(GL_REGISTER_COMBINERS_NV); glEnable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP_ARB); } else { GL_DisableDiffuseShader (); } } void GL_EnableColorShader (qboolean specular) { //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //primary color = light color //tu0 = light filter cube map //tu1 = material color map GL_SelectTexture(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_CUBE_MAP_ARB); GL_SelectTexture(GL_TEXTURE0_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, currentshadowlight->filtercube); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); if (!specular) { GL_EnableMultitexture(); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); } else { GL_EnableMultitexture(); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA); glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); } } void GL_DisableColorShader (qboolean specular) { if (!specular) { GL_DisableMultitexture(); } else { glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); GL_DisableMultitexture(); } glEnable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_CUBE_MAP_ARB); } void GL_EnableAttShader() { GL_Bind(glow_texture_object); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } void GL_DisableAttShader() { //empty glDisable(GL_REGISTER_COMBINERS_NV); } /* Draw incoming fragment to destination alpha. Note: A fragment in the next comment means a pixel that will be drawn on the screen (gl has some specific definition of it) */ void GL_DrawAlpha() { glColorMask(false, false, false, true); glDisable(GL_BLEND); } /* Draw incoming fragment by modulating it with destination alpha */ void GL_ModulateAlphaDrawAlpha() { glColorMask(false, false, false, true); glBlendFunc (GL_DST_ALPHA, GL_ZERO); glEnable (GL_BLEND); } /* Draw incoming fragment by adding it to destination alpha */ void GL_AddAlphaDrawAlpha() { glColorMask(false, false, false, true); glBlendFunc (GL_ONE, GL_ONE); glEnable (GL_BLEND); } /* Draw incoming fragment by modulation it with destination alpha */ void GL_ModulateAlphaDrawColor() { glColorMask(true, true, true, true); glBlendFunc (GL_DST_ALPHA, GL_ONE); glEnable (GL_BLEND); } /* Draw incoming alpha squared to destination alpha */ void GL_DrawSquareAlpha() { glColorMask(false, false, false, true); glBlendFunc (GL_SRC_ALPHA, GL_ZERO); glEnable (GL_BLEND); } /* Square the destination alpha */ void GL_SquareAlpha() { glColorMask(false, false, false, true); glBlendFunc (GL_ZERO, GL_DST_ALPHA); glEnable (GL_BLEND); } /* Add incoming fragment to destination color */ void GL_AddColor() { glColorMask(true, true, true, true); glBlendFunc (GL_ONE, GL_ONE); glEnable (GL_BLEND); } /* Ovewrite destination color with incoming fragment */ void GL_DrawColor() { glColorMask(true, true, true, true); glDisable (GL_BLEND); } /* ================= R_WorldToObjectMatrix Returns a world to object coordinate transformation matrix. This is crap and I know it ;) The problem is that quake does strange stuff with its angles (look at R_RotateForEntity) so inverting the matrix will certainly give the desired result. Why I use the gl matrix? Well quake doesn't have build in matix routines an I don't have any lying around in c (Lot's in Pascal of course i'm a Delphi man) ================= */ void R_WorldToObjectMatrix(entity_t *e, matrix_4x4 result) { matrix_4x4 world; glPushMatrix(); glLoadIdentity(); R_RotateForEntity (e); glGetFloatv (GL_MODELVIEW_MATRIX, &world[0][0]); glPopMatrix(); MatrixAffineInverse(world,result); } /* ============= GL_SetupCubeMapMatrix Loads the current matrix with a tranformation used for light filters ============= */ void GL_SetupCubeMapMatrix(const transform_t *tr) { glLoadIdentity(); glRotatef (-currentshadowlight->angles[0], 1, 0, 0); glRotatef (-currentshadowlight->angles[1], 0, 1, 0); glRotatef (-currentshadowlight->angles[2], 0, 0, 1); glRotatef (currentshadowlight->rspeed*cl.time,0,0,1); glTranslatef(-currentshadowlight->origin[0], -currentshadowlight->origin[1], -currentshadowlight->origin[2]); //if (!world) // R_RotateForEntity(currententity); glTranslatef (tr->origin[0], tr->origin[1], tr->origin[2]); glRotatef (tr->angles[1], 0, 0, 1); glRotatef (-tr->angles[0], 0, 1, 0); glRotatef (tr->angles[2], 1, 0, 0); } /************************************************************** PART2: Geommety sending code This parts containts code for sending different geommety types (brushes, alias, ...) with different per vertex options (light, H, att) Every method is the core of 1 pass during bump map rendering. This is all direct mode stuff, it should be put in vertex arrays. ***************************************************************/ /* ============= R_DrawWorldLLV -Draws the world sending the tangent space light vector as unit 0's texture coordinates. -Sends as uni1t's texture coordinates the original texture coordinates. -Rebinds unit1's texture if the surface material changes (binds the current surface's bump map) ============= */ void R_DrawWorldLLV(lightcmd_t *lightCmds) { int command, num, i; int lightPos = 0; vec3_t lightOr; msurface_t *surf; float *v; shader_t *s;//XYZ //support flickering lights VectorCopy(currentshadowlight->origin,lightOr); while (1) { command = lightCmds[lightPos++].asInt; if (command == 0) break; //end of list surf = lightCmds[lightPos++].asVoid; if (surf->visframe != r_framecount) { lightPos+=(4+surf->polys->numverts*(2+3)); continue; } num = surf->polys->numverts; lightPos+=4;//skip color //XYZ s = surf->shader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glBegin(command); //v = surf->polys->verts[0]; v = (float *)(&globalVertexTable[surf->polys->firstvertex]); for (i=0; ivertexes[ind].position,lightDir); if (surf->flags & SURF_PLANEBACK) { tsLightDir[2] = -DotProduct(lightDir,surf->plane->normal); } else { tsLightDir[2] = DotProduct(lightDir,surf->plane->normal); } tsLightDir[1] = -DotProduct(lightDir,surf->texinfo->vecs[1]); tsLightDir[0] = DotProduct(lightDir,surf->texinfo->vecs[0]); glTexCoord3fv(&tsLightDir[0]); */ glTexCoord3fv(&lightCmds[lightPos].asFloat); lightPos+=3; qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(&v[0]); } glEnd(); } } /* ============= R_DrawWorldHAV -Draws the world sending the tangent space half angle vector as unit 0's texture coordinates. -Sends as uni1t's texture coordinates the original texture coordinates. -Rebinds unit1's texture if the surface material changes (binds the current surface's bump map) ============= */ void R_DrawWorldHAV(lightcmd_t *lightCmds) { int command, num, i; int lightPos = 0; vec3_t lightOr,tsH,H; msurface_t *surf; float *v,*lightP; vec3_t lightDir; shader_t *s;//XYZ //support flickering lights VectorCopy(currentshadowlight->origin,lightOr); while (1) { command = lightCmds[lightPos++].asInt; if (command == 0) break; //end of list surf = lightCmds[lightPos++].asVoid; if (surf->visframe != r_framecount) { lightPos+=(4+surf->polys->numverts*(2+3)); continue; } num = surf->polys->numverts; lightPos+=4;//skip color //XYZ s = surf->shader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glBegin(command); //v = surf->polys->verts[0]; v = (float *)(&globalVertexTable[surf->polys->firstvertex]); for (i=0; iflags & SURF_PLANEBACK) { tsH[2] = -DotProduct(H,surf->plane->normal); } else { tsH[2] = DotProduct(H,surf->plane->normal); } tsH[1] = -DotProduct(H,surf->binormal); tsH[0] = DotProduct(H,surf->tangent); VectorAdd(lightDir,tsH,tsH); glTexCoord3fv(&tsH[0]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(&v[0]); } glEnd(); } } /* ============= R_DrawWorldATT Draw the world sending as texture unit 0's texture coordinates the precalcuated attenuation coordinates. As primary color the light color modulated by the current brightness (for flickering lights this depends on t) ============= */ void R_DrawWorldATT(lightcmd_t *lightCmds) { int command, num, i; int lightPos = 0; //edit: modulation of light maps msurface_t *surf; float *v; //support flickering lights float b = d_lightstylevalue[currentshadowlight->style]/255.0; while (1) { command = lightCmds[lightPos++].asInt; if (command == 0) break; //end of list //edit: modulation of light maps surf = lightCmds[lightPos++].asVoid; if (surf->visframe != r_framecount) { lightPos+=(4+surf->polys->numverts*(2+3)); continue; } num = surf->polys->numverts; //v = surf->polys->verts[0]; v = (float *)(&globalVertexTable[surf->polys->firstvertex]); glColor4f( (&lightCmds[lightPos].asFloat)[0] *b, (&lightCmds[lightPos].asFloat)[1] *b, (&lightCmds[lightPos].asFloat)[2] *b, (&lightCmds[lightPos].asFloat)[3] *b ); lightPos+=4; glBegin(command); for (i=0; ivisframe != r_framecount) { lightPos+=(4+surf->polys->numverts*(2+3)); continue; } num = surf->polys->numverts; //v = surf->polys->verts[0]; v = (float *)(&globalVertexTable[surf->polys->firstvertex]); //XYZ s = surf->shader->shader; if ( specular ) if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); else if (s->numcolorstages > 0) GL_Bind(s->colorstages[0].texture[0]->texnum); lightPos+=4;//no attent color glBegin(command); for (i=0; imodel; msurface_t *surf; glpoly_t *poly; int i, j, count; brushlightinstant_t *ins = e->brushlightinstant; float *v; shader_t *s; count = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //XYZ s = surf->shader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { glTexCoord3fv(&ins->tslights[count+j][0]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } /* ============= R_DrawBrushHAV -Draws the brush sending the tangent space half angle vector as unit 0's texture coordinates. -Sends as uni1t's texture coordinates the original texture coordinates. -Rebinds unit1's texture if the surface material changes (binds the current surface's bump map) ============= */ void R_DrawBrushHAV(entity_t *e) { model_t *model = e->model; msurface_t *surf; glpoly_t *poly; int i, j, count; brushlightinstant_t *ins = e->brushlightinstant; float *v; shader_t *s;//XYZ count = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //XYZ s = surf->shader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { glTexCoord3fv(&ins->tshalfangles[count+j][0]); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } /* ============= R_DrawBrushATT Draw the brush sending as texture unit 0's texture coordinates the calcuated attentuation coordinates. As primary color the light color modulated by the current brightness (for flickering lights this depends on t) ============= */ void R_DrawBrushATT(entity_t *e) { model_t *model = e->model; msurface_t *surf; glpoly_t *poly; int i, j, count, countc; brushlightinstant_t *ins = e->brushlightinstant; float *v, bright; count = 0; countc = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //GL_Bind(surf->texinfo->texture->gl_texturenum); bright = ins->colorscales[countc]; countc++; glColor4f(bright,bright,bright,bright); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { glTexCoord2fv(&ins->atencoords[count+j][0]); //qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } /* ============= R_DrawBrushWV ============= */ void R_DrawBrushWV(entity_t *e, qboolean specular) { model_t *model = e->model; msurface_t *surf; glpoly_t *poly; int i, j, count; brushlightinstant_t *ins = e->brushlightinstant; float *v; shader_t *s; count = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //XYZ s = surf->shader->shader; if ( specular ) if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); else if (s->numcolorstages > 0) GL_Bind(s->colorstages[0].texture[0]->texnum); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { glTexCoord3fv(v); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, v[3], v[4]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } /* ============= R_DrawBrushObjectLight Idea: Creepy object oriented programming by using function pointers. Function: Puts the light into object space, adapts the world->eye matrix and calls BrushGeoSender if all that has been done. Cleans up afterwards so nothing has changed. ============= */ void R_DrawBrushObjectLight(entity_t *e,void (*BrushGeoSender) (entity_t *e)) { model_t *clmodel; vec3_t oldlightorigin; //backup light origin since we will have to translate //light into model space VectorCopy (currentshadowlight->origin, oldlightorigin); currententity = e; currenttexture = -1; clmodel = e->model; glPushMatrix (); e->angles[0] = -e->angles[0]; // stupid quake bug R_RotateForEntity (e); e->angles[0] = -e->angles[0]; // stupid quake bug VectorCopy(((brushlightinstant_t *)e->brushlightinstant)->lightpos,currentshadowlight->origin); BrushGeoSender(e); VectorCopy(oldlightorigin,currentshadowlight->origin); glPopMatrix (); } void R_DrawAliasFrameLLV (aliashdr_t *paliashdr, aliasframeinstant_t *instant) { fstvert_t *texcoords; int *indecies, anim; aliaslightinstant_t *linstant = instant->lightinstant; shader_t *s; texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords); indecies = (int *)((byte *)paliashdr + paliashdr->indecies); //bind normal map anim = (int)(cl.time*10) & 3; s = pheader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glVertexPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_VERTEX_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(3, GL_FLOAT, 0, linstant->tslights); glEnableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawElements(GL_TRIANGLES,linstant->numtris*3,GL_UNSIGNED_INT,&linstant->indecies[0]); if (sh_noshadowpopping.value) { glStencilFunc(GL_LEQUAL, 1, 0xffffffff); glDrawElements(GL_TRIANGLES,(paliashdr->numtris*3)-(linstant->numtris*3),GL_UNSIGNED_INT,&linstant->indecies[linstant->numtris*3]); glStencilFunc(GL_EQUAL, 0, 0xffffffff); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void R_DrawAliasFrameHAV (aliashdr_t *paliashdr, aliasframeinstant_t *instant) { fstvert_t *texcoords; int *indecies, anim; aliaslightinstant_t *linstant = instant->lightinstant; shader_t *s; texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords); indecies = (int *)((byte *)paliashdr + paliashdr->indecies); //bind normal map anim = (int)(cl.time*10) & 3; s = pheader->shader; if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); glVertexPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_VERTEX_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(3, GL_FLOAT, 0, linstant->tshalfangles); glEnableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawElements(GL_TRIANGLES,linstant->numtris*3,GL_UNSIGNED_INT,&linstant->indecies[0]); if (sh_noshadowpopping.value) { glStencilFunc(GL_LEQUAL, 1, 0xffffffff); glDrawElements(GL_TRIANGLES,(paliashdr->numtris*3)-(linstant->numtris*3),GL_UNSIGNED_INT,&linstant->indecies[linstant->numtris*3]); glStencilFunc(GL_EQUAL, 0, 0xffffffff); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } /* ============= R_DrawAliasFrameWV Draw an alias model with the ojbect space vertex coordinates as texture coords ============= */ void R_DrawAliasFrameWV (aliashdr_t *paliashdr, aliasframeinstant_t *instant, qboolean specular) { int *indecies, anim; fstvert_t *texcoords; aliaslightinstant_t *linstant = instant->lightinstant; shader_t *s; texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords); indecies = (int *)((byte *)paliashdr + paliashdr->indecies); anim = (int)(cl.time*10) & 3; s = pheader->shader; if ( specular ) if (s->numbumpstages > 0) GL_Bind(s->bumpstages[0].texture[0]->texnum); else if (s->numcolorstages > 0) GL_Bind(s->colorstages[0].texture[0]->texnum); glVertexPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_VERTEX_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if ( gl_cardtype == GENERIC || gl_cardtype == GEFORCE ) {//PA: qglClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glNormalPointer(GL_FLOAT, 0, instant->normals); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_FLOAT, 0, linstant->colors); } glDrawElements(GL_TRIANGLES,linstant->numtris*3,GL_UNSIGNED_INT,&linstant->indecies[0]); if (sh_noshadowpopping.value) { glStencilFunc(GL_LEQUAL, 1, 0xffffffff); glDrawElements(GL_TRIANGLES,(paliashdr->numtris*3)-(linstant->numtris*3),GL_UNSIGNED_INT,&linstant->indecies[linstant->numtris*3]); glStencilFunc(GL_EQUAL, 0, 0xffffffff); } if ( gl_cardtype == GENERIC || gl_cardtype == GEFORCE ) {//PA: glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } qglClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void PrintScreenPos(vec3_t v) { double Dproject_matrix[16]; double Dworld_matrix[16]; GLint Iviewport[4]; // changed from int to GLint. double px, py, pz; glGetDoublev (GL_MODELVIEW_MATRIX, Dworld_matrix); glGetDoublev (GL_PROJECTION_MATRIX, Dproject_matrix); glGetIntegerv (GL_VIEWPORT, Iviewport); gluProject(v[0], v[1], v[2], Dworld_matrix, Dproject_matrix, Iviewport, &px, &py, &pz); Con_Printf("Pos: %f %f %f\n", px, py, pz); } /* ================= R_DrawAliasObjectLight Same as R_DrawBrushObjectLight but with alias models ================= */ void R_DrawAliasObjectLight(entity_t *e,void (*AliasGeoSender) (aliashdr_t *paliashdr, aliasframeinstant_t* instant)) { int pose, numposes; //matrix_4x4 transf; //float org[4],res[4]; aliashdr_t *paliashdr; alias3data_t *data; vec3_t oldlightpos, oldvieworg; aliasframeinstant_t *aliasframeinstant; int i,maxnumsurf; currententity = e; // VectorCopy (currententity->origin, r_entorigin); // VectorSubtract (r_origin, r_entorigin, modelorg); glPushMatrix (); R_RotateForEntity (e); // // locate the proper data // data = (alias3data_t *)Mod_Extradata (e->model); maxnumsurf = data->numSurfaces; aliasframeinstant = e->aliasframeinstant; for (i=0;iofsSurfaces[i]); if (!aliasframeinstant) { glPopMatrix(); Con_Printf("R_DrawAliasObjectLight: missing instant for ent %s\n", e->model->name); return; } if (aliasframeinstant->shadowonly) continue; if ((e->frame >= paliashdr->numframes) || (e->frame < 0)) { glPopMatrix(); return; } VectorCopy(currentshadowlight->origin,oldlightpos); VectorCopy(currentshadowlight->origin,currentshadowlight->oldlightorigin); VectorCopy( r_refdef.vieworg,oldvieworg); VectorCopy( aliasframeinstant->lightinstant->vieworg, r_refdef.vieworg); VectorCopy(aliasframeinstant->lightinstant->lightpos ,currentshadowlight->origin); pose = paliashdr->frames[e->frame].firstpose; numposes = paliashdr->frames[e->frame].numposes; //Draw it! AliasGeoSender(paliashdr,aliasframeinstant); aliasframeinstant = aliasframeinstant->_next; VectorCopy(oldvieworg, r_refdef.vieworg); VectorCopy(oldlightpos,currentshadowlight->origin); } /* for paliashdr */ glPopMatrix(); } /* ================= R_DrawSpriteModelWV Draw a sprite texture with as tex0 coordinates the world space position of it's vertexes. tex1 is the sprites texture coordinates. ================= */ void R_DrawSpriteModelWV (entity_t *e) { vec3_t point; mspriteframe_t *frame; float *up, *right; vec3_t v_forward, v_right, v_up; msprite_t *psprite; frame = R_GetSpriteFrame (e); psprite = currententity->model->cache.data; if (psprite->type == SPR_ORIENTED) { // bullet marks on walls PENTA: bulltet marks in quake 1? never seen one ;) AngleVectors (currententity->angles, v_forward, v_right, v_up); up = v_up; right = v_right; } else { // normal sprite up = vup; right = vright; } GL_Bind(frame->gl_texturenum); glBegin (GL_QUADS); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1); VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->left, right, point); glTexCoord3fv(point); glVertex3fv (point); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0); VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->left, right, point); glTexCoord3fv(point); glVertex3fv (point); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 0); VectorMA (e->origin, frame->up, up, point); VectorMA (point, frame->right, right, point); glTexCoord3fv(point); glVertex3fv (point); qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 1); VectorMA (e->origin, frame->down, up, point); VectorMA (point, frame->right, right, point); glTexCoord3fv(point); glVertex3fv (point); glEnd (); } /************************************************************** PART3: Abstraction ***************************************************************/ /* ============= GL_DrawWorldBumped Draws the world bumped how this is done you don't have to know! ============= */ void R_DrawWorldBumpedGF() { if (!currentshadowlight->visible) return; glDepthMask (0); glShadeModel (GL_SMOOTH); /* if (gl_geforce3) { if (currentshadowlight->filtercube) { //draw attent into dest alpha GL_DrawAlpha(); GL_EnableAttentShaderGF3(NULL); R_DrawWorldWV(currentshadowlight->lightCmds); GL_DisableAttentShaderGF3(); GL_ModulateAlphaDrawColor(); } else { GL_AddColor(); } glColor3fv(¤tshadowlight->color[0]); GL_EnableDiffuseShaderGF3(true,currentshadowlight->origin); R_DrawWorldGF3Diffuse(currentshadowlight->lightCmds); GL_DisableDiffuseShaderGF3(); GL_EnableSpecularShaderGF3(true,currentshadowlight->origin); R_DrawWorldGF3Specular(currentshadowlight->lightCmds); GL_DisableDiffuseShaderGF3(); glColor3f (1,1,1); glDisable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask (1); return; } */ // Diffuse bump mapping GL_DrawAlpha(); GL_EnableDiffuseShader (); if (!currentshadowlight->isStatic) { R_DrawWorldLLV(&lightCmdsBuff[0]); } else { R_DrawWorldLLV(currentshadowlight->lightCmds); } GL_DisableDiffuseShader (); // Attenuation GL_ModulateAlphaDrawAlpha(); GL_EnableAttShader(); R_DrawWorldATT(currentshadowlight->lightCmds); GL_DisableAttShader(); // Color map/light filter glMatrixMode(GL_TEXTURE); glPushMatrix(); GL_SetupCubeMapMatrix(true); GL_ModulateAlphaDrawColor(); glColor3fv(¤tshadowlight->baseColor[0]); GL_EnableColorShader (false); R_DrawWorldWV(currentshadowlight->lightCmds, false); GL_DisableColorShader (false); glPopMatrix(); // Specular if ( gl_cardtype == GEFORCE || gl_cardtype == GEFORCE3 ) GL_DrawAlpha(); else GL_DrawSquareAlpha(); GL_EnableSpecularShader (); R_DrawWorldHAV(currentshadowlight->lightCmds); GL_DisableSpecularShader (); if ( gl_cardtype == GENERIC ) { int i; //raise specular to a high exponent my multiplying it a few times //this is evidently slow and we should use a better system for it GL_SquareAlpha(); for (i=0; i<3; i++) { //why draw world att?: 1) I dont want to write new code for this // 2) It uses the least bandwith/ setup R_DrawWorldATT (currentshadowlight->lightCmds); } } // Attenttuation GL_ModulateAlphaDrawAlpha(); GL_EnableAttShader(); R_DrawWorldATT(currentshadowlight->lightCmds); GL_DisableAttShader(); // Color map/light filter glPushMatrix(); GL_SetupCubeMapMatrix(true); GL_ModulateAlphaDrawColor(); glColor3fv(¤tshadowlight->baseColor[0]); GL_EnableColorShader (true); R_DrawWorldWV(currentshadowlight->lightCmds, true); GL_DisableColorShader (true); // End separate specular glPopMatrix(); glMatrixMode(GL_MODELVIEW); glColor3f (1,1,1); glDisable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask (1); } void R_DrawWorldBumpedGEN() { R_DrawWorldBumpedGF(); } /* ============= GL_DrawBrushBumped Draw a brush entity with bump maps ============= *//* void R_DrawBrushBumped(entity_t *e) { // Diffuse bump mapping GL_DrawAlpha(); GL_EnableDiffuseShader (); R_DrawBrushLLV(e); GL_DisableDiffuseShader (); // Attenttuation GL_ModulateAlphaDrawAlpha(); GL_EnableAttShader(); R_DrawBrushATT(e); GL_DisableAttShader(); // Color map/light filter glMatrixMode(GL_TEXTURE); glPushMatrix(); GL_SetupCubeMapMatrix(false); GL_ModulateAlphaDrawColor(); glColor3fv(¤tshadowlight->baseColor[0]); GL_EnableColorShader (false); R_DrawBrushWV(e, false); GL_DisableColorShader (false); glPopMatrix(); glMatrixMode(GL_MODELVIEW); // Specular bump mapping if ( gl_cardtype == GEFORCE || gl_cardtype == GEFORCE3 ) GL_DrawAlpha(); else GL_DrawSquareAlpha(); GL_EnableSpecularShader (); R_DrawBrushHAV(e); GL_DisableSpecularShader (); if ( gl_cardtype == GENERIC ) { int i; GL_SquareAlpha(); //Why R_DrawBrushWV?: Same as for world but not WV is better for (i=0; i<3; i++) R_DrawBrushWV(e, false); } // Attenttuation GL_ModulateAlphaDrawAlpha(); GL_EnableAttShader(); R_DrawBrushATT(e); GL_DisableAttShader(); // Color map/light filter glMatrixMode(GL_TEXTURE); glPushMatrix(); GL_SetupCubeMapMatrix(false); GL_ModulateAlphaDrawColor(); glColor3fv(¤tshadowlight->baseColor[0]); GL_EnableColorShader (true); R_DrawBrushWV(e, true); GL_DisableColorShader (true); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } */ /* ============= R_DrawAliasBumped Draw a alias entity with bump maps ============= *//* void R_DrawAliasBumped(aliashdr_t *paliashdr, aliasframeinstant_t *instant) { //Diffuse bump mapping GL_DrawAlpha(); GL_EnableDiffuseShader (); R_DrawAliasFrameLLV(paliashdr,instant); GL_DisableDiffuseShader (); // Color map/light filter glMatrixMode(GL_TEXTURE); glPushMatrix(); GL_SetupCubeMapMatrix(false); GL_ModulateAlphaDrawColor(); glEnable(GL_LIGHTING); GL_EnableColorShader (false); R_DrawAliasFrameWV(paliashdr,instant, false); GL_DisableColorShader (false); glDisable(GL_LIGHTING); glPopMatrix(); glMatrixMode(GL_MODELVIEW); //Specular bump mapping if ( gl_cardtype == GEFORCE ) GL_DrawAlpha(); else GL_DrawSquareAlpha(); GL_EnableSpecularShader (); R_DrawAliasFrameHAV(paliashdr,instant); GL_DisableSpecularShader (); if ( gl_cardtype == GENERIC ) { int i; GL_SquareAlpha(); for (i=0; i<3; i++) R_DrawAliasFrameWV(paliashdr,instant, false); } // Color map/light filter glMatrixMode(GL_TEXTURE); glPushMatrix(); GL_SetupCubeMapMatrix(false); GL_ModulateAlphaDrawColor(); glEnable(GL_LIGHTING); GL_EnableColorShader (true); R_DrawAliasFrameWV(paliashdr,instant, true); GL_DisableColorShader (true); glDisable(GL_LIGHTING); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } */