/* 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... Same as gl_bumpmap.c but geforce3&4 optimized These routines require 4 texture units an some need nvidia shaders Most lights reqire 2 passes this way 1 diffuse 2 specular If a light has a cubemap filter it requires 3 passes 1 attenuation 2 diffuse 3 specular */ #include "quakedef.h" // "diffuse_program_object" has to be defined static. Otherwise nameclash with "gl_bumpradeon.c". static GLuint diffuse_program_object; static GLuint specularalias_program_object; //He he nice name to type a lot /* Pixel shader for diffuse bump mapping does diffuse bumpmapping with norm cube, self shadowing & dist attent in 1 pass (thanx to the 4 texture units on a gf4) */ void GL_EnableDiffuseShaderGF3(qboolean world, vec3_t lightOrig) { float invrad = 1/currentshadowlight->radius; //tex 0 = normal map //tex 1 = nomalization cube map (tangent space light vector) //tex 2 = color map //tex 3 = (attenuation or light filter, depends on light settings but the actual // register combiner setup does not change only the bound texture) GL_SelectTexture(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object); GL_SelectTexture(GL_TEXTURE2_ARB); glEnable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE3_ARB); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); if (currentshadowlight->filtercube) { glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, currentshadowlight->filtercube); GL_SetupCubeMapMatrix(world); } else { glEnable(GL_TEXTURE_3D); glBindTexture(GL_TEXTURE_3D, atten3d_texture_object); glTranslatef(0.5,0.5,0.5); glScalef(0.5,0.5,0.5); glScalef(invrad, invrad, invrad); glTranslatef(-lightOrig[0], -lightOrig[1], -lightOrig[2]); } GL_SelectTexture(GL_TEXTURE0_ARB); //combiner0 RGB: calculate // (normal map = A) dot (norm cubemap = B) save in Spare0 RGB // (color map = C) mul (light filter = D) save in Spare1 RGB qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_SPARE1_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE); //combiner0 Alpha: store 8*expand(tang space light vect z comp) into Spare0 Alpha (this is the selfshadow term) qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); qglCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //Only if the light is not white we use a second combiner //this is when the light is at its full brightness (for flickering lights) //and doesn't have any color (other than white) if ((currentshadowlight->color[0] != 1) || (currentshadowlight->color[1] != 1) || (currentshadowlight->color[2] != 1)) { qglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 2); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerOutputNV(GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //alpha out = nothing qglCombinerOutputNV(GL_COMBINER1_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); } else { qglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1); } //final combiner: final RGB = (Spare 0 Alpha) * ( (Spare 0 RGB) * (Spare 1 RGB) ) qglFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); //qglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); //qglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); //final cominer alpha doesn't really matter we use A dot B qglFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE); glEnable(GL_REGISTER_COMBINERS_NV); // Enable the vertex program. //qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, diffuse_program_object ); //glEnable( GL_VERTEX_PROGRAM_ARB ); qglBindProgramNV( GL_VERTEX_PROGRAM_NV, diffuse_program_object ); glEnable( GL_VERTEX_PROGRAM_NV ); } void GL_DisableDiffuseShaderGF3() { qglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1); //tex 0 = normal map //tex 1 = nomalization cube map (tangent space light vector) //tex 2 = color map //tex 3 = (attenuation or light filter, depends on light settings) GL_SelectTexture(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_CUBE_MAP_ARB); GL_SelectTexture(GL_TEXTURE2_ARB); glDisable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE3_ARB); if (currentshadowlight->filtercube) { glDisable(GL_TEXTURE_CUBE_MAP_ARB); } else { glDisable(GL_TEXTURE_3D); } glPopMatrix(); glMatrixMode(GL_MODELVIEW); GL_SelectTexture(GL_TEXTURE0_ARB); glDisable(GL_REGISTER_COMBINERS_NV); // glDisable( GL_VERTEX_PROGRAM_ARB ); glDisable( GL_VERTEX_PROGRAM_NV ); } void GL_EnableSpecularShaderGF3(qboolean world, vec3_t lightOrig, qboolean alias) { vec3_t scaler = {0.5f, 0.5f, 0.5f}; float invrad = 1/currentshadowlight->radius; //tex 0 = normal map //tex 1 = nomalization cube map (tangent space half angle) //tex 2 = color map //tex 3 = (attenuation or light filter, depends on light settings but the actual // register combiner setup does not change only the bound texture) GL_SelectTexture(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object); GL_SelectTexture(GL_TEXTURE2_ARB); glEnable(GL_TEXTURE_2D); GL_SelectTexture(GL_TEXTURE3_ARB); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); if (currentshadowlight->filtercube) { glEnable(GL_TEXTURE_CUBE_MAP_ARB); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, currentshadowlight->filtercube); GL_SetupCubeMapMatrix(world); } else { glEnable(GL_TEXTURE_3D); glBindTexture(GL_TEXTURE_3D, atten3d_texture_object); glTranslatef(0.5,0.5,0.5); glScalef(0.5,0.5,0.5); glScalef(invrad, invrad, invrad); glTranslatef(-lightOrig[0], -lightOrig[1], -lightOrig[2]); } GL_SelectTexture(GL_TEXTURE0_ARB); qglCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 4); qglCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &scaler[0]); //combiner0 RGB: calculate // (normal map = A) dot (norm cubemap = B) save in Spare0 RGB // (gloss map = C) mul (light filter = D) save in Spare1 RGB qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV , GL_ALPHA); qglCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_SPARE1_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE); //combiner0 Alpha: store 8*expand(tang space light vect z comp) into Spare1 Alpha (this is the selfshadow term) if (alias) { qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_SECONDARY_COLOR_NV, GL_EXPAND_NORMAL_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_SECONDARY_COLOR_NV, GL_EXPAND_NORMAL_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); } else { qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_BLUE); qglCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA); } qglCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV, GL_SPARE1_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //rgb = multipy light with color qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerInputNV(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerOutputNV(GL_COMBINER1_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner1 Alpha: calculate 2*((N'dotH)^2 - 0.5f) -> store in Spare0 Alpha ("raise" to an exponent) 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_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner2 Alpha: Raise specular further qglCombinerInputNV(GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglCombinerOutputNV(GL_COMBINER2_NV, GL_ALPHA, GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner2 rgb: Do nothing // qglCombinerInputNV(GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); // qglCombinerInputNV(GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV, GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB); // qglCombinerOutputNV(GL_COMBINER2_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); qglCombinerOutputNV(GL_COMBINER2_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner3 Alpha: Raise specular further qglCombinerInputNV(GL_COMBINER3_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER3_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglCombinerOutputNV(GL_COMBINER3_NV, GL_ALPHA, GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //combiner3 rgb: Do nothing // qglCombinerOutputNV(GL_COMBINER2_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); qglCombinerInputNV(GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglCombinerInputNV(GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglCombinerInputNV(GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_C_NV, GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV , GL_ALPHA); qglCombinerInputNV(GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_D_NV, GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV , GL_RGB); qglCombinerOutputNV(GL_COMBINER3_NV, GL_RGB, GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE); //final combiner: final RGB = (Spare 0 Alpha) * ( (Spare 0 RGB) * (Spare 1 RGB) ) qglFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA); qglFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_E_TIMES_F_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_ZERO, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); qglFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB); //final cominer alpha doesn't really matter we use A dot B qglFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE); glEnable(GL_REGISTER_COMBINERS_NV); // Enable the vertex program. // qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, diffuse_program_object ); // glEnable( GL_VERTEX_PROGRAM_ARB ); if (alias) qglBindProgramNV( GL_VERTEX_PROGRAM_NV, specularalias_program_object ); else qglBindProgramNV( GL_VERTEX_PROGRAM_NV, diffuse_program_object ); glEnable( GL_VERTEX_PROGRAM_NV ); } /* GL_DisableSpecularShaderGF3() ?? Same as GL_DisableDiffuseShaderGF3() */ void GL_EnableAttentShaderGF3(vec3_t lightOrig) { float invrad = 1/currentshadowlight->radius; glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glTranslatef(0.5,0.5,0.5); glScalef(0.5,0.5,0.5); glScalef(invrad, invrad, invrad); glTranslatef(-lightOrig[0], -lightOrig[1], -lightOrig[2]); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_3D); glBindTexture(GL_TEXTURE_3D, atten3d_texture_object); } void GL_DisableAttentShaderGF3() { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glDisable(GL_TEXTURE_3D); glEnable(GL_TEXTURE_2D); } void R_DrawWorldGF3Diffuse(lightcmd_t *lightCmds) { int command, num, i; int lightPos = 0; vec3_t lightOr; msurface_t *surf; float *v; texture_t *t;//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 t = R_TextureAnimation (surf->texinfo->texture); GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(t->gl_texturenum+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(t->gl_texturenum); glBegin(command); //v = surf->polys->verts[0]; v = (float *)(&globalVertexTable[surf->polys->firstvertex]); for (i=0; iorigin,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 t = R_TextureAnimation (surf->texinfo->texture); GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(t->gl_texturenum+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(t->gl_texturenum); 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->texinfo->vecs[1]); tsH[0] = DotProduct(H,surf->texinfo->vecs[0]); // VectorAdd(lightDir,tsH,tsH); qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]); qglMultiTexCoord3fvARB(GL_TEXTURE1_ARB,&tsH[0]); glVertex3fv(&v[0]); } glEnd(); } GL_SelectTexture(GL_TEXTURE0_ARB); } void R_DrawBrushGF3Diffuse(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; texture_t *t; //XYZ count = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //XYZ t = R_TextureAnimation (surf->texinfo->texture); GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(t->gl_texturenum+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(t->gl_texturenum); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]); qglMultiTexCoord3fvARB(GL_TEXTURE1_ARB,&ins->tslights[count+j][0]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } void R_DrawBrushGF3Specular(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; texture_t *t;//XYZ count = 0; surf = &model->surfaces[model->firstmodelsurface]; for (i=0; inummodelsurfaces; i++, surf++) { if (!ins->polygonVis[i]) continue; poly = surf->polys; //XYZ t = R_TextureAnimation (surf->texinfo->texture); GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(t->gl_texturenum+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(t->gl_texturenum); glBegin(GL_TRIANGLE_FAN); //v = poly->verts[0]; v = (float *)(&globalVertexTable[poly->firstvertex]); for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) { qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]); qglMultiTexCoord3fvARB(GL_TEXTURE1_ARB,&ins->tshalfangles[count+j][0]); glVertex3fv(v); } glEnd(); count+=surf->numedges; } } void R_DrawAliasFrameGF3Diffuse (aliashdr_t *paliashdr, aliasframeinstant_t *instant) { mtriangle_t *tris; fstvert_t *texcoords; int anim; int *indecies; aliaslightinstant_t *linstant = instant->lightinstant; tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles); texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords); //bind normal map anim = (int)(cl.time*10) & 3; GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); indecies = (int *)((byte *)paliashdr + paliashdr->indecies); glVertexPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_VERTEX_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(3, GL_FLOAT, 0, linstant->tslights); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //glDrawElements(GL_TRIANGLES,paliashdr->numtris*3,GL_UNSIGNED_INT,indecies); 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); GL_SelectTexture(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void R_DrawAliasFrameGF3Specular (aliashdr_t *paliashdr, aliasframeinstant_t *instant) { mtriangle_t *tris; fstvert_t *texcoords; vec3_t lightOr; int anim; int *indecies; aliaslightinstant_t *linstant = instant->lightinstant; tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles); texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords); VectorCopy(currentshadowlight->origin,lightOr); //bind normal map anim = (int)(cl.time*10) & 3; GL_SelectTexture(GL_TEXTURE0_ARB); GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]+1); GL_SelectTexture(GL_TEXTURE2_ARB); GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); indecies = (int *)((byte *)paliashdr + paliashdr->indecies); glVertexPointer(3, GL_FLOAT, 0, instant->vertices); glEnableClientState(GL_VERTEX_ARRAY); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(3, GL_FLOAT, 0, linstant->tshalfangles); glEnableClientState(GL_TEXTURE_COORD_ARRAY); //to to correct self shadowing on alias models send the light vectors an extra time... qglClientActiveTextureARB(GL_TEXTURE2_ARB); glTexCoordPointer(3, GL_FLOAT, 0, linstant->tslights); 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); //Con_Printf("%i backfacing tris\n",(paliashdr->numtris*3)-(linstant->numtris*3)); glDrawElements(GL_TRIANGLES,(paliashdr->numtris*3)-(linstant->numtris*3),GL_UNSIGNED_INT,&linstant->indecies[linstant->numtris*3]); glStencilFunc(GL_EQUAL, 0, 0xffffffff); } //qglClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); qglClientActiveTextureARB(GL_TEXTURE1_ARB); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void R_DrawWorldBumpedGF3() { if (!currentshadowlight->visible) return; glDepthMask (0); glShadeModel (GL_SMOOTH); if (currentshadowlight->filtercube) { //draw attent into dest alpha GL_DrawAlpha(); GL_EnableAttentShaderGF3(currentshadowlight->origin); R_DrawWorldWV(currentshadowlight->lightCmds, false); GL_DisableAttentShaderGF3(); GL_ModulateAlphaDrawColor(); } else { GL_AddColor(); } glColor3fv(¤tshadowlight->color[0]); GL_EnableSpecularShaderGF3(true,currentshadowlight->origin,false); R_DrawWorldGF3Specular(currentshadowlight->lightCmds); GL_DisableDiffuseShaderGF3(); GL_EnableDiffuseShaderGF3(true,currentshadowlight->origin); R_DrawWorldGF3Diffuse(currentshadowlight->lightCmds); GL_DisableDiffuseShaderGF3(); glColor3f (1,1,1); glDisable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask (1); } void R_DrawBrushBumpedGF3(entity_t *e) { if (currentshadowlight->filtercube) { //draw attent into dest alpha GL_DrawAlpha(); GL_EnableAttentShaderGF3(((brushlightinstant_t *)e->brushlightinstant)->lightpos); R_DrawBrushWV(e, false); GL_DisableAttentShaderGF3(); GL_ModulateAlphaDrawColor(); } else { GL_AddColor(); } glColor3fv(¤tshadowlight->color[0]); GL_EnableSpecularShaderGF3(false,((brushlightinstant_t *)e->brushlightinstant)->lightpos,false); R_DrawBrushGF3Specular(e); GL_DisableDiffuseShaderGF3(); GL_EnableDiffuseShaderGF3(false,((brushlightinstant_t *)e->brushlightinstant)->lightpos); R_DrawBrushGF3Diffuse(e); GL_DisableDiffuseShaderGF3(); } void R_DrawAliasBumpedGF3(aliashdr_t *paliashdr, aliasframeinstant_t *instant) { if (currentshadowlight->filtercube) { //draw attent into dest alpha GL_DrawAlpha(); GL_EnableAttentShaderGF3(instant->lightinstant->lightpos); R_DrawAliasFrameWV(paliashdr,instant, false); GL_DisableAttentShaderGF3(); GL_ModulateAlphaDrawColor(); } else { GL_AddColor(); } glColor3fv(¤tshadowlight->color[0]); GL_EnableSpecularShaderGF3(false,instant->lightinstant->lightpos,true); R_DrawAliasFrameGF3Specular(paliashdr,instant); GL_DisableDiffuseShaderGF3(); GL_EnableDiffuseShaderGF3(false,instant->lightinstant->lightpos); R_DrawAliasFrameGF3Diffuse(paliashdr,instant); GL_DisableDiffuseShaderGF3(); } /* Vertex programs */ /* Thisone does not do anything too usefull, it just copyies some things around instead of sending the save coordinates for unit0/2 we send them once and copy them here, this saves some bandwith and is slightly faster. */ char vpDiffuseGF3 [] = "!!VP1.1 # Diffuse bumpmapping vetex program.\n" "OPTION NV_position_invariant;" // Generates a necessary input for the diffuse bumpmapping registers // // c[0]...c[3] contains the modelview projection composite matrix // c[4]...c[7] contains the texture matrix of unit 3 // v[OPOS] contains the per-vertex position // v[TEX1] contains the per-vertex tangent space light vector // v[TEX0] contains the per-vertex texture coordinate 0 // o[HPOS] output register for homogeneous position // o[TEX0] output register for texture coordinate 0 // o[TEX1] output register for texture coordinate 1 // o[TEX2] output register for texture coordinate 2 // o[TEX3] output register for texture coordinate 3 // Transform vertex to view-space // Transform vertex by texture matrix and copy to output "DP4 o[TEX3].x, v[OPOS], c[4];" "DP4 o[TEX3].y, v[OPOS], c[5];" "DP4 o[TEX3].z, v[OPOS], c[6];" "DP4 o[TEX3].w, v[OPOS], c[7];" //copy tex coords of unit 0 to unit 2 "MOV o[TEX0], v[TEX0];" "MOV o[TEX2], v[TEX0];" "MOV o[TEX1], v[TEX1];" "MOV o[COL0], v[COL0];" "END"; /* Only used for specular on alias models when noshadowpopping is enabled... */ char vpSpecularAliasGF3 [] = "!!VP1.1 # Diffuse bumpmapping vetex program.\n" "OPTION NV_position_invariant;" // Generates a necessary input for the diffuse bumpmapping registers // // c[0]...c[3] contains the modelview projection composite matrix // c[4]...c[7] contains the texture matrix of unit 3 // v[OPOS] contains the per-vertex position // v[TEX1] contains the per-vertex tangent space light vector // v[TEX0] contains the per-vertex texture coordinate 0 // v[TEX2] contains the per-vertex light vector // o[HPOS] output register for homogeneous position // o[TEX0] output register for texture coordinate 0 // o[TEX1] output register for texture coordinate 1 // o[TEX2] output register for texture coordinate 2 // o[TEX3] output register for texture coordinate 3 // Transform vertex to view-space // Transform vertex by texture matrix and copy to output "DP4 o[TEX3].x, v[OPOS], c[4];" "DP4 o[TEX3].y, v[OPOS], c[5];" "DP4 o[TEX3].z, v[OPOS], c[6];" "DP4 o[TEX3].w, v[OPOS], c[7];" "MOV o[TEX0], v[TEX0];" //range compress into secondary color "MAD o[COL1], v[TEX2], c[20], c[20];" //copy tex coords of unit 0 to unit 2 "MOV o[TEX2], v[TEX0];" "MOV o[TEX1], v[TEX1];" "MOV o[COL0], v[COL0];" "END"; void R_LoadVertexProgram() { GLint errPos, errCode; const GLubyte *errString; if ( gl_cardtype != GEFORCE3 ) return; // Create the vertex program. qglGenProgramsNV( 1, &diffuse_program_object); qglLoadProgramNV( GL_VERTEX_PROGRAM_NV, diffuse_program_object, strlen(vpDiffuseGF3), (const GLubyte *) vpDiffuseGF3); qglGenProgramsNV( 1, &specularalias_program_object); qglLoadProgramNV( GL_VERTEX_PROGRAM_NV, specularalias_program_object, strlen(vpSpecularAliasGF3), (const GLubyte *) vpSpecularAliasGF3); if ( (errCode = glGetError()) != GL_NO_ERROR ) { errString = gluErrorString( errCode ); // glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos); glGetIntegerv( GL_PROGRAM_ERROR_POSITION_NV, &errPos); Con_Printf("LoadVertexProgram: %s\n", errString); Con_Printf("error is located at line: %d\n", errPos); exit( -1 ); } else { Con_Printf("VertexProgram loaded\n"); } // Track the concatenation of the modelview and projection matrix in registers 0-3. qglTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV ); // Track the texture unit 3 maxtix in registers 4-7 qglTrackMatrixNV( GL_VERTEX_PROGRAM_NV, 4, GL_TEXTURE3_ARB, GL_IDENTITY_NV ); //store 0.5 0.5 0.5 0.5 in register 8 qglProgramParameter4fNV( GL_VERTEX_PROGRAM_NV, 20, 0.5, 0.5, 0.5, 0.5); }