I still suck ass at OpenGL. But I was able to hack Unreal-style vertex lighting (a.k.a. "fake directional" lighting) for models. This tutorial assumes you've already implemented Phoenix's model interpolation tutorial, and possibly muff's MD2 tutorial. Unfortunately, due to the massive number of ways that the MD2 and MDL drawing routines have been hacked, I can't say this will work out-of-the-box for everyone. First things first: Create a file called "vertexlights.h", and throw the following code in it:extern byte anorm_pitch[162]; extern byte anorm_yaw[162]; extern byte vlighttable[256][256]; float VLight_LerpLight(int index1, int index2, float ilerp, float apitch, float ayaw); // RIOT - Vertex lighting for models #include "quakedef.h" #include "vertexlights.h" cvar_t vlight_pitch = {"vl_pitch", "45", true}; cvar_t vlight_yaw = {"vl_yaw", "45", true}; cvar_t vlight_highcut = {"vl_highcut", "128", true}; cvar_t vlight_lowcut = {"vl_lowcut", "60", true}; byte anorm_pitch[162]; byte anorm_yaw[162]; byte vlighttable[256][256]; float VLight_GetLightValue(int index, float apitch, float ayaw) { int pitchofs, yawofs; float retval; pitchofs = anorm_pitch[index] + (apitch * 256 / 360); yawofs = anorm_yaw[index] + (ayaw * 256 / 360); while(pitchofs > 255) pitchofs -= 256; while(yawofs > 255) yawofs -= 256; while(pitchofs < 0) pitchofs += 256; while(yawofs < 0) yawofs += 256; retval = vlighttable[pitchofs][yawofs]; return retval / 256; } float VLight_LerpLight(int index1, int index2, float ilerp, float apitch, float ayaw) { float lightval1; float lightval2; lightval1 = VLight_GetLightValue(index1, apitch, ayaw); lightval2 = VLight_GetLightValue(index2, apitch, ayaw); return (lightval2*ilerp) + (lightval1*(1-ilerp)); } void VLight_ResetAnormTable() { int i,j; vec3_t tempanorms[162] = { #include "anorms.h" }; float forward; float yaw, pitch; float angle; float sp, sy, cp, cy; float precut; vec3_t normal; vec3_t lightvec; // Define the light vector here angle = DEG2RAD(vlight_pitch.value); sy = sin(angle); cy = cos(angle); angle = DEG2RAD(-vlight_yaw.value); sp = sin(angle); cp = cos(angle); lightvec[0] = cp*cy; lightvec[1] = cp*sy; lightvec[2] = -sp; // First thing that needs to be done is the conversion of the // anorm table into a pitch/yaw table for(i=0;i<162;i++) { if (tempanorms[i][1] == 0 && tempanorms[i][0] == 0) { yaw = 0; if (tempanorms[i][2] > 0) pitch = 90; else pitch = 270; } else { yaw = (int) (atan2(tempanorms[i][1], tempanorms[i][0]) * 57.295779513082320); if (yaw < 0) yaw += 360; forward = sqrt (tempanorms[i][0]*tempanorms[i][0] + tempanorms[i][1]*tempanorms[i][1]); pitch = (int) (atan2(tempanorms[i][2], forward) * 57.295779513082320); if (pitch < 0) pitch += 360; } anorm_pitch[i] = pitch * 256 / 360; anorm_yaw[i] = yaw * 256 / 360; } // Next, a light value table must be constructed for pitch/yaw offsets // DotProduct values // DotProduct values never go higher than 2, so store bytes as // (product * 127.5) if(vlight_highcut.value <= vlight_lowcut.value || vlight_highcut.value > 256 || vlight_highcut.value < 10) Cvar_SetValue("vl_highcut", 256); if(vlight_lowcut.value >= vlight_highcut.value || vlight_lowcut.value < 0 || vlight_lowcut.value > 250) Cvar_SetValue("vl_lowcut", 0); for(i=0;i<256;i++) { angle = DEG2RAD(i * 360 / 256); sy = sin(angle); cy = cos(angle); for(j=0;j<256;j++) { angle = DEG2RAD(j * 360 / 256); sp = sin(angle); cp = cos(angle); normal[0] = cp*cy; normal[1] = cp*sy; normal[2] = -sp; precut = ((DotProduct(normal, lightvec) + 2) * 63.5); precut = (precut - (vlight_lowcut.value)) * 256 / (vlight_highcut.value - vlight_lowcut.value); if(precut > 255) precut = 255; if(precut < 0) precut = 0; vlighttable[i][j] = precut; } } } void VLight_ChangeLightAngle_f(void) { VLight_ResetAnormTable(); } void VLight_DumpLightTable_f(void) { COM_WriteFile ("lighttable.raw", vlighttable, 256*256); } #define DEG2RAD(a) (a * M_PI / 180.0) extern cvar_t vlight_pitch; // RIOT - Vertex lighting extern cvar_t vlight_yaw; extern cvar_t vlight_lowcut; extern cvar_t vlight_highcut; void VLight_ResetAnormTable(); // RIOT - Vertex lighting Cvar_RegisterVariable(&vlight_pitch); Cvar_RegisterVariable(&vlight_yaw); Cvar_RegisterVariable(&vlight_highcut); Cvar_RegisterVariable(&vlight_lowcut); VLight_ResetAnormTable(); void VLight_ChangeLightAngle_f(void); // RIOT - Vertex lights void VLight_DumpLightTable_f(void); Cmd_AddCommand ("vl_changeangle", VLight_ChangeLightAngle_f); Cmd_AddCommand ("vl_dumplight", VLight_DumpLightTable_f); #include "vertexlights.h" l = shadedots_mdl[verts1->lightnormalindex]; // RIOT - Vertex lighting l = VLight_LerpLight(verts1->lightnormalindex, verts2->lightnormalindex, blend, apitch, ayaw); #include "vertexlights.h" l = shadedots_md2[verts1->lightnormalindex]; // RIOT - Vertex lighting l = VLight_LerpLight(verts1[order[2]].lightnormalindex, verts2[order[2]].lightnormalindex, ilerp, apitch, ayaw); There's only one problem left: You need to relay pitch and yaw to the lerp functions. The changes needed to do this are numerous, so you'll have to hunt them down yourself. The definite thing is that you need to add "float apitch, float ayaw" to the parameter lists of R_SetupQ2AliasFrame, GL_DrawQ2AliasFrame, and GL_DrawAliasBlendedFrame. R_SetupQ2AliasFrame also needs to pass the pitch/yaw values to GL_DrawQ2AliasFrame. This should not be very difficult at all, assuming your code editor has a Find function. Finally, find R_DrawAliasModel. Make the following changes:GL_DrawAliasBlendedFrame (currententity->frame, paliashdr, currententity); GL_DrawAliasBlendedFrame (currententity->frame, paliashdr, currententity, e->angles[0], e->angles[1]); R_SetupQ2AliasFrame (currententity->frame, pheader, currententity); R_SetupQ2AliasFrame (currententity->frame, pheader, currententity, e->angles[0], e->angles[1]); This does, by the way, pave the way for directional lighting. What you'd need to do is tweak the pitch/yaw input values for VLight_LerpLight to point towards the light source. Oh, and one last thing.... All code in this document (c)2001 Orbiter Productions and is protected by the terms and conditions described in the GNU General Public License, downloadable at http://www.gnu.org/copyleft/gpl.html. In other words, don't steal my shit. |