From 217a26e3c67b0c3e5941e5a1837586f4a334304f Mon Sep 17 00:00:00 2001 From: sago007 Date: Sun, 27 Nov 2016 11:24:18 +0100 Subject: [PATCH] Different proactive changes to prevent problems... or make them A LOT more visible. --- code/client/snd_codec_xmp.c | 65 +- code/renderer_oa/tr_bloom.c | 204 ++--- code/renderer_oa/tr_model_mdo.c | 1424 +++++++++++++++---------------- 3 files changed, 842 insertions(+), 851 deletions(-) diff --git a/code/client/snd_codec_xmp.c b/code/client/snd_codec_xmp.c index e88b66bd..60bea85b 100644 --- a/code/client/snd_codec_xmp.c +++ b/code/client/snd_codec_xmp.c @@ -80,12 +80,10 @@ S_XMP_CodecOpenStream // FIXME: there's a memory leak here if you start the same song many many many many times. snd_stream_t *S_XMP_CodecOpenStream(const char *filename) { - snd_stream_t *rv; - // First let's close whatever song we had.... // Open - rv = S_CodecUtilOpen(filename, &xmp_codec); + snd_stream_t *rv = S_CodecUtilOpen(filename, &xmp_codec); if(!rv) return NULL; @@ -93,7 +91,6 @@ snd_stream_t *S_XMP_CodecOpenStream(const char *filename) { fileHandle_t file; - void *buffer; // Try to open the file FS_FOpenFileRead(filename, &file, qtrue); @@ -105,15 +102,14 @@ snd_stream_t *S_XMP_CodecOpenStream(const char *filename) // Allocate some memory - long thelength = FS_ReadFile(filename, buffer); + long thelength = FS_ReadFile(filename, NULL); - buffer = Hunk_AllocateTempMemory(thelength); + void *buffer = Hunk_AllocateTempMemory(thelength); if(!buffer) { FS_FCloseFile(file); - Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n", - filename); + Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n", filename); return NULL; } @@ -133,15 +129,13 @@ snd_stream_t *S_XMP_CodecOpenStream(const char *filename) FS_FCloseFile(file); // unfortunately these do not help with the leak if (itsloaded == 0) - itsloaded = xmp_start_player(xmpsong, xmpspeed, 0); // TODO: do sample rate of the mixer. + itsloaded = xmp_start_player(xmpsong, xmpspeed, 0); // TODO: do sample rate of the mixer. if (itsloaded == 0){ - - // Com_Printf("XMP loaded our buffer of the file %s which is %i long \n", filename, thelength); - xmp_get_module_info(xmpsong, &mi); - // Com_Printf("Song Name: %s\n", mi.mod->name); - // Com_Printf("CODECLOAD %s\n", filename); - + // Com_Printf("XMP loaded our buffer of the file %s which is %i long \n", filename, thelength); + xmp_get_module_info(xmpsong, &mi); + // Com_Printf("Song Name: %s\n", mi.mod->name); + // Com_Printf("CODECLOAD %s\n", filename); } } @@ -182,9 +176,6 @@ int S_XMP_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) // buffer handling struct xmp_module_info mi; struct xmp_frame_info fi; - - int bytesRead, bytesLeft, c; - char *bufPtr; // check if input is valid if(!(stream && buffer)) @@ -197,9 +188,9 @@ int S_XMP_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) return 0; } - bytesRead = 0; - bytesLeft = bytes; - bufPtr = buffer; + int bytesRead = 0; + int bytesLeft = bytes; + char* bufPtr = buffer; // cycle until we have the requested or all available bytes read while(-1) @@ -207,26 +198,26 @@ int S_XMP_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) int yeah=xmp_play_buffer(xmpsong, buffer, bytesLeft, 0); if (yeah == 0){ // if we can play it... - xmp_get_frame_info(xmpsong, &fi); + xmp_get_frame_info(xmpsong, &fi); - c = fi.buffer; + int c = fi.buffer_size; - // no more bytes are left - if(c <= 0) - { - break; - } + // no more bytes are left + if(c <= 0) + { + break; + } - bytesRead += c; - bytesLeft -= c; - bufPtr += c; - xmp_get_module_info(xmpsong, &mi); + bytesRead += c; + bytesLeft -= c; + bufPtr += c; + xmp_get_module_info(xmpsong, &mi); - // we have enough bytes - if(bytesLeft <= 0) - { - break; - } + // we have enough bytes + if(bytesLeft <= 0) + { + break; + } } else // if we can't play it JUST STOP OK { diff --git a/code/renderer_oa/tr_bloom.c b/code/renderer_oa/tr_bloom.c index 06d818e7..ee643ff0 100644 --- a/code/renderer_oa/tr_bloom.c +++ b/code/renderer_oa/tr_bloom.c @@ -751,30 +751,33 @@ static void ID_INLINE R_Bloom_QuadTV( int width, int height, float texX, float t static void R_Bloom_RestoreScreen_Postprocessed( void ) { #ifdef GLSL_POSTPROCESSING - glslProgram_t *program; - if (leifxmode) - { - if (leifxmode == 1){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXDitherProgram); program=tr.programs[tr.leiFXDitherProgram];} - if (leifxmode == 2){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXGammaProgram); program=tr.programs[tr.leiFXGammaProgram];} - if (leifxmode == 3){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXFilterProgram); program=tr.programs[tr.leiFXFilterProgram];} - if (leifxmode == 888){ if (vertexShaders) R_GLSL_UseProgram(tr.animeProgram); program=tr.programs[tr.animeProgram];} - if (leifxmode == 999){ if (vertexShaders) R_GLSL_UseProgram(tr.animeFilmProgram); program=tr.programs[tr.animeFilmProgram];} - if (leifxmode == 777){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); program=tr.programs[tr.motionBlurProgram];} - if (leifxmode == 778){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); program=tr.programs[tr.motionBlurProgram];} - if (leifxmode == 779){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurPostProgram); program=tr.programs[tr.motionBlurPostProgram];} - if (leifxmode == 632){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCEncodeProgram); program=tr.programs[tr.NTSCEncodeProgram];} - if (leifxmode == 633){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCDecodeProgram); program=tr.programs[tr.NTSCDecodeProgram];} - if (leifxmode == 634){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCBleedProgram); program=tr.programs[tr.NTSCBleedProgram];} - if (leifxmode == 666){ if (vertexShaders) R_GLSL_UseProgram(tr.BrightnessProgram); program=tr.programs[tr.BrightnessProgram];} - if (leifxmode == 1236){ if (vertexShaders) R_GLSL_UseProgram(tr.CRTProgram); program=tr.programs[tr.CRTProgram];} - if (leifxmode == 1997){ if (vertexShaders) R_GLSL_UseProgram(tr.paletteProgram); program=tr.programs[tr.paletteProgram];} + glslProgram_t *program = NULL; + if (leifxmode) { + if (leifxmode == 1){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXDitherProgram); program=tr.programs[tr.leiFXDitherProgram];} + if (leifxmode == 2){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXGammaProgram); program=tr.programs[tr.leiFXGammaProgram];} + if (leifxmode == 3){ if (vertexShaders) R_GLSL_UseProgram(tr.leiFXFilterProgram); program=tr.programs[tr.leiFXFilterProgram];} + if (leifxmode == 888){ if (vertexShaders) R_GLSL_UseProgram(tr.animeProgram); program=tr.programs[tr.animeProgram];} + if (leifxmode == 999){ if (vertexShaders) R_GLSL_UseProgram(tr.animeFilmProgram); program=tr.programs[tr.animeFilmProgram];} + if (leifxmode == 777){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); program=tr.programs[tr.motionBlurProgram];} + if (leifxmode == 778){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurProgram); program=tr.programs[tr.motionBlurProgram];} + if (leifxmode == 779){ if (vertexShaders) R_GLSL_UseProgram(tr.motionBlurPostProgram); program=tr.programs[tr.motionBlurPostProgram];} + if (leifxmode == 632){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCEncodeProgram); program=tr.programs[tr.NTSCEncodeProgram];} + if (leifxmode == 633){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCDecodeProgram); program=tr.programs[tr.NTSCDecodeProgram];} + if (leifxmode == 634){ if (vertexShaders) R_GLSL_UseProgram(tr.NTSCBleedProgram); program=tr.programs[tr.NTSCBleedProgram];} + if (leifxmode == 666){ if (vertexShaders) R_GLSL_UseProgram(tr.BrightnessProgram); program=tr.programs[tr.BrightnessProgram];} + if (leifxmode == 1236){ if (vertexShaders) R_GLSL_UseProgram(tr.CRTProgram); program=tr.programs[tr.CRTProgram];} + if (leifxmode == 1997){ if (vertexShaders) R_GLSL_UseProgram(tr.paletteProgram); program=tr.programs[tr.paletteProgram];} } - else - { - if (vertexShaders) R_GLSL_UseProgram(tr.postprocessingProgram); - // Feed GLSL postprocess program - program=tr.programs[tr.postprocessingProgram]; + else { + if (vertexShaders) R_GLSL_UseProgram(tr.postprocessingProgram); + // Feed GLSL postprocess program + program=tr.programs[tr.postprocessingProgram]; + } + if (!program) { + //If leifsmode has been set to something invalid we have to bail out or we will dereference a null pointer + Com_Printf( S_COLOR_YELLOW"WARNING: 'leifxmode' has an invalid value\n" ); + return; } if (program->u_ScreenSizeX > -1) R_GLSL_SetUniform_u_ScreenSizeX(program, glConfig.vidWidth); @@ -1133,11 +1136,13 @@ static void R_Postprocess_InitTextures( void ) // postproc.tvwork.height /= intdiv; // interlacey - for (postproc.tveffect.width = 1;postproc.tveffect.width < postproc.tvwork.width;postproc.tveffect.width *= 2); -if (intdiv > 1) - for (postproc.tveffect.height = 1;(postproc.tveffect.height/2) < postproc.tvwork.height;postproc.tveffect.height *= 2); - else - for (postproc.tveffect.height = 1;postproc.tveffect.height < postproc.tvwork.height;postproc.tveffect.height *= 2); + for (postproc.tveffect.width = 1;postproc.tveffect.width < postproc.tvwork.width;postproc.tveffect.width *= 2) {} + if (intdiv > 1) { + for (postproc.tveffect.height = 1;(postproc.tveffect.height/2) < postproc.tvwork.height;postproc.tveffect.height *= 2) {} + } + else { + for (postproc.tveffect.height = 1;postproc.tveffect.height < postproc.tvwork.height;postproc.tveffect.height *= 2) {} + } postproc.tveffect.readW = postproc.tvwork.width / (float)postproc.tveffect.width; postproc.tveffect.readH = postproc.tvwork.height / (float)postproc.tveffect.height; @@ -1340,9 +1345,9 @@ void R_LeiFXPostprocessDitherScreen( void ) leifxmode = 1; // reduct and dither - 1 pass R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); - } + } - force32upload = 0; + force32upload = 0; #endif } @@ -1365,9 +1370,10 @@ void R_LeiFXPostprocessFilterScreen( void ) return; } - if ( !backEnd.projection2D ) + if ( !backEnd.projection2D ) { RB_SetGL2D(); - force32upload = 1; + } + force32upload = 1; // postprocess = 1; @@ -1381,8 +1387,8 @@ void R_LeiFXPostprocessFilterScreen( void ) */ // Gamma disabled because r_alternateBrightness 2 makes it redundant now. if (r_leifx->integer > 3){ leifxmode = 3; // filter - 4 pass - // The stupidest hack in america - R_LeiFX_Stupid_Hack(); + // The stupidest hack in america + R_LeiFX_Stupid_Hack(); leifxpass = 0; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); @@ -1395,10 +1401,10 @@ void R_LeiFXPostprocessFilterScreen( void ) leifxpass = 3; R_Postprocess_BackupScreen(); R_Bloom_RestoreScreen_Postprocessed(); - } + } backEnd.doneleifx = qtrue; - force32upload = 0; + force32upload = 0; #endif } @@ -1432,9 +1438,10 @@ void R_NTSCScreen( void ) return; } - if ( !backEnd.projection2D ) + if ( !backEnd.projection2D ) { RB_SetGL2D(); - force32upload = 1; + } + force32upload = 1; int ntsc_bleed = 0; int ntsc_encode = 0; @@ -1545,7 +1552,7 @@ void R_BrightItUp (int dst, int src, float intensity) void R_BrightScreen( void ) { - int mode; // 0 = none; 1 = blend; 2 = shader + int mode = 0; // 0 = none; 1 = blend; 2 = shader if( !r_alternateBrightness->integer) return; if ( backEnd.doneAltBrightness) @@ -1557,10 +1564,12 @@ void R_BrightScreen( void ) if (r_alternateBrightness->integer == 2) { // Automatically determine from capabilities - if ( vertexShaders ) - mode = 2; - else - mode = 1; + if ( vertexShaders ) { + mode = 2; + } + else { + mode = 1; + } } // the modern pixel shader way @@ -1595,14 +1604,12 @@ void R_BrightScreen( void ) else if (mode == 1) #endif { - int eh, ah; - if ((r_overBrightBits->integer)) - { + if ((r_overBrightBits->integer)) { ah = r_overBrightBits->integer; - if (ah < 1) ah = 1; if (ah > 2) ah = 2; // clamp so it never looks stupid - + if (ah < 1) { ah = 1; } + if (ah > 2) { ah = 2; } // clamp so it never looks stupid // Blend method // do a loop for every overbright bit enabled @@ -1611,8 +1618,7 @@ void R_BrightScreen( void ) R_BrightItUp(GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ONE, 1.0f); backEnd.doneAltBrightness = qtrue; - } - + } } } @@ -1638,7 +1644,6 @@ void R_AltBrightnessInit( void ) { void R_FilmScreen( void ) { vec3_t tone, toneinv, tonecont; - vec3_t tonework; if( !r_film->integer ) return; @@ -1648,83 +1653,78 @@ void R_FilmScreen( void ) RB_SetGL2D(); backEnd.doneFilm = qtrue; - // set up our colors, this is our default - tone[0] = 0.8f; - tone[1] = 0.9f; - tone[2] = 1.0f; + // set up our colors, this is our default + tone[0] = 0.8f; + tone[1] = 0.9f; + tone[2] = 1.0f; //VectorCopy( backEnd.currentEntity->ambientLight, tone ); - if (backEnd.currentEntity){ - if (backEnd.currentEntity->ambientLight[0] > 0.001f && backEnd.currentEntity->ambientLight[1] > 0.001f && backEnd.currentEntity->ambientLight[2] > 0.001f){ - tone[0] = backEnd.currentEntity->ambientLight[0]; - tone[1] = backEnd.currentEntity->ambientLight[1]; - tone[2] = backEnd.currentEntity->ambientLight[2]; - } + if (backEnd.currentEntity){ + if (backEnd.currentEntity->ambientLight[0] > 0.001f && backEnd.currentEntity->ambientLight[1] > 0.001f && backEnd.currentEntity->ambientLight[2] > 0.001f){ + tone[0] = backEnd.currentEntity->ambientLight[0]; + tone[1] = backEnd.currentEntity->ambientLight[1]; + tone[2] = backEnd.currentEntity->ambientLight[2]; } + } // VectorNormalize(tone); - tone[0] *= 0.3 + 0.7; - tone[1] *= 0.3 + 0.7; - tone[2] *= 0.3 + 0.7; + tone[0] *= 0.3 + 0.7; + tone[1] *= 0.3 + 0.7; + tone[2] *= 0.3 + 0.7; // tone[0] = 1.6f; // tone[1] = 1.2f; // tone[2] = 0.7f; - // TODO: Get overexposure to flares raising this faking "HDR" - tonecont[0] = 0.0f; - tonecont[1] = 0.0f; - tonecont[2] = 0.0f; - + // TODO: Get overexposure to flares raising this faking "HDR" + tonecont[0] = 0.0f; + tonecont[1] = 0.0f; + tonecont[2] = 0.0f; - // inverted - toneinv[0] = tone[0] * -1 + 1 + tonecont[0]; - toneinv[1] = tone[1] * -1 + 1 + tonecont[1]; - toneinv[2] = tone[2] * -1 + 1 + tonecont[2]; + // inverted - // darken vignette. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);GL_Bind( tr.dlightImage ); GL_Cull( CT_TWO_SIDED ); - qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.35f, 0.35f, 0.2f, 0.2f ); + toneinv[0] = tone[0] * -1 + 1 + tonecont[0]; + toneinv[1] = tone[1] * -1 + 1 + tonecont[1]; + toneinv[2] = tone[2] * -1 + 1 + tonecont[2]; + + // darken vignette. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO);GL_Bind( tr.dlightImage ); GL_Cull( CT_TWO_SIDED ); + qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.35f, 0.35f, 0.2f, 0.2f ); - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE);GL_Bind( tr.dlightImage ); GL_Cull( CT_TWO_SIDED ); - //qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); - qglColor4f( (0.9f + (tone[0] * 0.5)), (0.9f + (tone[1] * 0.5)), (0.9f + (tone[2] * 0.5)), 1.0f ); + // brighten. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE);GL_Bind( tr.dlightImage ); GL_Cull( CT_TWO_SIDED ); + //qglColor4f( 0.941177, 0.952941, 0.968628, 1.0f ); + qglColor4f( (0.9f + (tone[0] * 0.5)), (0.9f + (tone[1] * 0.5)), (0.9f + (tone[2] * 0.5)), 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.25f, 0.25f, 0.48f, 0.48f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0.25f, 0.25f, 0.48f, 0.48f ); - // invert. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); + // invert. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); // qglColor4f(0.85098, 0.85098, 0.815686, 1.0f ); - qglColor4f( (0.8f + (toneinv[0] * 0.5)), (0.8f + (toneinv[1] * 0.5)), (0.8f + (toneinv[2] * 0.5)), 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); + qglColor4f( (0.8f + (toneinv[0] * 0.5)), (0.8f + (toneinv[1] * 0.5)), (0.8f + (toneinv[2] * 0.5)), 1.0f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); - qglColor4f( 0.615686, 0.615686, 0.615686, 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); + // brighten. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); + qglColor4f( 0.615686, 0.615686, 0.615686, 1.0f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - // invoort. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); - qglColor4f(1.0f, 1.0f, 1.0f , 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); + // invoort. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_DST_COLOR | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); + qglColor4f(1.0f, 1.0f, 1.0f , 1.0f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - // brighten. - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); + // brighten. + GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR);GL_Bind( tr.whiteImage ); GL_Cull( CT_TWO_SIDED ); // qglColor4f( 0.866667, 0.847059, 0.776471, 1.0f ); - qglColor4f( (0.73f + (toneinv[0] * 0.4)), (0.73f + (toneinv[1] * 0.4)), (0.73f + (toneinv[2] * 0.4)), 1.0f ); - R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); - - - - - + qglColor4f( (0.73f + (toneinv[0] * 0.4)), (0.73f + (toneinv[1] * 0.4)), (0.73f + (toneinv[2] * 0.4)), 1.0f ); + R_Brighter_Quad( glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, 1 ); } diff --git a/code/renderer_oa/tr_model_mdo.c b/code/renderer_oa/tr_model_mdo.c index 9149868f..08d74aac 100644 --- a/code/renderer_oa/tr_model_mdo.c +++ b/code/renderer_oa/tr_model_mdo.c @@ -25,431 +25,431 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LL(x) x=LittleLong(x) -typedef struct{ - float matrix[3][4]; +typedef struct{ + float matrix[3][4]; }boneMatrix_t; -/* -================= -LOADING CODE -================= +/* +================= +LOADING CODE +================= */ -/* -================= -R_LoadMDO -================= -*/ -qboolean R_LoadMDO( model_t *mod, void *buffer, int filesize, const char *mod_name ) { - int i, j, k, lodindex; - mdoHeader_t *pinmodel, *mdo; - mdoFrame_t *frame; - mdoLOD_t *lod; - mdoSurface_t *surf; - mdoTriangle_t *tri; - mdoVertex_t *v; - mdoBoneInfo_t *bone; - int *boneRef; - int version; - int size; - shader_t *sh; - int frameSize; - - pinmodel = (mdoHeader_t *)buffer; - - if( Q_strncmp(pinmodel->ident, MDO_IDENT, sizeof(pinmodel->ident) ) ){ // failed - ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has wrong ident (%s should be %s)\n", - mod_name, pinmodel->ident, MDO_IDENT); - } - - version = LittleLong (pinmodel->version); - if (version != MDO_VERSION) { - ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has wrong version (%i should be %i)\n", - mod_name, version, MDO_VERSION); - return qfalse; - } - - mod->type = MOD_MDO; - - size = LittleLong(pinmodel->ofsEnd); - if(size > filesize) - { - ri.Printf(PRINT_WARNING, "R_LoadMDO: Header of %s is broken. Wrong filesize declared!\n", mod_name); - return qfalse; - } - - mod->dataSize += size; - mod->modelData = mdo = ri.Hunk_Alloc( size, h_low ); - - Com_Memcpy( mdo, buffer, LittleLong(pinmodel->ofsEnd) ); - - LL(mdo->version); - LL(mdo->numFrames); - LL(mdo->numBones); - LL(mdo->numLODs); - LL(mdo->ofsFrames); - LL(mdo->ofsLODs); - LL(mdo->ofsEnd); - - if ( mdo->numFrames < 1 ) { - ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has no frames\n", mod_name ); - return qfalse; - } - - if( mdo->numLODs < 1){ - ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has no LODs\n", mod_name ); - return qfalse; - } - - mod->numLods = mdo->numLODs; // ... don't forget this or LODs won't work - - // swap all the frames - frameSize = (int)( &((mdoFrame_t *)0)->bones[ mdo->numBones ] ); - for ( i = 0 ; i < mdo->numFrames ; i++, frame++) { - frame = (mdoFrame_t *) ( (byte *)mdo + mdo->ofsFrames + i * frameSize ); - frame->radius = LittleFloat( frame->radius ); - for ( j = 0 ; j < 3 ; j++ ) { - frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); - frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); - frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); - } - - for ( j = 0 ; j < mdo->numBones * sizeof( mdoBoneComp_t ) / sizeof( short ); j++ ) { - ( (short *)frame->bones )[j] = LittleShort( ( (short *)frame->bones )[j] ); - } - } - - // swap all the bone infos - bone = (mdoBoneInfo_t *) ( (byte *)mdo + mdo->ofsBones ); - for ( i = 0; i < mdo->numBones; i++, bone++ ){ - // lowercase the bone name so name compares are faster - Q_strlwr( bone->name ); - bone->flags = LittleLong(bone->flags); - bone->parent = LittleLong(bone->parent); - } - - // swap all the LOD's - lod = (mdoLOD_t *) ( (byte *)mdo + mdo->ofsLODs ); - for ( lodindex = 0 ; lodindex < mdo->numLODs ; lodindex++ ) { - LL(lod->numSurfaces); - LL(lod->ofsSurfaces); - LL(lod->ofsEnd); - // swap all the surfaces - surf = (mdoSurface_t *) ( (byte *)lod + lod->ofsSurfaces ); - for ( i = 0 ; i < lod->numSurfaces ; i++) { - //LL(surf->ident); - LL(surf->ofsHeader); // don't swap header offset - LL(surf->numTriangles); - LL(surf->ofsTriangles); - LL(surf->numVerts); - LL(surf->ofsVerts); - LL(surf->numBoneRefs); - LL(surf->ofsBoneRefs); - LL(surf->ofsEnd); - - - if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Error (ERR_DROP, "R_LoadMDO: %s has more than %i verts on a surface (%i)", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); - } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Error (ERR_DROP, "R_LoadMDO: %s has more than %i triangles on a surface (%i)", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); - } - - // change to surface identifier - surf->ident = SF_MDO; - - // lowercase the surface name so skin compares are faster - Q_strlwr( surf->name ); - - // register the shaders - sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); - if ( sh->defaultShader ) { - surf->shaderIndex = 0; - } else { - surf->shaderIndex = sh->index; - } - - // swap all the vertexes and texcoords - v = (mdoVertex_t *) ( (byte *)surf + surf->ofsVerts); - for ( j = 0 ; j < surf->numVerts ; j++ ) { - v->xyz[0] = LittleFloat( v->xyz[0] ); - v->xyz[1] = LittleFloat( v->xyz[1] ); - v->xyz[2] = LittleFloat( v->xyz[2] ); - - v->texCoords[0] = LittleFloat( v->texCoords[0] ); - v->texCoords[1] = LittleFloat( v->texCoords[1] ); - - v->normal = LittleShort( v->normal ); - // num bone weights + weights[] are bytes - v = (mdoVertex_t *)&v->weights[v->numWeights]; - } - - // swap all the triangles - tri = (mdoTriangle_t *) ( (byte *)surf + surf->ofsTriangles ); - for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { - LL(tri->indexes[0]); - LL(tri->indexes[1]); - LL(tri->indexes[2]); - } - - // swap all the bone references - boneRef = ( int * )( ( byte *)surf + surf->ofsBoneRefs ); - for ( j = 0; j < surf->numBoneRefs; j++, boneRef++ ){ - *boneRef = LittleLong( *boneRef ); - } - - // find the next surface - surf = (mdoSurface_t *)( (byte *)surf + surf->ofsEnd ); - } - - // find the next LOD - lod = (mdoLOD_t *)( (byte *)lod + lod->ofsEnd ); - } - - return qtrue; -} - -/* -================= -DRAWING CODE -================= -*/ - -/* -============= -R_CullMDO -============= -*/ - -static int R_CullMDO( mdoHeader_t *header, trRefEntity_t *ent ) { - vec3_t bounds[2]; - mdoFrame_t *oldFrame, *newFrame; - int i, frameSize; - - frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); - - // compute frame pointers - newFrame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - oldFrame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); - - // cull bounding sphere ONLY if this is not an upscaled entity - if ( !ent->e.nonNormalizedAxes ) - { - if ( ent->e.frame == ent->e.oldframe ) - { - switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) - { - - case CULL_OUT: - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - - case CULL_IN: - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - - case CULL_CLIP: - tr.pc.c_sphere_cull_md3_clip++; - break; - } - } - else - { - int sphereCull, sphereCullB; - - sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); - if ( newFrame == oldFrame ) { - sphereCullB = sphereCull; - } else { - sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); - } - - if ( sphereCull == sphereCullB ) - { - if ( sphereCull == CULL_OUT ) - { - tr.pc.c_sphere_cull_md3_out++; - return CULL_OUT; - } - else if ( sphereCull == CULL_IN ) - { - tr.pc.c_sphere_cull_md3_in++; - return CULL_IN; - } - else - { - tr.pc.c_sphere_cull_md3_clip++; - } - } - } - } - - // calculate a bounding box in the current coordinate system - for (i = 0 ; i < 3 ; i++) { - bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; - bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; - } - - switch ( R_CullLocalBox( bounds ) ) - { - case CULL_IN: - tr.pc.c_box_cull_md3_in++; - return CULL_IN; - case CULL_CLIP: - tr.pc.c_box_cull_md3_clip++; - return CULL_CLIP; - case CULL_OUT: - default: - tr.pc.c_box_cull_md3_out++; - return CULL_OUT; - } -} - -/* -================= -R_ComputeMDOFogNum - -================= -*/ -int R_ComputeMDOFogNum( mdoHeader_t *header, trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - mdoFrame_t *frame; - vec3_t localOrigin; - int frameSize; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); - - // FIXME: non-normalized axis issues - frame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - VectorAdd( ent->e.origin, frame->localOrigin, localOrigin ); - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( localOrigin[j] - frame->radius >= fog->bounds[1][j] ) { - break; - } - if ( localOrigin[j] + frame->radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -============== -R_AddMDOSurfaces -============== -*/ -void R_AddMDOSurfaces( trRefEntity_t *ent ) { - mdoHeader_t *header; - mdoSurface_t *surface; - mdoLOD_t *lod; - shader_t *shader; - skin_t *skin; - int i, j, k; - int lodnum = 0; - int fogNum = 0; - int cull; - qboolean personalModel; - - header = (mdoHeader_t *) tr.currentModel->modelData; - - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; - - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= header->numFrames; - ent->e.oldframe %= header->numFrames; - } - - // - // Validate the frames so there is no chance of a crash. - // This will write directly into the entity structure, so - // when the surfaces are rendered, they don't need to be - // range checked again. - // - if ((ent->e.frame >= header->numFrames) - || (ent->e.frame < 0) - || (ent->e.oldframe >= header->numFrames) - || (ent->e.oldframe < 0) ) - { - ri.Printf( PRINT_DEVELOPER, "R_AddMDOSurfaces: no such frame %d to %d for '%s'\n", - ent->e.oldframe, ent->e.frame, tr.currentModel->name ); - ent->e.frame = 0; - ent->e.oldframe = 0; - } - - // - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - // - cull = R_CullMDO (header, ent); - if ( cull == CULL_OUT ) { - return; - } - - // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. - lodnum = R_ComputeLOD(ent); - // check whether this model has as that many LODs at all. If not, try the closest thing we got. - if(header->numLODs <= 0) - return; - if(header->numLODs <= lodnum) - lodnum = header->numLODs - 1; - - lod = (mdoLOD_t *)( (byte *)header + header->ofsLODs); - for(i = 0; i < lodnum; i++) - { - lod = (mdoLOD_t *) ((byte *) lod + lod->ofsEnd); - } - - // set up lighting - if ( !personalModel || r_shadows->integer > 1 ) - { - R_SetupEntityLighting( &tr.refdef, ent ); - } - - // fogNum - fogNum = R_ComputeMDOFogNum( header, ent ); - - surface = (mdoSurface_t *)( (byte *)lod + lod->ofsSurfaces ); - - for ( i = 0 ; i < lod->numSurfaces ; i++ ) - { - - if(ent->e.customShader) - shader = R_GetShaderByHandle(ent->e.customShader); - else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) - { - skin = R_GetSkinByHandle(ent->e.customSkin); - shader = tr.defaultShader; - - for(j = 0; j < skin->numSurfaces; j++) - { - if (!strcmp(skin->surfaces[j]->name, surface->name)) - { - shader = skin->surfaces[j]->shader; - break; - } - } - } - else if(surface->shaderIndex > 0) - shader = R_GetShaderByHandle( surface->shaderIndex ); - else - shader = tr.defaultShader; - - // we will add shadows even if the main object isn't visible in the view - +/* +================= +R_LoadMDO +================= +*/ +qboolean R_LoadMDO( model_t *mod, void *buffer, int filesize, const char *mod_name ) { + int i, j, k, lodindex; + mdoHeader_t *pinmodel, *mdo; + mdoFrame_t *frame; + mdoLOD_t *lod; + mdoSurface_t *surf; + mdoTriangle_t *tri; + mdoVertex_t *v; + mdoBoneInfo_t *bone; + int *boneRef; + int version; + int size; + shader_t *sh; + int frameSize; + + pinmodel = (mdoHeader_t *)buffer; + + if( Q_strncmp(pinmodel->ident, MDO_IDENT, sizeof(pinmodel->ident) ) ){ // failed + ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has wrong ident (%s should be %s)\n", + mod_name, pinmodel->ident, MDO_IDENT); + } + + version = LittleLong (pinmodel->version); + if (version != MDO_VERSION) { + ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has wrong version (%i should be %i)\n", + mod_name, version, MDO_VERSION); + return qfalse; + } + + mod->type = MOD_MDO; + + size = LittleLong(pinmodel->ofsEnd); + if(size > filesize) + { + ri.Printf(PRINT_WARNING, "R_LoadMDO: Header of %s is broken. Wrong filesize declared!\n", mod_name); + return qfalse; + } + + mod->dataSize += size; + mod->modelData = mdo = ri.Hunk_Alloc( size, h_low ); + + Com_Memcpy( mdo, buffer, LittleLong(pinmodel->ofsEnd) ); + + LL(mdo->version); + LL(mdo->numFrames); + LL(mdo->numBones); + LL(mdo->numLODs); + LL(mdo->ofsFrames); + LL(mdo->ofsLODs); + LL(mdo->ofsEnd); + + if ( mdo->numFrames < 1 ) { + ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has no frames\n", mod_name ); + return qfalse; + } + + if( mdo->numLODs < 1){ + ri.Printf( PRINT_WARNING, "R_LoadMDO: %s has no LODs\n", mod_name ); + return qfalse; + } + + mod->numLods = mdo->numLODs; // ... don't forget this or LODs won't work + + // swap all the frames + frameSize = (int)( &((mdoFrame_t *)0)->bones[ mdo->numBones ] ); + for ( i = 0 ; i < mdo->numFrames ; i++, frame++) { + frame = (mdoFrame_t *) ( (byte *)mdo + mdo->ofsFrames + i * frameSize ); + frame->radius = LittleFloat( frame->radius ); + for ( j = 0 ; j < 3 ; j++ ) { + frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] ); + frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] ); + frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] ); + } + + for ( j = 0 ; j < mdo->numBones * sizeof( mdoBoneComp_t ) / sizeof( short ); j++ ) { + ( (short *)frame->bones )[j] = LittleShort( ( (short *)frame->bones )[j] ); + } + } + + // swap all the bone infos + bone = (mdoBoneInfo_t *) ( (byte *)mdo + mdo->ofsBones ); + for ( i = 0; i < mdo->numBones; i++, bone++ ){ + // lowercase the bone name so name compares are faster + Q_strlwr( bone->name ); + bone->flags = LittleLong(bone->flags); + bone->parent = LittleLong(bone->parent); + } + + // swap all the LOD's + lod = (mdoLOD_t *) ( (byte *)mdo + mdo->ofsLODs ); + for ( lodindex = 0 ; lodindex < mdo->numLODs ; lodindex++ ) { + LL(lod->numSurfaces); + LL(lod->ofsSurfaces); + LL(lod->ofsEnd); + // swap all the surfaces + surf = (mdoSurface_t *) ( (byte *)lod + lod->ofsSurfaces ); + for ( i = 0 ; i < lod->numSurfaces ; i++) { + //LL(surf->ident); + LL(surf->ofsHeader); // don't swap header offset + LL(surf->numTriangles); + LL(surf->ofsTriangles); + LL(surf->numVerts); + LL(surf->ofsVerts); + LL(surf->numBoneRefs); + LL(surf->ofsBoneRefs); + LL(surf->ofsEnd); + + + if ( surf->numVerts > SHADER_MAX_VERTEXES ) { + ri.Error (ERR_DROP, "R_LoadMDO: %s has more than %i verts on a surface (%i)", + mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + } + if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { + ri.Error (ERR_DROP, "R_LoadMDO: %s has more than %i triangles on a surface (%i)", + mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + } + + // change to surface identifier + surf->ident = SF_MDO; + + // lowercase the surface name so skin compares are faster + Q_strlwr( surf->name ); + + // register the shaders + sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue); + if ( sh->defaultShader ) { + surf->shaderIndex = 0; + } else { + surf->shaderIndex = sh->index; + } + + // swap all the vertexes and texcoords + v = (mdoVertex_t *) ( (byte *)surf + surf->ofsVerts); + for ( j = 0 ; j < surf->numVerts ; j++ ) { + v->xyz[0] = LittleFloat( v->xyz[0] ); + v->xyz[1] = LittleFloat( v->xyz[1] ); + v->xyz[2] = LittleFloat( v->xyz[2] ); + + v->texCoords[0] = LittleFloat( v->texCoords[0] ); + v->texCoords[1] = LittleFloat( v->texCoords[1] ); + + v->normal = LittleShort( v->normal ); + // num bone weights + weights[] are bytes + v = (mdoVertex_t *)&v->weights[v->numWeights]; + } + + // swap all the triangles + tri = (mdoTriangle_t *) ( (byte *)surf + surf->ofsTriangles ); + for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) { + LL(tri->indexes[0]); + LL(tri->indexes[1]); + LL(tri->indexes[2]); + } + + // swap all the bone references + boneRef = ( int * )( ( byte *)surf + surf->ofsBoneRefs ); + for ( j = 0; j < surf->numBoneRefs; j++, boneRef++ ){ + *boneRef = LittleLong( *boneRef ); + } + + // find the next surface + surf = (mdoSurface_t *)( (byte *)surf + surf->ofsEnd ); + } + + // find the next LOD + lod = (mdoLOD_t *)( (byte *)lod + lod->ofsEnd ); + } + + return qtrue; +} + +/* +================= +DRAWING CODE +================= +*/ + +/* +============= +R_CullMDO +============= +*/ + +static int R_CullMDO( mdoHeader_t *header, trRefEntity_t *ent ) { + vec3_t bounds[2]; + mdoFrame_t *oldFrame, *newFrame; + int i, frameSize; + + frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); + + // compute frame pointers + newFrame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); + oldFrame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe); + + // cull bounding sphere ONLY if this is not an upscaled entity + if ( !ent->e.nonNormalizedAxes ) + { + if ( ent->e.frame == ent->e.oldframe ) + { + switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) ) + { + + case CULL_OUT: + tr.pc.c_sphere_cull_md3_out++; + return CULL_OUT; + + case CULL_IN: + tr.pc.c_sphere_cull_md3_in++; + return CULL_IN; + + case CULL_CLIP: + tr.pc.c_sphere_cull_md3_clip++; + break; + } + } + else + { + int sphereCull, sphereCullB; + + sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ); + if ( newFrame == oldFrame ) { + sphereCullB = sphereCull; + } else { + sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius ); + } + + if ( sphereCull == sphereCullB ) + { + if ( sphereCull == CULL_OUT ) + { + tr.pc.c_sphere_cull_md3_out++; + return CULL_OUT; + } + else if ( sphereCull == CULL_IN ) + { + tr.pc.c_sphere_cull_md3_in++; + return CULL_IN; + } + else + { + tr.pc.c_sphere_cull_md3_clip++; + } + } + } + } + + // calculate a bounding box in the current coordinate system + for (i = 0 ; i < 3 ; i++) { + bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; + bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; + } + + switch ( R_CullLocalBox( bounds ) ) + { + case CULL_IN: + tr.pc.c_box_cull_md3_in++; + return CULL_IN; + case CULL_CLIP: + tr.pc.c_box_cull_md3_clip++; + return CULL_CLIP; + case CULL_OUT: + default: + tr.pc.c_box_cull_md3_out++; + return CULL_OUT; + } +} + +/* +================= +R_ComputeMDOFogNum + +================= +*/ +int R_ComputeMDOFogNum( mdoHeader_t *header, trRefEntity_t *ent ) { + int i, j; + fog_t *fog; + mdoFrame_t *frame; + vec3_t localOrigin; + int frameSize; + + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return 0; + } + + frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); + + // FIXME: non-normalized axis issues + frame = ( mdoFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); + VectorAdd( ent->e.origin, frame->localOrigin, localOrigin ); + for ( i = 1 ; i < tr.world->numfogs ; i++ ) { + fog = &tr.world->fogs[i]; + for ( j = 0 ; j < 3 ; j++ ) { + if ( localOrigin[j] - frame->radius >= fog->bounds[1][j] ) { + break; + } + if ( localOrigin[j] + frame->radius <= fog->bounds[0][j] ) { + break; + } + } + if ( j == 3 ) { + return i; + } + } + + return 0; +} + +/* +============== +R_AddMDOSurfaces +============== +*/ +void R_AddMDOSurfaces( trRefEntity_t *ent ) { + mdoHeader_t *header; + mdoSurface_t *surface; + mdoLOD_t *lod; + shader_t *shader; + skin_t *skin; + int i, j, k; + int lodnum = 0; + int fogNum = 0; + int cull; + qboolean personalModel; + + header = (mdoHeader_t *) tr.currentModel->modelData; + + personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; + + if ( ent->e.renderfx & RF_WRAP_FRAMES ) + { + ent->e.frame %= header->numFrames; + ent->e.oldframe %= header->numFrames; + } + + // + // Validate the frames so there is no chance of a crash. + // This will write directly into the entity structure, so + // when the surfaces are rendered, they don't need to be + // range checked again. + // + if ((ent->e.frame >= header->numFrames) + || (ent->e.frame < 0) + || (ent->e.oldframe >= header->numFrames) + || (ent->e.oldframe < 0) ) + { + ri.Printf( PRINT_DEVELOPER, "R_AddMDOSurfaces: no such frame %d to %d for '%s'\n", + ent->e.oldframe, ent->e.frame, tr.currentModel->name ); + ent->e.frame = 0; + ent->e.oldframe = 0; + } + + // + // cull the entire model if merged bounding box of both frames + // is outside the view frustum. + // + cull = R_CullMDO (header, ent); + if ( cull == CULL_OUT ) { + return; + } + + // figure out the current LOD of the model we're rendering, and set the lod pointer respectively. + lodnum = R_ComputeLOD(ent); + // check whether this model has as that many LODs at all. If not, try the closest thing we got. + if(header->numLODs <= 0) + return; + if(header->numLODs <= lodnum) + lodnum = header->numLODs - 1; + + lod = (mdoLOD_t *)( (byte *)header + header->ofsLODs); + for(i = 0; i < lodnum; i++) + { + lod = (mdoLOD_t *) ((byte *) lod + lod->ofsEnd); + } + + // set up lighting + if ( !personalModel || r_shadows->integer > 1 ) + { + R_SetupEntityLighting( &tr.refdef, ent ); + } + + // fogNum + fogNum = R_ComputeMDOFogNum( header, ent ); + + surface = (mdoSurface_t *)( (byte *)lod + lod->ofsSurfaces ); + + for ( i = 0 ; i < lod->numSurfaces ; i++ ) + { + + if(ent->e.customShader) + shader = R_GetShaderByHandle(ent->e.customShader); + else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) + { + skin = R_GetSkinByHandle(ent->e.customSkin); + shader = tr.defaultShader; + + for(j = 0; j < skin->numSurfaces; j++) + { + if (!strcmp(skin->surfaces[j]->name, surface->name)) + { + shader = skin->surfaces[j]->shader; + break; + } + } + } + else if(surface->shaderIndex > 0) + shader = R_GetShaderByHandle( surface->shaderIndex ); + else + shader = tr.defaultShader; + + // we will add shadows even if the main object isn't visible in the view + // stencil shadows can't do personal models unless I polyhedron clip if ( !personalModel && r_shadows->integer == 2 @@ -470,299 +470,299 @@ void R_AddMDOSurfaces( trRefEntity_t *ent ) { } if (!personalModel) - R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); - - surface = (mdoSurface_t *)( (byte *)surface + surface->ofsEnd ); - } -} - -/* -================= -ANIMATION -================= -*/ - -void CompBoneToMatrix( const vec4_t quat, vec3_t trans, float matrix[3][4] ) { - float xx = 2.0f * quat[0] * quat[0]; - float yy = 2.0f * quat[1] * quat[1]; - float zz = 2.0f * quat[2] * quat[2]; - float xy = 2.0f * quat[0] * quat[1]; - float xz = 2.0f * quat[0] * quat[2]; - float yz = 2.0f * quat[1] * quat[2]; - float wx = 2.0f * quat[3] * quat[0]; - float wy = 2.0f * quat[3] * quat[1]; - float wz = 2.0f * quat[3] * quat[2]; - - matrix[0][0] = ( 1.0f - ( yy + zz ) ); - matrix[0][1] = ( xy - wz ); - matrix[0][2] = ( xz + wy ); - matrix[0][3] = trans[0]; - - matrix[1][0] = ( xy + wz); - matrix[1][1] = ( 1.0f - ( xx + zz ) ); - matrix[1][2] = ( yz - wx); - matrix[1][3] = trans[1]; - - matrix[2][0] = ( xz - wy ); - matrix[2][1] = ( yz + wx ); - matrix[2][2] = ( 1.0f - ( xx + yy ) ); - matrix[2][3] = trans[2]; -} - -void R_UncompressBone( int boneIndex, mdoFrame_t *frame, float matrix[3][4] ) -{ - mdoBoneComp_t *bone = &frame->bones[boneIndex]; - vec4_t quat; - vec3_t trans; - - - quat[0] = bone->rotQuat[0] * MDO_QUAT_SCALE; - quat[1] = bone->rotQuat[1] * MDO_QUAT_SCALE; - quat[2] = bone->rotQuat[2] * MDO_QUAT_SCALE; - quat[3] = bone->rotQuat[3] * MDO_QUAT_SCALE; - - trans[0] = bone->translation[0] * MDO_TRANSLATION_SCALE; - trans[1] = bone->translation[1] * MDO_TRANSLATION_SCALE; - trans[2] = bone->translation[2] * MDO_TRANSLATION_SCALE; - - CompBoneToMatrix( quat, trans, matrix ); -} - -void Matrix3x4Lerp( float mat1[3][4], float mat2[3][4], float blerp, float out[3][4], qboolean slerp ) -{ - float flerp = 1.0f - blerp; - - out[0][0] = flerp * mat1[0][0] + blerp * mat2[0][0]; - out[0][1] = flerp * mat1[0][1] + blerp * mat2[0][1]; - out[0][2] = flerp * mat1[0][2] + blerp * mat2[0][2]; - out[0][3] = flerp * mat1[0][3] + blerp * mat2[0][3]; - - out[1][0] = flerp * mat1[1][0] + blerp * mat2[1][0]; - out[1][1] = flerp * mat1[1][1] + blerp * mat2[1][1]; - out[1][2] = flerp * mat1[1][2] + blerp * mat2[1][2]; - out[1][3] = flerp * mat1[1][3] + blerp * mat2[1][3]; - - out[2][0] = flerp * mat1[2][0] + blerp * mat2[2][0]; - out[2][1] = flerp * mat1[2][1] + blerp * mat2[2][1]; - out[2][2] = flerp * mat1[2][2] + blerp * mat2[2][2]; - out[2][3] = flerp * mat1[2][3] + blerp * mat2[2][3]; - - if( slerp ){ // unsquash the rotations - VectorNormalize( out[0] ); - VectorNormalize( out[1] ); - VectorNormalize( out[2] ); - } -} - -/* -================ -R_GetMDOTag -================ -*/ -md3Tag_t *R_GetMDOTag( mdoHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) -{ - int i, j, k; - int frameSize; - mdoFrame_t *frame; - mdoBoneInfo_t *bone; - - if ( framenum >= mod->numFrames ) - { - // it is possible to have a bad frame while changing models, so don't error - framenum = mod->numFrames - 1; - } - - bone = (mdoBoneInfo_t *)((byte *)mod + mod->ofsBones); - for ( i = 0; i < mod->numBones; i++, bone++ ) - { - if( !(bone->flags & BFLAG_TAG) ){ - continue; - } - - if ( !strcmp( bone->name, tagName ) ) - { - vec4_t quat; - vec3_t trans; - float matrix[3][4]; - - Q_strncpyz(dest->name, bone->name, sizeof(dest->name)); - - frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ mod->numBones ] ); - frame = (mdoFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); - - R_UncompressBone( i, frame, matrix); - + R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse ); + + surface = (mdoSurface_t *)( (byte *)surface + surface->ofsEnd ); + } +} + +/* +================= +ANIMATION +================= +*/ + +void CompBoneToMatrix( const vec4_t quat, vec3_t trans, float matrix[3][4] ) { + float xx = 2.0f * quat[0] * quat[0]; + float yy = 2.0f * quat[1] * quat[1]; + float zz = 2.0f * quat[2] * quat[2]; + float xy = 2.0f * quat[0] * quat[1]; + float xz = 2.0f * quat[0] * quat[2]; + float yz = 2.0f * quat[1] * quat[2]; + float wx = 2.0f * quat[3] * quat[0]; + float wy = 2.0f * quat[3] * quat[1]; + float wz = 2.0f * quat[3] * quat[2]; + + matrix[0][0] = ( 1.0f - ( yy + zz ) ); + matrix[0][1] = ( xy - wz ); + matrix[0][2] = ( xz + wy ); + matrix[0][3] = trans[0]; + + matrix[1][0] = ( xy + wz); + matrix[1][1] = ( 1.0f - ( xx + zz ) ); + matrix[1][2] = ( yz - wx); + matrix[1][3] = trans[1]; + + matrix[2][0] = ( xz - wy ); + matrix[2][1] = ( yz + wx ); + matrix[2][2] = ( 1.0f - ( xx + yy ) ); + matrix[2][3] = trans[2]; +} + +void R_UncompressBone( int boneIndex, mdoFrame_t *frame, float matrix[3][4] ) +{ + mdoBoneComp_t *bone = &frame->bones[boneIndex]; + vec4_t quat; + vec3_t trans; + + + quat[0] = bone->rotQuat[0] * MDO_QUAT_SCALE; + quat[1] = bone->rotQuat[1] * MDO_QUAT_SCALE; + quat[2] = bone->rotQuat[2] * MDO_QUAT_SCALE; + quat[3] = bone->rotQuat[3] * MDO_QUAT_SCALE; + + trans[0] = bone->translation[0] * MDO_TRANSLATION_SCALE; + trans[1] = bone->translation[1] * MDO_TRANSLATION_SCALE; + trans[2] = bone->translation[2] * MDO_TRANSLATION_SCALE; + + CompBoneToMatrix( quat, trans, matrix ); +} + +void Matrix3x4Lerp( float mat1[3][4], float mat2[3][4], float blerp, float out[3][4], qboolean slerp ) +{ + float flerp = 1.0f - blerp; + + out[0][0] = flerp * mat1[0][0] + blerp * mat2[0][0]; + out[0][1] = flerp * mat1[0][1] + blerp * mat2[0][1]; + out[0][2] = flerp * mat1[0][2] + blerp * mat2[0][2]; + out[0][3] = flerp * mat1[0][3] + blerp * mat2[0][3]; + + out[1][0] = flerp * mat1[1][0] + blerp * mat2[1][0]; + out[1][1] = flerp * mat1[1][1] + blerp * mat2[1][1]; + out[1][2] = flerp * mat1[1][2] + blerp * mat2[1][2]; + out[1][3] = flerp * mat1[1][3] + blerp * mat2[1][3]; + + out[2][0] = flerp * mat1[2][0] + blerp * mat2[2][0]; + out[2][1] = flerp * mat1[2][1] + blerp * mat2[2][1]; + out[2][2] = flerp * mat1[2][2] + blerp * mat2[2][2]; + out[2][3] = flerp * mat1[2][3] + blerp * mat2[2][3]; + + if( slerp ){ // unsquash the rotations + VectorNormalize( out[0] ); + VectorNormalize( out[1] ); + VectorNormalize( out[2] ); + } +} + +/* +================ +R_GetMDOTag +================ +*/ +md3Tag_t *R_GetMDOTag( mdoHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) +{ + int i, j, k; + int frameSize; + mdoFrame_t *frame; + mdoBoneInfo_t *bone; + + if ( framenum >= mod->numFrames ) + { + // it is possible to have a bad frame while changing models, so don't error + framenum = mod->numFrames - 1; + } + + bone = (mdoBoneInfo_t *)((byte *)mod + mod->ofsBones); + for ( i = 0; i < mod->numBones; i++, bone++ ) + { + if( !(bone->flags & BFLAG_TAG) ){ + continue; + } + + if ( !strcmp( bone->name, tagName ) ) + { + vec4_t quat; + vec3_t trans; + float matrix[3][4]; + + Q_strncpyz(dest->name, bone->name, sizeof(dest->name)); + + frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ mod->numBones ] ); + frame = (mdoFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize ); + + R_UncompressBone( i, frame, matrix); + for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++){ dest->axis[j][k] = matrix[k][j]; } dest->origin[j] = matrix[j][3]; - } - - return dest; - } - } - - return NULL; -} - -/* -================ -RB_SurfaceMDO -================ -*/ -#define FTABLESIZE_DIV_256 4 // optimizations, may want to move this right next to the functables -#define FTABLESIZE_DIV_4 256 // and use it for other functions that use them -void RB_SurfaceMDO( mdoSurface_t *surface ) -{ - int i, j, k; - int frameSize; - float frontlerp, backlerp; - int *triangles; - int indexes; - int baseIndex, baseVertex; - int numVerts; - int *boneRefList; - int *boneRef; - mdoVertex_t *v; - mdoHeader_t *header; - mdoFrame_t *frame; - mdoFrame_t *oldFrame; - boneMatrix_t bones[MDO_MAX_BONES], *bonePtr, *bone; - mdoBoneInfo_t *boneInfo; - refEntity_t *ent; - - ent = &backEnd.currentEntity->e; - - // don't lerp if lerping off, or this is the only frame, or the last frame... - // - if (ent->oldframe == ent->frame) - { - backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used - frontlerp = 1; - } - else - { - backlerp = ent->backlerp; - frontlerp = 1.0f - backlerp; - } - - header = (mdoHeader_t *)((byte *)surface - surface->ofsHeader); - - - // - // Set up all triangles. - // - RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 ); - triangles = (int *) ((byte *)surface + surface->ofsTriangles); - indexes = surface->numTriangles * 3; - baseIndex = tess.numIndexes; - baseVertex = tess.numVertexes; - - for (j = 0 ; j < indexes ; j++) - { - tess.indexes[baseIndex + j] = baseVertex + triangles[j]; - } - tess.numIndexes += indexes; - - // - // Setup and lerp all the needed bones - // - frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); - - frame = (mdoFrame_t *)((byte *)header + header->ofsFrames + ent->frame * frameSize ); - oldFrame = (mdoFrame_t *)((byte *)header + header->ofsFrames + ent->oldframe * frameSize ); - - // boneRefs - boneRefList = ( int * )( (byte *)surface + surface->ofsBoneRefs ); - boneRef = boneRefList; - - // boneInfos - boneInfo = (mdoBoneInfo_t *)((byte *)header + header->ofsBones); - - bonePtr = bones; - for( i = 0 ; i < surface->numBoneRefs ; i++, boneRef++ ) - { - - if( !backlerp ){ // no need for cache, animation is simple - R_UncompressBone( *boneRef, frame, bonePtr[*boneRef].matrix ); - }else{ - float mat1[3][4], mat2[3][4]; - R_UncompressBone( *boneRef, frame, mat1 ); - R_UncompressBone( *boneRef, oldFrame, mat2 ); - Matrix3x4Lerp(mat1, mat2, backlerp, bonePtr[*boneRef].matrix, qtrue); - } - } - - // - // deform the vertexes by the lerped bones - // - numVerts = surface->numVerts; - v = (mdoVertex_t *) ((byte *)surface + surface->ofsVerts); - for ( j = 0; j < numVerts; j++ ) - { - vec3_t vertex, normal; - vec3_t unCompNormal; - unsigned int lat, lng; - - VectorClear( vertex ); - VectorClear( normal ); - - // Uncompress the normal - lat = ( v->normal >> 8 ) & 0xff; - lng = ( v->normal & 0xff ); - lat *= (FTABLESIZE_DIV_256); - lng *= (FTABLESIZE_DIV_256); - - unCompNormal[0] = tr.sinTable[(lat+(FTABLESIZE_DIV_4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - unCompNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - unCompNormal[2] = tr.sinTable[(lng+(FTABLESIZE_DIV_4))&FUNCTABLE_MASK]; - - if( !v->numWeights || !header->numBones ){ // static model, or un weighted vertex - vertex[0] = v->xyz[0]; - vertex[1] = v->xyz[1]; - vertex[2] = v->xyz[2]; - - normal[0] = unCompNormal[0]; - normal[1] = unCompNormal[1]; - normal[2] = unCompNormal[2]; - - VectorNormalizeFast(normal); // ensure a normalized normal - }else{ - mdoWeight_t *w; - w = v->weights; - for( k = 0; k < v->numWeights; k++, w++ ){ - float fWeight = w->boneWeight * MDO_BYTE_WEIGHT_SCALE; - int boneIndex = w->boneIndex; - - bone = bonePtr + boneIndex; - // Transform the vert and normal - vertex[0] += fWeight * ( DotProduct( bone->matrix[0], v->xyz ) + bone->matrix[0][3] ); - vertex[1] += fWeight * ( DotProduct( bone->matrix[1], v->xyz ) + bone->matrix[1][3] ); - vertex[2] += fWeight * ( DotProduct( bone->matrix[2], v->xyz ) + bone->matrix[2][3] ); - - normal[0] += fWeight * DotProduct( bone->matrix[0], unCompNormal ); - normal[1] += fWeight * DotProduct( bone->matrix[1], unCompNormal ); - normal[2] += fWeight * DotProduct( bone->matrix[2], unCompNormal ); - } - VectorNormalizeFast(normal); // ensure a normalized normal - } - - tess.xyz[baseVertex + j][0] = vertex[0]; - tess.xyz[baseVertex + j][1] = vertex[1]; - tess.xyz[baseVertex + j][2] = vertex[2]; - - tess.normal[baseVertex + j][0] = normal[0]; - tess.normal[baseVertex + j][1] = normal[1]; - tess.normal[baseVertex + j][2] = normal[2]; - - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; - - v = (mdoVertex_t *)&v->weights[v->numWeights]; - } - - tess.numVertexes += surface->numVerts; -} - + } + + return dest; + } + } + + return NULL; +} + +/* +================ +RB_SurfaceMDO +================ +*/ +#define FTABLESIZE_DIV_256 4 // optimizations, may want to move this right next to the functables +#define FTABLESIZE_DIV_4 256 // and use it for other functions that use them +void RB_SurfaceMDO( mdoSurface_t *surface ) +{ + int i, j, k; + int frameSize; + float frontlerp, backlerp; + int *triangles; + int indexes; + int baseIndex, baseVertex; + int numVerts; + int *boneRefList; + int *boneRef; + mdoVertex_t *v; + mdoHeader_t *header; + mdoFrame_t *frame; + mdoFrame_t *oldFrame; + boneMatrix_t bones[MDO_MAX_BONES], *bonePtr, *bone; + mdoBoneInfo_t *boneInfo; + refEntity_t *ent; + + ent = &backEnd.currentEntity->e; + + // don't lerp if lerping off, or this is the only frame, or the last frame... + // + if (ent->oldframe == ent->frame) + { + backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used + frontlerp = 1; + } + else + { + backlerp = ent->backlerp; + frontlerp = 1.0f - backlerp; + } + + header = (mdoHeader_t *)((byte *)surface - surface->ofsHeader); + + + // + // Set up all triangles. + // + RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 ); + triangles = (int *) ((byte *)surface + surface->ofsTriangles); + indexes = surface->numTriangles * 3; + baseIndex = tess.numIndexes; + baseVertex = tess.numVertexes; + + for (j = 0 ; j < indexes ; j++) + { + tess.indexes[baseIndex + j] = baseVertex + triangles[j]; + } + tess.numIndexes += indexes; + + // + // Setup and lerp all the needed bones + // + frameSize = (size_t)( &((mdoFrame_t *)0)->bones[ header->numBones ] ); + + frame = (mdoFrame_t *)((byte *)header + header->ofsFrames + ent->frame * frameSize ); + oldFrame = (mdoFrame_t *)((byte *)header + header->ofsFrames + ent->oldframe * frameSize ); + + // boneRefs + boneRefList = ( int * )( (byte *)surface + surface->ofsBoneRefs ); + boneRef = boneRefList; + + // boneInfos + boneInfo = (mdoBoneInfo_t *)((byte *)header + header->ofsBones); + + bonePtr = bones; + for( i = 0 ; i < surface->numBoneRefs ; i++, boneRef++ ) + { + + if( !backlerp ){ // no need for cache, animation is simple + R_UncompressBone( *boneRef, frame, bonePtr[*boneRef].matrix ); + }else{ + float mat1[3][4], mat2[3][4]; + R_UncompressBone( *boneRef, frame, mat1 ); + R_UncompressBone( *boneRef, oldFrame, mat2 ); + Matrix3x4Lerp(mat1, mat2, backlerp, bonePtr[*boneRef].matrix, qtrue); + } + } + + // + // deform the vertexes by the lerped bones + // + numVerts = surface->numVerts; + v = (mdoVertex_t *) ((byte *)surface + surface->ofsVerts); + for ( j = 0; j < numVerts; j++ ) + { + vec3_t vertex, normal; + vec3_t unCompNormal; + unsigned int lat, lng; + + VectorClear( vertex ); + VectorClear( normal ); + + // Uncompress the normal + lat = ( v->normal >> 8 ) & 0xff; + lng = ( v->normal & 0xff ); + lat *= (FTABLESIZE_DIV_256); + lng *= (FTABLESIZE_DIV_256); + + unCompNormal[0] = tr.sinTable[(lat+(FTABLESIZE_DIV_4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + unCompNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + unCompNormal[2] = tr.sinTable[(lng+(FTABLESIZE_DIV_4))&FUNCTABLE_MASK]; + + if( !v->numWeights || !header->numBones ){ // static model, or un weighted vertex + vertex[0] = v->xyz[0]; + vertex[1] = v->xyz[1]; + vertex[2] = v->xyz[2]; + + normal[0] = unCompNormal[0]; + normal[1] = unCompNormal[1]; + normal[2] = unCompNormal[2]; + + VectorNormalizeFast(normal); // ensure a normalized normal + }else{ + mdoWeight_t *w; + w = v->weights; + for( k = 0; k < v->numWeights; k++, w++ ){ + float fWeight = w->boneWeight * MDO_BYTE_WEIGHT_SCALE; + int boneIndex = w->boneIndex; + + bone = bonePtr + boneIndex; + // Transform the vert and normal + vertex[0] += fWeight * ( DotProduct( bone->matrix[0], v->xyz ) + bone->matrix[0][3] ); + vertex[1] += fWeight * ( DotProduct( bone->matrix[1], v->xyz ) + bone->matrix[1][3] ); + vertex[2] += fWeight * ( DotProduct( bone->matrix[2], v->xyz ) + bone->matrix[2][3] ); + + normal[0] += fWeight * DotProduct( bone->matrix[0], unCompNormal ); + normal[1] += fWeight * DotProduct( bone->matrix[1], unCompNormal ); + normal[2] += fWeight * DotProduct( bone->matrix[2], unCompNormal ); + } + VectorNormalizeFast(normal); // ensure a normalized normal + } + + tess.xyz[baseVertex + j][0] = vertex[0]; + tess.xyz[baseVertex + j][1] = vertex[1]; + tess.xyz[baseVertex + j][2] = vertex[2]; + + tess.normal[baseVertex + j][0] = normal[0]; + tess.normal[baseVertex + j][1] = normal[1]; + tess.normal[baseVertex + j][2] = normal[2]; + + tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; + tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; + + v = (mdoVertex_t *)&v->weights[v->numWeights]; + } + + tess.numVertexes += surface->numVerts; +} +