1 //********************************************************************************************
2 //*
3 //*    This file is part of Egoboo.
4 //*
5 //*    Egoboo is free software: you can redistribute it and/or modify it
6 //*    under the terms of the GNU General Public License as published by
7 //*    the Free Software Foundation, either version 3 of the License, or
8 //*    (at your option) any later version.
9 //*
10 //*    Egoboo is distributed in the hope that it will be useful, but
11 //*    WITHOUT ANY WARRANTY; without even the implied warranty of
12 //*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //*    General Public License for more details.
14 //*
15 //*    You should have received a copy of the GNU General Public License
16 //*    along with Egoboo.  If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19 
20 /// @file graphic_mad.c
21 /// @brief Character model drawing code.
22 /// @details
23 
24 #include "graphic_mad.h"
25 
26 #include "profile.inl"
27 #include "char.inl"
28 #include "mad.h"
29 
30 #include "md2.inl"
31 #include "id_md2.h"
32 
33 #include "log.h"
34 #include "camera.h"
35 #include "game.h"
36 #include "input.h"
37 #include "texture.h"
38 #include "lighting.h"
39 
40 #include "egoboo_setup.h"
41 #include "egoboo.h"
42 
43 #include <SDL_opengl.h>
44 
45 //--------------------------------------------------------------------------------------------
46 //--------------------------------------------------------------------------------------------
47 
48 // the flip tolerance is the default flip increment / 2
49 static const float flip_tolerance = 0.25f * 0.5f;
50 
51 //--------------------------------------------------------------------------------------------
52 //--------------------------------------------------------------------------------------------
53 
54 static void draw_chr_verts( chr_t * pchr, int vrt_offset, int verts );
55 static void _draw_one_grip_raw( chr_instance_t * pinst, mad_t * pmad, int slot );
56 static void draw_one_grip( chr_instance_t * pinst, mad_t * pmad, int slot );
57 static void draw_chr_grips( chr_t * pchr );
58 static void draw_chr_attached_grip( chr_t * pchr );
59 static void draw_chr_bbox( chr_t * pchr );
60 
61 // these functions are only called by render_one_mad()
62 static gfx_rv render_one_mad_enviro( const CHR_REF ichr, GLXvector4f tint, Uint32 bits );
63 static gfx_rv render_one_mad_tex( const CHR_REF ichr, GLXvector4f tint, Uint32 bits );
64 
65 // private chr_instance_t methods
66 static gfx_rv chr_instance_alloc( chr_instance_t * pinst, size_t vlst_size );
67 static gfx_rv chr_instance_free( chr_instance_t * pinst );
68 static gfx_rv chr_instance_update_vlst_cache( chr_instance_t * pinst, int vmax, int vmin, bool_t force, bool_t vertices_match, bool_t frames_match );
69 static gfx_rv chr_instance_needs_update( chr_instance_t * pinst, int vmin, int vmax, bool_t *verts_match, bool_t *frames_match );
70 static gfx_rv chr_instance_set_frame( chr_instance_t * pinst, int frame );
71 static void   chr_instance_clear_cache( chr_instance_t * pinst );
72 
73 // private vlst_cache_t methods
74 vlst_cache_t * vlst_cache_init( vlst_cache_t * );
75 gfx_rv         vlst_cache_test( vlst_cache_t *, chr_instance_t * );
76 
77 // private chr_reflection_cache_t methods
78 chr_reflection_cache_t * chr_reflection_cache_init( chr_reflection_cache_t * pcache );
79 
80 // private matrix_cache_t methods
81 matrix_cache_t * matrix_cache_init( matrix_cache_t * mcache );
82 
83 //--------------------------------------------------------------------------------------------
84 //--------------------------------------------------------------------------------------------
render_one_mad_enviro(const CHR_REF character,GLXvector4f tint,Uint32 bits)85 gfx_rv render_one_mad_enviro( const CHR_REF character, GLXvector4f tint, Uint32 bits )
86 {
87     /// @details ZZ@> This function draws an environment mapped model
88 
89     GLint matrix_mode[1];
90     Uint16 cnt;
91     Uint16 vertex;
92     float  uoffset, voffset;
93 
94     chr_t          * pchr;
95     mad_t          * pmad;
96     MD2_Model_t    * pmd2;
97     chr_instance_t * pinst;
98     oglx_texture_t   * ptex;
99 
100     if ( !INGAME_CHR( character ) )
101     {
102         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, character, "invalid character" );
103         return gfx_error;
104     }
105     pchr  = ChrList.lst + character;
106     pinst = &( pchr->inst );
107 
108     if ( !LOADED_MAD( pinst->imad ) )
109     {
110         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
111         return gfx_error;
112     }
113     pmad = MadStack.lst + pinst->imad;
114 
115     if ( NULL == pmad->md2_ptr )
116     {
117         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL md2" );
118         return gfx_error;
119     }
120     pmd2 = pmad->md2_ptr;
121 
122     ptex = NULL;
123     if ( HAS_SOME_BITS( bits, CHR_PHONG ) )
124     {
125         ptex = TxTexture_get_ptr(( TX_REF )TX_PHONG );
126     }
127 
128     if ( !GL_DEBUG( glIsEnabled )( GL_BLEND ) )
129     {
130         return gfx_fail;
131     }
132 
133     if ( NULL == ptex )
134     {
135         ptex = TxTexture_get_ptr( pinst->texture );
136     }
137 
138     uoffset = pinst->uoffset - PCamera->turn_z_one;
139     voffset = pinst->voffset;
140 
141     // save the matrix mode
142     GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
143 
144     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
145     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
146     GL_DEBUG( glPushMatrix )();
147 
148     if ( HAS_SOME_BITS( bits, CHR_REFLECT ) )
149     {
150         GL_DEBUG( glMultMatrixf )( pinst->ref.matrix.v );
151     }
152     else
153     {
154         GL_DEBUG( glMultMatrixf )( pinst->matrix.v );
155     }
156 
157     // Choose texture and matrix
158     oglx_texture_Bind( ptex );
159 
160     ATTRIB_PUSH( __FUNCTION__, GL_CURRENT_BIT );
161     {
162         int cmd_count;
163         MD2_GLCommand_t * glcommand;
164 
165         GLXvector4f curr_color;
166 
167         GL_DEBUG( glGetFloatv )( GL_CURRENT_COLOR, curr_color );
168 
169         // Render each command
170         cmd_count   = md2_get_numCommands( pmd2 );
171         glcommand   = ( MD2_GLCommand_t * )md2_get_Commands( pmd2 );
172 
173         for ( cnt = 0; cnt < cmd_count && NULL != glcommand; cnt++ )
174         {
175             int count = glcommand->command_count;
176 
177             GL_DEBUG( glBegin )( glcommand->gl_mode );
178             {
179                 int tnc;
180 
181                 for ( tnc = 0; tnc < count; tnc++ )
182                 {
183                     GLfloat     cmax;
184                     GLXvector4f col;
185                     GLfloat     tex[2];
186                     GLvertex   *pvrt;
187 
188                     vertex = glcommand->data[tnc].index;
189                     if ( vertex >= pinst->vrt_count ) continue;
190 
191                     pvrt   = pinst->vrt_lst + vertex;
192 
193                     // normalize the color so it can be modulated by the phong/environment map
194                     col[RR] = pvrt->color_dir * INV_FF;
195                     col[GG] = pvrt->color_dir * INV_FF;
196                     col[BB] = pvrt->color_dir * INV_FF;
197                     col[AA] = 1.0f;
198 
199                     cmax = MAX( MAX( col[RR], col[GG] ), col[BB] );
200 
201                     if ( cmax != 0.0f )
202                     {
203                         col[RR] /= cmax;
204                         col[GG] /= cmax;
205                         col[BB] /= cmax;
206                     }
207 
208                     // apply the tint
209                     col[RR] *= tint[RR] * curr_color[RR];
210                     col[GG] *= tint[GG] * curr_color[GG];
211                     col[BB] *= tint[BB] * curr_color[BB];
212                     col[AA] *= tint[AA] * curr_color[AA];
213 
214                     tex[0] = pvrt->env[XX] + uoffset;
215                     tex[1] = CLIP( cmax, 0.0f, 1.0f );
216 
217                     if ( 0 != ( bits & CHR_PHONG ) )
218                     {
219                         // determine the phong texture coordinates
220                         // the default phong is bright in both the forward and back directions...
221                         tex[1] = tex[1] * 0.5f + 0.5f;
222                     }
223 
224                     GL_DEBUG( glColor4fv )( col );
225                     GL_DEBUG( glNormal3fv )( pvrt->nrm );
226                     GL_DEBUG( glTexCoord2fv )( tex );
227                     GL_DEBUG( glVertex3fv )( pvrt->pos );
228                 }
229 
230             }
231             GL_DEBUG_END();
232 
233             glcommand = glcommand->next;
234         }
235     }
236     ATTRIB_POP( __FUNCTION__ );
237 
238     // Restore the GL_MODELVIEW matrix
239     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
240     GL_DEBUG( glPopMatrix )();
241 
242     // restore the matrix mode
243     GL_DEBUG( glMatrixMode )( matrix_mode[0] );
244 
245     return gfx_success;
246 }
247 
248 // Do fog...
249 /*
250 if(fogon && pinst->light==255)
251 {
252     // The full fog value
253     alpha = 0xff000000 | (fogred<<16) | (foggrn<<8) | (fogblu);
254 
255     for (cnt = 0; cnt < pmad->transvertices; cnt++)
256     {
257         // Figure out the z position of the vertex...  Not totally accurate
258         z = (pinst->vrt_lst[cnt].pos[ZZ]) + pchr->matrix(3,2);
259 
260         // Figure out the fog coloring
261         if(z < fogtop)
262         {
263             if(z < fogbottom)
264             {
265                 pinst->vrt_lst[cnt].specular = alpha;
266             }
267             else
268             {
269                 z = 1.0f - ((z - fogbottom)/fogdistance);  // 0.0f to 1.0f...  Amount of fog to keep
270                 red = fogred * z;
271                 grn = foggrn * z;
272                 blu = fogblu * z;
273                 fogspec = 0xff000000 | (red<<16) | (grn<<8) | (blu);
274                 pinst->vrt_lst[cnt].specular = fogspec;
275             }
276         }
277         else
278         {
279             pinst->vrt_lst[cnt].specular = 0;
280         }
281     }
282 }
283 else
284 {
285     for (cnt = 0; cnt < pmad->transvertices; cnt++)
286         pinst->vrt_lst[cnt].specular = 0;
287 }
288 */
289 
290 //--------------------------------------------------------------------------------------------
render_one_mad_tex(const CHR_REF character,GLXvector4f tint,Uint32 bits)291 gfx_rv render_one_mad_tex( const CHR_REF character, GLXvector4f tint, Uint32 bits )
292 {
293     /// @details ZZ@> This function draws a model
294 
295     GLint matrix_mode[1];
296 
297     int    cmd_count;
298     int    cnt;
299     Uint16 vertex;
300     float  uoffset, voffset;
301 
302     chr_t          * pchr;
303     mad_t          * pmad;
304     MD2_Model_t    * pmd2;
305     chr_instance_t * pinst;
306     oglx_texture_t   * ptex;
307 
308     if ( !INGAME_CHR( character ) )
309     {
310         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, character, "invalid character" );
311         return gfx_error;
312     }
313     pchr  = ChrList.lst + character;
314     pinst = &( pchr->inst );
315 
316     if ( !LOADED_MAD( pinst->imad ) )
317     {
318         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
319         return gfx_error;
320     }
321     pmad = MadStack.lst + pinst->imad;
322 
323     if ( NULL == pmad->md2_ptr )
324     {
325         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL md2" );
326         return gfx_error;
327     }
328     pmd2 = pmad->md2_ptr;
329 
330     // To make life easier
331     ptex = TxTexture_get_ptr( pinst->texture );
332 
333     uoffset = pinst->uoffset * INV_FFFF;
334     voffset = pinst->voffset * INV_FFFF;
335 
336     // save the matrix mode
337     GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
338 
339     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
340     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
341     GL_DEBUG( glPushMatrix )();
342 
343     if ( 0 != ( bits & CHR_REFLECT ) )
344     {
345         GL_DEBUG( glMultMatrixf )( pinst->ref.matrix.v );
346     }
347     else
348     {
349         GL_DEBUG( glMultMatrixf )( pinst->matrix.v );
350     }
351 
352     // Choose texture and matrix
353     oglx_texture_Bind( ptex );
354 
355     ATTRIB_PUSH( __FUNCTION__, GL_CURRENT_BIT );
356     {
357         float             base_amb;
358         MD2_GLCommand_t * glcommand;
359 
360         // set the basic tint. if the object is marked with CHR_LIGHT
361         // the color will not be set again inside the loop
362         GL_DEBUG( glColor4fv )( tint );
363 
364         base_amb = 0.0f;
365         if ( 0 == ( bits & CHR_LIGHT ) )
366         {
367             // convert the "light" parameter to self-lighting for
368             // every object that is not being rendered using CHR_LIGHT
369             base_amb   = ( 255 == pinst->light ) ? 0 : ( pinst->light * INV_FF );
370         }
371 
372         // Render each command
373         cmd_count   = md2_get_numCommands( pmd2 );
374         glcommand   = ( MD2_GLCommand_t * )md2_get_Commands( pmd2 );
375 
376         for ( cnt = 0; cnt < cmd_count && NULL != glcommand; cnt++ )
377         {
378             int count = glcommand->command_count;
379 
380             GL_DEBUG( glBegin )( glcommand->gl_mode );
381             {
382                 int tnc;
383 
384                 for ( tnc = 0; tnc < count; tnc++ )
385                 {
386                     GLXvector2f tex;
387                     GLvertex * pvrt;
388 
389                     vertex = glcommand->data[tnc].index;
390                     if ( vertex >= pinst->vrt_count ) continue;
391 
392                     pvrt = pinst->vrt_lst + vertex;
393 
394                     // determine the texture coordinates
395                     tex[0] = glcommand->data[tnc].s + uoffset;
396                     tex[1] = glcommand->data[tnc].t + voffset;
397 
398                     // no per-vertex lighting for CHR_LIGHT objects
399                     if ( HAS_NO_BITS( bits, CHR_LIGHT ) )
400                     {
401                         GLXvector4f col;
402 
403                         float fcol;
404 
405                         // the directional lighting
406                         fcol   = pvrt->color_dir * INV_FF;
407 
408                         col[RR] = fcol;
409                         col[GG] = fcol;
410                         col[BB] = fcol;
411                         col[AA] = 1.0f;
412 
413                         // ambient lighting
414                         if ( HAS_NO_BITS( bits, CHR_PHONG ) )
415                         {
416                             // convert the "light" parameter to self-lighting for
417                             // every object that is not being rendered using CHR_LIGHT
418 
419                             float acol = base_amb + pinst->color_amb * INV_FF;
420 
421                             col[0] += acol;
422                             col[1] += acol;
423                             col[2] += acol;
424                         }
425 
426                         // clip the colors
427                         col[0] = CLIP( col[0], 0.0f, 1.0f );
428                         col[1] = CLIP( col[1], 0.0f, 1.0f );
429                         col[2] = CLIP( col[2], 0.0f, 1.0f );
430 
431                         // tint the object
432                         col[0] *= tint[RR];
433                         col[1] *= tint[GG];
434                         col[2] *= tint[BB];
435 
436                         GL_DEBUG( glColor4fv )( col );
437                     }
438 
439                     GL_DEBUG( glNormal3fv )( pvrt->nrm );
440                     GL_DEBUG( glTexCoord2fv )( tex );
441                     GL_DEBUG( glVertex3fv )( pvrt->pos );
442                 }
443             }
444             GL_DEBUG_END();
445 
446             glcommand = glcommand->next;
447         }
448     }
449     ATTRIB_POP( __FUNCTION__ );
450 
451     // Restore the GL_MODELVIEW matrix
452     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
453     GL_DEBUG( glPopMatrix )();
454 
455     // restore the matrix mode
456     GL_DEBUG( glMatrixMode )( matrix_mode[0] );
457 
458     return gfx_success;
459 }
460 
461 /*
462     // Do fog...
463     if(fogon && pinst->light==255)
464     {
465         // The full fog value
466         alpha = 0xff000000 | (fogred<<16) | (foggrn<<8) | (fogblu);
467 
468         for (cnt = 0; cnt < pmad->transvertices; cnt++)
469         {
470             // Figure out the z position of the vertex...  Not totally accurate
471             z = (pinst->vrt_lst[cnt].pos[ZZ]) + pchr->matrix(3,2);
472 
473             // Figure out the fog coloring
474             if(z < fogtop)
475             {
476                 if(z < fogbottom)
477                 {
478                     pinst->vrt_lst[cnt].specular = alpha;
479                 }
480                 else
481                 {
482                     spek = pinst->vrt_lst[cnt].specular & 255;
483                     z = (z - fogbottom)/fogdistance;  // 0.0f to 1.0f...  Amount of old to keep
484                     fogtokeep = 1.0f-z;  // 0.0f to 1.0f...  Amount of fog to keep
485                     spek = spek * z;
486                     red = (fogred * fogtokeep) + spek;
487                     grn = (foggrn * fogtokeep) + spek;
488                     blu = (fogblu * fogtokeep) + spek;
489                     fogspec = 0xff000000 | (red<<16) | (grn<<8) | (blu);
490                     pinst->vrt_lst[cnt].specular = fogspec;
491                 }
492             }
493         }
494     }
495 */
496 
497 //--------------------------------------------------------------------------------------------
render_one_mad(const CHR_REF character,GLXvector4f tint,BIT_FIELD bits)498 gfx_rv render_one_mad( const CHR_REF character, GLXvector4f tint, BIT_FIELD bits )
499 {
500     /// @details ZZ@> This function picks the actual function to use
501 
502     chr_t * pchr;
503     gfx_rv retval;
504 
505     if ( !INGAME_CHR( character ) )
506     {
507         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, character, "invalid character" );
508         return gfx_error;
509     }
510     pchr = ChrList.lst + character;
511 
512     if ( pchr->is_hidden ) return gfx_fail;
513 
514     if ( pchr->inst.enviro || HAS_SOME_BITS( bits, CHR_PHONG ) )
515     {
516         retval = render_one_mad_enviro( character, tint, bits );
517     }
518     else
519     {
520         retval = render_one_mad_tex( character, tint, bits );
521     }
522 
523 #if defined(DRAW_CHR_BBOX)
524     // don't draw the debug stuff for reflections
525     if ( 0 == ( bits & CHR_REFLECT ) )
526     {
527         draw_chr_bbox( pchr );
528     }
529 
530     // the grips of all objects
531     //draw_chr_attached_grip( pchr );
532 
533     // draw all the vertices of an object
534     //GL_DEBUG( glPointSize( 5 ) );
535     //draw_chr_verts( pchr, 0, pro_get_pmad(pchr->inst.imad)->md2_data.vertex_lst );
536 #endif
537 
538     return retval;
539 }
540 
541 //--------------------------------------------------------------------------------------------
render_one_mad_ref(const CHR_REF ichr)542 gfx_rv render_one_mad_ref( const CHR_REF ichr )
543 {
544     /// @details ZZ@> This function draws characters reflected in the floor
545 
546     chr_t * pchr;
547     chr_instance_t * pinst;
548     GLXvector4f tint;
549     gfx_rv retval;
550 
551     if ( !INGAME_CHR( ichr ) )
552     {
553         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, ichr, "invalid character" );
554         return gfx_error;
555     }
556     pchr = ChrList.lst + ichr;
557     pinst = &( pchr->inst );
558 
559     if ( pchr->is_hidden ) return gfx_fail;
560 
561     // assume the best
562     retval = gfx_success;
563 
564     if ( !pinst->ref.matrix_valid )
565     {
566         if ( !apply_reflection_matrix( &( pchr->inst ), pchr->enviro.grid_level ) )
567         {
568             return gfx_error;
569         }
570     }
571 
572     ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_POLYGON_BIT | GL_COLOR_BUFFER_BIT );
573     {
574         // cull backward facing polygons
575         GL_DEBUG( glEnable )( GL_CULL_FACE );  // GL_ENABLE_BIT
576 
577         // cull face CCW because we are rendering a reflected object
578         GL_DEBUG( glFrontFace )( GL_CCW );    // GL_POLYGON_BIT
579 
580         if ( pinst->ref.alpha != 255 && pinst->ref.light == 255 )
581         {
582             GL_DEBUG( glEnable )( GL_BLEND );                                 // GL_ENABLE_BIT
583             GL_DEBUG( glBlendFunc )( GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA );                        // GL_COLOR_BUFFER_BIT
584 
585             chr_instance_get_tint( pinst, tint, CHR_ALPHA | CHR_REFLECT );
586 
587             // the previous call to chr_instance_update_lighting_ref() has actually set the
588             // alpha and light for all vertices
589             if ( gfx_error == render_one_mad( ichr, tint, CHR_ALPHA | CHR_REFLECT ) )
590             {
591                 retval = gfx_error;
592             }
593         }
594 
595         if ( pinst->ref.light != 255 )
596         {
597             GL_DEBUG( glEnable )( GL_BLEND );                                 // GL_ENABLE_BIT
598             GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE );                        // GL_COLOR_BUFFER_BIT
599 
600             chr_instance_get_tint( pinst, tint, CHR_LIGHT | CHR_REFLECT );
601 
602             // the previous call to chr_instance_update_lighting_ref() has actually set the
603             // alpha and light for all vertices
604             if ( gfx_error == render_one_mad( ichr, tint, CHR_LIGHT | CHR_REFLECT ) )
605             {
606                 retval = gfx_error;
607             }
608         }
609 
610         if ( gfx.phongon && pinst->sheen > 0 )
611         {
612             GL_DEBUG( glEnable )( GL_BLEND );
613             GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE );
614 
615             chr_instance_get_tint( pinst, tint, CHR_PHONG | CHR_REFLECT );
616 
617             if ( gfx_error == render_one_mad( ichr, tint, CHR_PHONG | CHR_REFLECT ) )
618             {
619                 retval = gfx_error;
620             }
621         }
622     }
623     ATTRIB_POP( __FUNCTION__ );
624 
625     return retval;
626 }
627 
628 //--------------------------------------------------------------------------------------------
render_one_mad_trans(const CHR_REF ichr)629 gfx_rv render_one_mad_trans( const CHR_REF ichr )
630 {
631     /// @details ZZ@> This function dispatches the rendering of transparent characters
632     ///               to the correct function. (this does not handle characer reflection)
633 
634     chr_t * pchr;
635     chr_instance_t * pinst;
636     GLXvector4f tint;
637     bool_t rendered;
638 
639     if ( !INGAME_CHR( ichr ) )
640     {
641         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, ichr, "invalid character" );
642         return gfx_error;
643     }
644     pchr = ChrList.lst + ichr;
645     pinst = &( pchr->inst );
646 
647     if ( pchr->is_hidden ) return gfx_fail;
648 
649     // there is an outside chance the object will not be rendered
650     rendered = bfalse;
651 
652     ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_POLYGON_BIT | GL_COLOR_BUFFER_BIT )
653     {
654         if ( pinst->alpha < 255 && 255 == pinst->light )
655         {
656             // most alpha effects will be messed up by
657             // skipping backface culling, so don't
658             GL_DEBUG( glEnable )( GL_CULL_FACE );         // GL_ENABLE_BIT
659             GL_DEBUG( glFrontFace )( GL_CW );             // GL_POLYGON_BIT
660 
661             // get a speed-up by not displaying completely transparent portions of the skin
662             GL_DEBUG( glEnable )( GL_ALPHA_TEST );                                // GL_ENABLE_BIT
663             GL_DEBUG( glAlphaFunc )( GL_GREATER, 0.0f );                             // GL_COLOR_BUFFER_BIT
664 
665             GL_DEBUG( glEnable )( GL_BLEND );                                     // GL_ENABLE_BIT
666             GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );      // GL_COLOR_BUFFER_BIT
667 
668             chr_instance_get_tint( pinst, tint, CHR_ALPHA );
669 
670             if ( render_one_mad( ichr, tint, CHR_ALPHA ) )
671             {
672                 rendered = btrue;
673             }
674         }
675         if ( pinst->light < 255 )
676         {
677             // light effects should show through transparent objects
678             GL_DEBUG( glDisable )( GL_CULL_FACE );         // GL_ENABLE_BIT
679 
680             // the alpha test can only mess us up here
681             GL_DEBUG( glDisable )( GL_ALPHA_TEST );     // GL_ENABLE_BIT
682 
683             GL_DEBUG( glEnable )( GL_BLEND );           // GL_ENABLE_BIT
684             GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE );  // GL_COLOR_BUFFER_BIT
685 
686             chr_instance_get_tint( pinst, tint, CHR_LIGHT );
687 
688             if ( render_one_mad( ichr, tint, CHR_LIGHT ) )
689             {
690                 rendered = btrue;
691             }
692         }
693 
694         if ( gfx.phongon && pinst->sheen > 0 )
695         {
696             GL_DEBUG( glEnable )( GL_BLEND );             // GL_ENABLE_BIT
697             GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE );    // GL_COLOR_BUFFER_BIT
698 
699             chr_instance_get_tint( pinst, tint, CHR_PHONG );
700 
701             if ( render_one_mad( ichr, tint, CHR_PHONG ) )
702             {
703                 rendered = btrue;
704             }
705         }
706     }
707     ATTRIB_POP( __FUNCTION__ );
708 
709     return rendered ? gfx_success : gfx_fail;
710 }
711 
712 //--------------------------------------------------------------------------------------------
render_one_mad_solid(const CHR_REF ichr)713 gfx_rv render_one_mad_solid( const CHR_REF ichr )
714 {
715     chr_t * pchr;
716     chr_instance_t * pinst;
717     gfx_rv retval = gfx_error;
718 
719     if ( !INGAME_CHR( ichr ) )
720     {
721         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, ichr, "invalid character" );
722         return gfx_error;
723     }
724     pchr = ChrList.lst + ichr;
725     pinst = &( pchr->inst );
726 
727     if ( pchr->is_hidden ) return gfx_fail;
728 
729     // assume the best
730     retval = gfx_success;
731 
732     ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT );
733     {
734         // do not display the completely transparent portion
735         // this allows characters that have "holes" in their
736         // textures to display the solid portions properly
737         //
738         // Objects with partially transparent skins should enable the [MODL] parameter "T"
739         // which will enable the display of the partially transparent portion of the skin
740 
741         GL_DEBUG( glEnable )( GL_ALPHA_TEST );                 // GL_ENABLE_BIT
742         GL_DEBUG( glAlphaFunc )( GL_EQUAL, 1.0f );             // GL_COLOR_BUFFER_BIT
743 
744         // can I turn this off?
745         GL_DEBUG( glEnable )( GL_BLEND );                     // GL_ENABLE_BIT
746         GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );   // GL_COLOR_BUFFER_BIT
747 
748         if ( 255 == pinst->alpha && 255 == pinst->light )
749         {
750             GLXvector4f tint;
751 
752             // allow the dont_cull_backfaces to keep solid objects from culling backfaces
753             if ( pinst->dont_cull_backfaces )
754             {
755                 GL_DEBUG( glDisable )( GL_CULL_FACE );         // GL_ENABLE_BIT
756             }
757             else
758             {
759                 GL_DEBUG( glEnable )( GL_CULL_FACE );         // GL_ENABLE_BIT
760                 GL_DEBUG( glFrontFace )( GL_CW );             // GL_POLYGON_BIT
761             }
762 
763             chr_instance_get_tint( pinst, tint, CHR_SOLID );
764 
765             if ( gfx_error == render_one_mad( ichr, tint, CHR_SOLID ) )
766             {
767                 retval = gfx_error;
768             }
769         }
770     }
771     ATTRIB_POP( __FUNCTION__ );
772 
773     return retval;
774 }
775 
776 //--------------------------------------------------------------------------------------------
777 //--------------------------------------------------------------------------------------------
draw_chr_bbox(chr_t * pchr)778 void draw_chr_bbox( chr_t * pchr )
779 {
780     if ( !ACTIVE_PCHR( pchr ) ) return;
781 
782     // draw the object bounding box as a part of the graphics debug mode F7
783     if ( cfg.dev_mode && SDLKEYDOWN( SDLK_F7 ) && pchr->ismount )
784     {
785         GL_DEBUG( glDisable )( GL_TEXTURE_2D );
786         {
787             oct_bb_t bb;
788 
789             oct_bb_add_fvec3( &( pchr->slot_cv[SLOT_LEFT] ), pchr->pos.v, &bb );
790 
791             GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
792             render_oct_bb( &bb, btrue, btrue );
793         }
794         GL_DEBUG( glEnable )( GL_TEXTURE_2D );
795     }
796 
797     //// the grips and vertrices of all objects
798     //if ( cfg.dev_mode && SDLKEYDOWN( SDLK_F6 ) )
799     //{
800     //    draw_chr_attached_grip( pchr );
801 
802     //    // draw all the vertices of an object
803     //    GL_DEBUG( glPointSize( 5 ) );
804     //    draw_chr_verts( pchr, 0, pchr->inst.vrt_count );
805     //}
806 }
807 
808 //--------------------------------------------------------------------------------------------
draw_chr_verts(chr_t * pchr,int vrt_offset,int verts)809 void draw_chr_verts( chr_t * pchr, int vrt_offset, int verts )
810 {
811     /// @details BB@> a function that will draw some of the vertices of the given character.
812     ///     The original idea was to use this to debug the grip for attached items.
813 
814     GLint matrix_mode[1];
815 
816     mad_t * pmad;
817 
818     int vmin, vmax, cnt;
819     GLboolean texture_1d_enabled, texture_2d_enabled;
820 
821     if ( !ACTIVE_PCHR( pchr ) ) return;
822 
823     pmad = chr_get_pmad( GET_REF_PCHR( pchr ) );
824     if ( NULL == pmad ) return;
825 
826     vmin = vrt_offset;
827     vmax = vmin + verts;
828 
829     if ( vmin < 0 || vmax < 0 ) return;
830     if ( vmin > pchr->inst.vrt_count || vmax > pchr->inst.vrt_count ) return;
831 
832     texture_1d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_1D );
833     texture_2d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_2D );
834 
835     // disable the texturing so all the points will be white,
836     // not the texture color of the last vertex we drawn
837     if ( texture_1d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_1D );
838     if ( texture_2d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_2D );
839 
840     // save the matrix mode
841     GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
842 
843     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
844     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
845     GL_DEBUG( glPushMatrix )();
846     GL_DEBUG( glMultMatrixf )( pchr->inst.matrix.v );
847 
848     GL_DEBUG( glBegin( GL_POINTS ) );
849     {
850         for ( cnt = vmin; cnt < vmax; cnt++ )
851         {
852             GL_DEBUG( glVertex3fv )( pchr->inst.vrt_lst[cnt].pos );
853         }
854     }
855     GL_DEBUG_END();
856 
857     // Restore the GL_MODELVIEW matrix
858     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
859     GL_DEBUG( glPopMatrix )();
860 
861     // restore the matrix mode
862     GL_DEBUG( glMatrixMode )( matrix_mode[0] );
863 
864     if ( texture_1d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_1D );
865     if ( texture_2d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_2D );
866 }
867 
868 //--------------------------------------------------------------------------------------------
draw_one_grip(chr_instance_t * pinst,mad_t * pmad,int slot)869 void draw_one_grip( chr_instance_t * pinst, mad_t * pmad, int slot )
870 {
871     GLint matrix_mode[1];
872     GLboolean texture_1d_enabled, texture_2d_enabled;
873 
874     texture_1d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_1D );
875     texture_2d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_2D );
876 
877     // disable the texturing so all the points will be white,
878     // not the texture color of the last vertex we drawn
879     if ( texture_1d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_1D );
880     if ( texture_2d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_2D );
881 
882     // save the matrix mode
883     GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
884 
885     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
886     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
887     GL_DEBUG( glPushMatrix )();
888     GL_DEBUG( glMultMatrixf )( pinst->matrix.v );
889 
890     _draw_one_grip_raw( pinst, pmad, slot );
891 
892     // Restore the GL_MODELVIEW matrix
893     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
894     GL_DEBUG( glPopMatrix )();
895 
896     // restore the matrix mode
897     GL_DEBUG( glMatrixMode )( matrix_mode[0] );
898 
899     if ( texture_1d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_1D );
900     if ( texture_2d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_2D );
901 }
902 
903 //--------------------------------------------------------------------------------------------
_draw_one_grip_raw(chr_instance_t * pinst,mad_t * pmad,int slot)904 void _draw_one_grip_raw( chr_instance_t * pinst, mad_t * pmad, int slot )
905 {
906     int vmin, vmax, cnt;
907 
908     float red[4] = {1, 0, 0, 1};
909     float grn[4] = {0, 1, 0, 1};
910     float blu[4] = {0, 0, 1, 1};
911     float * col_ary[3];
912 
913     col_ary[0] = red;
914     col_ary[1] = grn;
915     col_ary[2] = blu;
916 
917     if ( NULL == pinst || NULL == pmad ) return;
918 
919     vmin = ( int )pinst->vrt_count - ( int )slot_to_grip_offset(( slot_t )slot );
920     vmax = vmin + GRIP_VERTS;
921 
922     if ( vmin >= 0 && vmax >= 0 && vmax <= pinst->vrt_count )
923     {
924         fvec3_t   src, dst, diff;
925 
926         GL_DEBUG( glBegin )( GL_LINES );
927         {
928             for ( cnt = 1; cnt < GRIP_VERTS; cnt++ )
929             {
930                 src.x = pinst->vrt_lst[vmin].pos[XX];
931                 src.y = pinst->vrt_lst[vmin].pos[YY];
932                 src.z = pinst->vrt_lst[vmin].pos[ZZ];
933 
934                 diff.x = pinst->vrt_lst[vmin+cnt].pos[XX] - src.x;
935                 diff.y = pinst->vrt_lst[vmin+cnt].pos[YY] - src.y;
936                 diff.z = pinst->vrt_lst[vmin+cnt].pos[ZZ] - src.z;
937 
938                 dst.x = src.x + 3 * diff.x;
939                 dst.y = src.y + 3 * diff.y;
940                 dst.z = src.z + 3 * diff.z;
941 
942                 GL_DEBUG( glColor4fv )( col_ary[cnt-1] );
943 
944                 GL_DEBUG( glVertex3fv )( src.v );
945                 GL_DEBUG( glVertex3fv )( dst.v );
946             }
947         }
948         GL_DEBUG_END();
949     }
950 
951     GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
952 }
953 
954 //--------------------------------------------------------------------------------------------
draw_chr_attached_grip(chr_t * pchr)955 void draw_chr_attached_grip( chr_t * pchr )
956 {
957     mad_t * pholder_mad;
958     cap_t * pholder_cap;
959     chr_t * pholder;
960 
961     if ( !ACTIVE_PCHR( pchr ) ) return;
962 
963     if ( !INGAME_CHR( pchr->attachedto ) ) return;
964     pholder = ChrList.lst + pchr->attachedto;
965 
966     pholder_cap = pro_get_pcap( pholder->profile_ref );
967     if ( NULL == pholder_cap ) return;
968 
969     pholder_mad = chr_get_pmad( GET_REF_PCHR( pholder ) );
970     if ( NULL == pholder_mad ) return;
971 
972     draw_one_grip( &( pholder->inst ), pholder_mad, pchr->inwhich_slot );
973 }
974 
975 //--------------------------------------------------------------------------------------------
draw_chr_grips(chr_t * pchr)976 void draw_chr_grips( chr_t * pchr )
977 {
978     mad_t * pmad;
979     cap_t * pcap;
980 
981     int slot;
982 
983     GLint matrix_mode[1];
984     GLboolean texture_1d_enabled, texture_2d_enabled;
985 
986     if ( !ACTIVE_PCHR( pchr ) ) return;
987 
988     pcap = pro_get_pcap( pchr->profile_ref );
989     if ( NULL == pcap ) return;
990 
991     pmad = chr_get_pmad( GET_REF_PCHR( pchr ) );
992     if ( NULL == pmad ) return;
993 
994     texture_1d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_1D );
995     texture_2d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_2D );
996 
997     // disable the texturing so all the points will be white,
998     // not the texture color of the last vertex we drawn
999     if ( texture_1d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_1D );
1000     if ( texture_2d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_2D );
1001 
1002     // save the matrix mode
1003     GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
1004 
1005     // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
1006     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
1007     GL_DEBUG( glPushMatrix )();
1008     GL_DEBUG( glMultMatrixf )( pchr->inst.matrix.v );
1009 
1010     slot = SLOT_LEFT;
1011     if ( pcap->slotvalid[slot] )
1012     {
1013         _draw_one_grip_raw( &( pchr->inst ), pmad, slot );
1014     }
1015 
1016     slot = SLOT_RIGHT;
1017     if ( pcap->slotvalid[slot] )
1018     {
1019         _draw_one_grip_raw( &( pchr->inst ), pmad, slot );
1020     }
1021 
1022     // Restore the GL_MODELVIEW matrix
1023     GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
1024     GL_DEBUG( glPopMatrix )();
1025 
1026     // restore the matrix mode
1027     GL_DEBUG( glMatrixMode )( matrix_mode[0] );
1028 
1029     if ( texture_1d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_1D );
1030     if ( texture_2d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_2D );
1031 }
1032 
1033 //--------------------------------------------------------------------------------------------
1034 //--------------------------------------------------------------------------------------------
chr_instance_update_lighting_base(chr_instance_t * pinst,chr_t * pchr,bool_t force)1035 void chr_instance_update_lighting_base( chr_instance_t * pinst, chr_t * pchr, bool_t force )
1036 {
1037     /// @details BB@> determine the basic per-vertex lighting
1038 
1039     Uint16 cnt;
1040 
1041     lighting_cache_t global_light, loc_light;
1042 
1043     GLvertex * vrt_lst;
1044 
1045     mad_t * pmad;
1046 
1047     if ( NULL == pinst || NULL == pchr ) return;
1048     vrt_lst = pinst->vrt_lst;
1049 
1050     // force this function to be evaluated the 1st time through
1051     if ( 0 == update_wld && 0 == game_frame_all ) force = btrue;
1052 
1053     // has this already been calculated this update?
1054     if ( !force && pinst->lighting_update_wld >= update_wld ) return;
1055     pinst->lighting_update_wld = update_wld;
1056 
1057     // make sure the matrix is valid
1058     chr_update_matrix( pchr, btrue );
1059 
1060     // has this already been calculated this frame?
1061     if ( !force && pinst->lighting_frame_all >= game_frame_all ) return;
1062 
1063     // reduce the amount of updates to an average of about 1 every 2 frames, but dither
1064     // the updating so that not all objects update on the same frame
1065     pinst->lighting_frame_all = game_frame_all + (( game_frame_all + pchr->obj_base.guid ) & 0x03 );
1066 
1067     if ( !LOADED_MAD( pinst->imad ) ) return;
1068     pmad = MadStack.lst + pinst->imad;
1069     pinst->vrt_count = pinst->vrt_count;
1070 
1071     // interpolate the lighting for the origin of the object
1072     grid_lighting_interpolate( PMesh, &global_light, pchr->pos.x, pchr->pos.y );
1073 
1074     // rotate the lighting data to body_centered coordinates
1075     lighting_project_cache( &loc_light, &global_light, pinst->matrix );
1076 
1077     pinst->color_amb = 0.9f * pinst->color_amb + 0.1f * ( loc_light.hgh.lighting[LVEC_AMB] + loc_light.low.lighting[LVEC_AMB] ) * 0.5f;
1078 
1079     pinst->max_light = -255;
1080     pinst->min_light =  255;
1081     for ( cnt = 0; cnt < pinst->vrt_count; cnt++ )
1082     {
1083         Sint16 lite;
1084 
1085         GLvertex * pvert = pinst->vrt_lst + cnt;
1086 
1087         // a simple "height" measurement
1088         float hgt = pvert->pos[ZZ] * pinst->matrix.CNV( 3, 3 ) + pinst->matrix.CNV( 3, 3 );
1089 
1090         if ( pvert->nrm[0] == 0.0f && pvert->nrm[1] == 0.0f && pvert->nrm[2] == 0.0f )
1091         {
1092             // this is the "ambient only" index, but it really means to sum up all the light
1093             GLfloat tnrm[3];
1094 
1095             tnrm[0] = tnrm[1] = tnrm[2] = 1.0f;
1096             lite  = lighting_evaluate_cache( &loc_light, tnrm, hgt, PMesh->tmem.bbox, NULL, NULL );
1097 
1098             tnrm[0] = tnrm[1] = tnrm[2] = -1.0f;
1099             lite += lighting_evaluate_cache( &loc_light, tnrm, hgt, PMesh->tmem.bbox, NULL, NULL );
1100 
1101             // average all the directions
1102             lite /= 6;
1103         }
1104         else
1105         {
1106             lite  = lighting_evaluate_cache( &loc_light, pvert->nrm, hgt, PMesh->tmem.bbox, NULL, NULL );
1107         }
1108 
1109         pvert->color_dir = 0.9f * pvert->color_dir + 0.1f * lite;
1110 
1111         pinst->max_light = MAX( pinst->max_light, pvert->color_dir );
1112         pinst->min_light = MIN( pinst->min_light, pvert->color_dir );
1113     }
1114 
1115     // ??coerce this to reasonable values in the presence of negative light??
1116     if ( pinst->max_light < 0 ) pinst->max_light = 0;
1117     if ( pinst->min_light < 0 ) pinst->min_light = 0;
1118 }
1119 
1120 //--------------------------------------------------------------------------------------------
chr_instance_update_bbox(chr_instance_t * pinst)1121 gfx_rv chr_instance_update_bbox( chr_instance_t * pinst )
1122 {
1123     int           frame_count;
1124 
1125     mad_t       * pmad;
1126     MD2_Model_t * pmd2;
1127     MD2_Frame_t * frame_list, * pframe_nxt, * pframe_lst;
1128 
1129     if ( NULL == pinst )
1130     {
1131         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1132         return gfx_error;
1133     }
1134 
1135     // get the model. try to heal a bad model.
1136     if ( !LOADED_MAD( pinst->imad ) )
1137     {
1138         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1139         return gfx_error;
1140     }
1141     pmad = MadStack.lst + pinst->imad;
1142 
1143     if ( NULL == pmad->md2_ptr )
1144     {
1145         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL md2" );
1146         return gfx_error;
1147     }
1148     pmd2 = pmad->md2_ptr;
1149 
1150     frame_count = md2_get_numFrames( pmd2 );
1151     if ( pinst->frame_nxt >= frame_count ||  pinst->frame_lst >= frame_count )
1152     {
1153         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "invalid frame range" );
1154         return gfx_error;
1155     }
1156 
1157     frame_list = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
1158     pframe_lst = frame_list + pinst->frame_lst;
1159     pframe_nxt = frame_list + pinst->frame_nxt;
1160 
1161     if ( pinst->frame_nxt == pinst->frame_lst || pinst->flip == 0.0f )
1162     {
1163         oct_bb_copy( &( pinst->bbox ), &( pframe_lst->bb ) );
1164     }
1165     else if ( pinst->flip == 1.0f )
1166     {
1167         oct_bb_copy( &( pinst->bbox ), &( pframe_nxt->bb ) );
1168     }
1169     else
1170     {
1171         oct_bb_interpolate( &( pinst->bbox ), &( pframe_lst->bb ), &( pframe_nxt->bb ), pinst->flip );
1172     }
1173 
1174     return gfx_success;
1175 }
1176 
1177 //--------------------------------------------------------------------------------------------
chr_instance_needs_update(chr_instance_t * pinst,int vmin,int vmax,bool_t * verts_match,bool_t * frames_match)1178 gfx_rv chr_instance_needs_update( chr_instance_t * pinst, int vmin, int vmax, bool_t *verts_match, bool_t *frames_match )
1179 {
1180     /// @details BB@> determine whether some specific vertices of an instance need to be updated
1181     //                gfx_error   means that the function was passed invalid values
1182     //                gfx_fail    means that the instance does not need to be updated
1183     //                gfx_success means that the instance should be updated
1184 
1185     bool_t local_verts_match, flips_match, local_frames_match;
1186 
1187     vlst_cache_t * psave;
1188 
1189     mad_t * pmad;
1190     int maxvert;
1191 
1192     // ensure that the pointers point to something
1193     if ( NULL == verts_match ) verts_match  = &local_verts_match;
1194     if ( NULL == frames_match ) frames_match = &local_frames_match;
1195 
1196     // initialize the boolean pointers
1197     *verts_match  = bfalse;
1198     *frames_match = bfalse;
1199 
1200     // do we have a valid instance?
1201     if ( NULL == pinst )
1202     {
1203         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1204         return gfx_error;
1205     }
1206     psave = &( pinst->save );
1207 
1208     // do we hace a valid mad?
1209     if ( !LOADED_MAD( pinst->imad ) )
1210     {
1211         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1212         return gfx_error;
1213     }
1214     pmad = MadStack.lst + pinst->imad;
1215 
1216     // check to see if the vlst_cache has been marked as invalid.
1217     // in this case, everything needs to be updated
1218     if ( !psave->valid ) return gfx_success;
1219 
1220     // get the last valid vertex from the chr_instance
1221     maxvert = (( int )pinst->vrt_count ) - 1;
1222 
1223     // check to make sure the lower bound of the saved data is valid.
1224     // it is initialized to an invalid value (psave->vmin = psave->vmax = -1)
1225     if ( psave->vmin < 0 || psave->vmax < 0 ) return gfx_success;
1226 
1227     // check to make sure the upper bound of the saved data is valid.
1228     if ( psave->vmin > maxvert || psave->vmax > maxvert ) return gfx_success;
1229 
1230     // make sure that the min and max vertices are in the correct order
1231     if ( vmax < vmin ) SWAP( int, vmax, vmin );
1232 
1233     // test to see if we have already calculated this data
1234     *verts_match = ( vmin >= psave->vmin ) && ( vmax <= psave->vmax );
1235 
1236     flips_match = ( ABS( psave->flip - pinst->flip ) < flip_tolerance );
1237 
1238     *frames_match = ( pinst->frame_nxt == pinst->frame_lst && psave->frame_nxt == pinst->frame_nxt && psave->frame_lst == pinst->frame_lst ) ||
1239                     ( flips_match && psave->frame_nxt == pinst->frame_nxt && psave->frame_lst == pinst->frame_lst );
1240 
1241     return ( !( *verts_match ) || !( *frames_match ) ) ? gfx_success : gfx_fail;
1242 }
1243 
1244 //--------------------------------------------------------------------------------------------
chr_instance_interpolate_vertices_raw(GLvertex dst_ary[],MD2_Vertex_t lst_ary[],MD2_Vertex_t nxt_ary[],int vmin,int vmax,float flip)1245 void chr_instance_interpolate_vertices_raw( GLvertex dst_ary[], MD2_Vertex_t lst_ary[], MD2_Vertex_t nxt_ary[], int vmin, int vmax, float flip )
1246 {
1247     /// raw indicates no bounds checking, so be careful
1248 
1249     int i;
1250 
1251     GLvertex     * dst;
1252     MD2_Vertex_t * src_lst;
1253     MD2_Vertex_t * src_nxt;
1254 
1255     if ( 0.0f == flip )
1256     {
1257         for ( i = vmin; i <= vmax; i++ )
1258         {
1259             dst     = dst_ary + i;
1260             src_lst = lst_ary + i;
1261 
1262             fvec3_base_copy( dst->pos, src_lst->pos.v );
1263             dst->pos[WW] = 1.0f;
1264 
1265             fvec3_base_copy( dst->nrm, src_lst->nrm.v );
1266 
1267             dst->env[XX] = indextoenvirox[src_lst->normal];
1268             dst->env[YY] = 0.5f * ( 1.0f + dst->nrm[ZZ] );
1269         }
1270     }
1271     else if ( 1.0f == flip )
1272     {
1273         for ( i = vmin; i <= vmax; i++ )
1274         {
1275             dst     = dst_ary + i;
1276             src_nxt = nxt_ary + i;
1277 
1278             fvec3_base_copy( dst->pos, src_nxt->pos.v );
1279             dst->pos[WW] = 1.0f;
1280 
1281             fvec3_base_copy( dst->nrm, src_nxt->nrm.v );
1282 
1283             dst->env[XX] = indextoenvirox[src_nxt->normal];
1284             dst->env[YY] = 0.5f * ( 1.0f + dst->nrm[ZZ] );
1285         }
1286     }
1287     else
1288     {
1289         Uint16 vrta_lst, vrta_nxt;
1290 
1291         for ( i = vmin; i <= vmax; i++ )
1292         {
1293             dst     = dst_ary + i;
1294             src_lst = lst_ary + i;
1295             src_nxt = nxt_ary + i;
1296 
1297             dst->pos[XX] = src_lst->pos.x + ( src_nxt->pos.x - src_lst->pos.x ) * flip;
1298             dst->pos[YY] = src_lst->pos.y + ( src_nxt->pos.y - src_lst->pos.y ) * flip;
1299             dst->pos[ZZ] = src_lst->pos.z + ( src_nxt->pos.z - src_lst->pos.z ) * flip;
1300             dst->pos[WW] = 1.0f;
1301 
1302             dst->nrm[XX] = src_lst->nrm.x + ( src_nxt->nrm.x - src_lst->nrm.x ) * flip;
1303             dst->nrm[YY] = src_lst->nrm.y + ( src_nxt->nrm.y - src_lst->nrm.y ) * flip;
1304             dst->nrm[ZZ] = src_lst->nrm.z + ( src_nxt->nrm.z - src_lst->nrm.z ) * flip;
1305 
1306             vrta_lst = src_lst->normal;
1307             vrta_nxt = src_nxt->normal;
1308 
1309             dst->env[XX] = indextoenvirox[vrta_lst] + ( indextoenvirox[vrta_nxt] - indextoenvirox[vrta_lst] ) * flip;
1310             dst->env[YY] = 0.5f * ( 1.0f + dst->nrm[ZZ] );
1311         }
1312     }
1313 }
1314 
1315 //--------------------------------------------------------------------------------------------
chr_instance_update_vertices(chr_instance_t * pinst,int vmin,int vmax,bool_t force)1316 gfx_rv chr_instance_update_vertices( chr_instance_t * pinst, int vmin, int vmax, bool_t force )
1317 {
1318     int    maxvert, frame_count;
1319     bool_t vertices_match, frames_match;
1320     float  loc_flip;
1321 
1322     gfx_rv retval;
1323 
1324     vlst_cache_t * psave;
1325 
1326     mad_t       * pmad;
1327     MD2_Model_t * pmd2;
1328     MD2_Frame_t * frame_list, * pframe_nxt, * pframe_lst;
1329 
1330     int vdirty1_min = -1, vdirty1_max = -1;
1331     int vdirty2_min = -1, vdirty2_max = -1;
1332 
1333     if ( NULL == pinst )
1334     {
1335         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1336         return gfx_error;
1337     }
1338     psave = &( pinst->save );
1339 
1340     if ( gfx_error == chr_instance_update_bbox( pinst ) )
1341     {
1342         return gfx_error;
1343     }
1344 
1345     // get the model
1346     if ( !LOADED_MAD( pinst->imad ) )
1347     {
1348         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1349         return gfx_error;
1350     }
1351     pmad = MadStack.lst + pinst->imad;
1352 
1353     if ( NULL == pmad->md2_ptr )
1354     {
1355         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL md2" );
1356         return gfx_error;
1357     }
1358     pmd2 = pmad->md2_ptr;
1359 
1360     // make sure we have valid data
1361     if ( pinst->vrt_count != md2_get_numVertices( pmd2 ) )
1362     {
1363         log_error( "chr_instance_update_vertices() - character instance vertex data does not match its md2\n" );
1364     }
1365 
1366     // get the vertex list size from the chr_instance
1367     maxvert = (( int )pinst->vrt_count ) - 1;
1368 
1369     // handle the default parameters
1370     if ( vmin < 0 ) vmin = 0;
1371     if ( vmax < 0 ) vmax = maxvert;
1372 
1373     // are they in the right order?
1374     if ( vmax < vmin ) SWAP( int, vmax, vmin );
1375 
1376     // make sure that the vertices are within the max range
1377     vmin = CLIP( vmin, 0, maxvert );
1378     vmax = CLIP( vmax, 0, maxvert );
1379 
1380     if ( force )
1381     {
1382         // force an update of vertices
1383 
1384         // select a range that encompases the requested vertices and the saved vertices
1385         // if this is the 1st update, the saved vertices may be set to invalid values, as well
1386 
1387         // grab the dirty vertices
1388         vdirty1_min = vmin;
1389         vdirty1_max = vmax;
1390 
1391         // force the routine to update
1392         vertices_match = bfalse;
1393         frames_match   = bfalse;
1394     }
1395     else
1396     {
1397         // do we need to update?
1398         retval = chr_instance_needs_update( pinst, vmin, vmax, &vertices_match, &frames_match );
1399         if ( gfx_error == retval ) return gfx_error;            // gfx_error == retval means some pointer or reference is messed up
1400         if ( gfx_fail  == retval ) return gfx_success;          // gfx_fail  == retval means we do not need to update this round
1401 
1402         if ( !frames_match )
1403         {
1404             // the entire frame is dirty
1405             vdirty1_min = vmin;
1406             vdirty1_max = vmax;
1407         }
1408         else
1409         {
1410             // grab the dirty vertices
1411             if ( vmin < psave->vmin )
1412             {
1413                 vdirty1_min = vmin;
1414                 vdirty1_max = psave->vmin - 1;
1415             }
1416 
1417             if ( vmax > psave->vmax )
1418             {
1419                 vdirty2_min = psave->vmax + 1;
1420                 vdirty2_max = vmax;
1421             }
1422         }
1423     }
1424 
1425     // make sure the frames are in the valid range
1426     frame_count = md2_get_numFrames( pmd2 );
1427     if ( pinst->frame_nxt >= frame_count || pinst->frame_lst >= frame_count )
1428     {
1429         log_error( "chr_instance_update_vertices() - character instance frame is outside the range of its md2\n" );
1430     }
1431 
1432     // grab the frame data from the correct model
1433     frame_list = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
1434     pframe_nxt = frame_list + pinst->frame_nxt;
1435     pframe_lst = frame_list + pinst->frame_lst;
1436 
1437     // fix the flip for objects that are not animating
1438     loc_flip = pinst->flip;
1439     if ( pinst->frame_nxt == pinst->frame_lst ) loc_flip = 0.0f;
1440 
1441     // interpolate the 1st dirty region
1442     if ( vdirty1_min >= 0 && vdirty1_max >= 0 )
1443     {
1444         chr_instance_interpolate_vertices_raw( pinst->vrt_lst, pframe_lst->vertex_lst, pframe_nxt->vertex_lst, vdirty1_min, vdirty1_max, loc_flip );
1445     }
1446 
1447     // interpolate the 2nd dirty region
1448     if ( vdirty2_min >= 0 && vdirty2_max >= 0 )
1449     {
1450         chr_instance_interpolate_vertices_raw( pinst->vrt_lst, pframe_lst->vertex_lst, pframe_nxt->vertex_lst, vdirty2_min, vdirty2_max, loc_flip );
1451     }
1452 
1453     // update the saved parameters
1454     return chr_instance_update_vlst_cache( pinst, vmax, vmin, force, vertices_match, frames_match );
1455 }
1456 
1457 //--------------------------------------------------------------------------------------------
chr_instance_update_vlst_cache(chr_instance_t * pinst,int vmax,int vmin,bool_t force,bool_t vertices_match,bool_t frames_match)1458 gfx_rv chr_instance_update_vlst_cache( chr_instance_t * pinst, int vmax, int vmin, bool_t force, bool_t vertices_match, bool_t frames_match )
1459 {
1460     // this is getting a bit ugly...
1461     // we need to do this calculation as little as possible, so it is important that the
1462     // pinst->save.* values be tested and stored properly
1463 
1464     bool_t verts_updated, frames_updated;
1465     int    maxvert;
1466 
1467     vlst_cache_t * psave;
1468 
1469     if ( NULL == pinst )
1470     {
1471         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1472         return gfx_error;
1473     }
1474     maxvert = (( int )pinst->vrt_count ) - 1;
1475     psave   = &( pinst->save );
1476 
1477     // the save_vmin and save_vmax is the most complex
1478     verts_updated = bfalse;
1479     if ( force )
1480     {
1481         // to get here, either the specified range was outside the clean range or
1482         // the animation was updated. In any case, the only vertices that are
1483         // clean are in the range [vmin, vmax]
1484 
1485         psave->vmin   = vmin;
1486         psave->vmax   = vmax;
1487         verts_updated = btrue;
1488     }
1489     else if ( vertices_match && frames_match )
1490     {
1491         // everything matches, so there is nothing to do
1492     }
1493     else if ( vertices_match )
1494     {
1495         // The only way to get here is to fail the frames_match test, and pass vertices_match
1496 
1497         // This means that all of the vertices were SUPPOSED TO BE updated,
1498         // but only the ones in the range [vmin, vmax] actually were.
1499         psave->vmin = vmin;
1500         psave->vmax = vmax;
1501         verts_updated = btrue;
1502     }
1503     else if ( frames_match )
1504     {
1505         // The only way to get here is to fail the vertices_match test, and pass frames_match test
1506 
1507         // There was no update to the animation,  but there was an update to some of the vertices
1508         // The clean verrices should be the union of the sets of the vertices updated this time
1509         // and the oned updated last time.
1510         //
1511         //If these ranges are disjoint, then only one of them can be saved. Choose the larger set
1512 
1513         if ( vmax >= psave->vmin && vmin <= psave->vmax )
1514         {
1515             // the old list [save_vmin, save_vmax] and the new list [vmin, vmax]
1516             // overlap, so we can merge them
1517             psave->vmin = MIN( psave->vmin, vmin );
1518             psave->vmax = MAX( psave->vmax, vmax );
1519             verts_updated = btrue;
1520         }
1521         else
1522         {
1523             // the old list and the new list are disjoint sets, so we are out of luck
1524             // save the set with the largest number of members
1525             if (( psave->vmax - psave->vmin ) >= ( vmax - vmin ) )
1526             {
1527                 // obviously no change...
1528                 psave->vmin = psave->vmin;
1529                 psave->vmax = psave->vmax;
1530                 verts_updated = btrue;
1531             }
1532             else
1533             {
1534                 psave->vmin = vmin;
1535                 psave->vmax = vmax;
1536                 verts_updated = btrue;
1537             }
1538         }
1539     }
1540     else
1541     {
1542         // The only way to get here is to fail the vertices_match test, and fail the frames_match test
1543 
1544         // everything was dirty, so just save the new vertex list
1545         psave->vmin = vmin;
1546         psave->vmax = vmax;
1547         verts_updated = btrue;
1548     }
1549 
1550     psave->frame_nxt = pinst->frame_nxt;
1551     psave->frame_lst = pinst->frame_lst;
1552     psave->flip      = pinst->flip;
1553 
1554     // store the last time there was an update to the animation
1555     frames_updated = bfalse;
1556     if ( !frames_match )
1557     {
1558         psave->frame_wld = update_wld;
1559         frames_updated   = btrue;
1560     }
1561 
1562     // store the time of the last full update
1563     if ( 0 == vmin && maxvert == vmax )
1564     {
1565         psave->vert_wld  = update_wld;
1566     }
1567 
1568     // mark the saved vlst_cache data as valid
1569     psave->valid = btrue;
1570 
1571     return ( verts_updated || frames_updated ) ? gfx_success : gfx_fail;
1572 }
1573 
1574 //--------------------------------------------------------------------------------------------
chr_instance_update_grip_verts(chr_instance_t * pinst,Uint16 vrt_lst[],size_t vrt_count)1575 gfx_rv chr_instance_update_grip_verts( chr_instance_t * pinst, Uint16 vrt_lst[], size_t vrt_count )
1576 {
1577     int vmin, vmax;
1578     Uint32 cnt;
1579     size_t count;
1580     gfx_rv retval;
1581 
1582     if ( NULL == pinst )
1583     {
1584         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1585         return gfx_error;
1586     }
1587 
1588     if ( NULL == vrt_lst || 0 == vrt_count ) return gfx_fail;
1589 
1590     // count the valid attachment points
1591     vmin = 0xFFFF;
1592     vmax = 0;
1593     count = 0;
1594     for ( cnt = 0; cnt < vrt_count; cnt++ )
1595     {
1596         if ( 0xFFFF == vrt_lst[cnt] ) continue;
1597 
1598         vmin = MIN( vmin, vrt_lst[cnt] );
1599         vmax = MAX( vmax, vrt_lst[cnt] );
1600         count++;
1601     }
1602 
1603     // if there are no valid points, there is nothing to do
1604     if ( 0 == count ) return gfx_fail;
1605 
1606     // force the vertices to update
1607     retval = chr_instance_update_vertices( pinst, vmin, vmax, btrue );
1608 
1609     return retval;
1610 }
1611 
1612 //--------------------------------------------------------------------------------------------
chr_instance_set_action(chr_instance_t * pinst,int action,bool_t action_ready,bool_t override_action)1613 gfx_rv chr_instance_set_action( chr_instance_t * pinst, int action, bool_t action_ready, bool_t override_action )
1614 {
1615     int action_old;
1616     mad_t * pmad;
1617 
1618     // did we get a bad pointer?
1619     if ( NULL == pinst )
1620     {
1621         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1622         return gfx_error;
1623     }
1624 
1625     // is the action in the valid range?
1626     if ( action < 0 || action > ACTION_COUNT )
1627     {
1628         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, action, "invalid action range" );
1629         return gfx_error;
1630     }
1631 
1632     // do we have a valid model?
1633     if ( !LOADED_MAD( pinst->imad ) )
1634     {
1635         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1636         return gfx_error;
1637     }
1638     pmad = MadStack.lst + pinst->imad;
1639 
1640     // is the chosen action valid?
1641     if ( !pmad->action_valid[ action ] ) return gfx_fail;
1642 
1643     // are we going to check action_ready?
1644     if ( !override_action && !pinst->action_ready ) return gfx_fail;
1645 
1646     // save the old action
1647     action_old = pinst->action_which;
1648 
1649     // set up the action
1650     pinst->action_which = action;
1651     pinst->action_next  = ACTION_DA;
1652     pinst->action_ready = action_ready;
1653 
1654     // invalidate the vertex list if the action has changed
1655     if ( action_old != action )
1656     {
1657         pinst->save.valid = bfalse;
1658     }
1659 
1660     return gfx_success;
1661 }
1662 
1663 //--------------------------------------------------------------------------------------------
chr_instance_set_frame(chr_instance_t * pinst,int frame)1664 gfx_rv chr_instance_set_frame( chr_instance_t * pinst, int frame )
1665 {
1666     mad_t * pmad;
1667 
1668     // did we get a bad pointer?
1669     if ( NULL == pinst )
1670     {
1671         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1672         return gfx_error;
1673     }
1674 
1675     // is the action in the valid range?
1676     if ( pinst->action_which < 0 || pinst->action_which > ACTION_COUNT )
1677     {
1678         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->action_which, "invalid action range" );
1679         return gfx_error;
1680     }
1681 
1682     // do we have a valid model?
1683     if ( !LOADED_MAD( pinst->imad ) )
1684     {
1685         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1686         return gfx_error;
1687     }
1688     pmad = MadStack.lst + pinst->imad;
1689 
1690     // is the current action valid?
1691     if ( !pmad->action_valid[ pinst->action_which ] ) return gfx_fail;
1692 
1693     // is the frame within the valid range for this action?
1694     if ( frame < pmad->action_stt[ pinst->action_which ] ) return gfx_fail;
1695     if ( frame > pmad->action_end[ pinst->action_which ] ) return gfx_fail;
1696 
1697     // jump to the next frame
1698     pinst->flip      = 0.0f;
1699     pinst->ilip      = 0;
1700     pinst->frame_lst = pinst->frame_nxt;
1701     pinst->frame_nxt = frame;
1702 
1703     vlst_cache_test( &( pinst->save ), pinst );
1704 
1705     return gfx_success;
1706 }
1707 
1708 //--------------------------------------------------------------------------------------------
chr_instance_set_anim(chr_instance_t * pinst,int action,int frame,bool_t action_ready,bool_t override_action)1709 gfx_rv chr_instance_set_anim( chr_instance_t * pinst, int action, int frame, bool_t action_ready, bool_t override_action )
1710 {
1711     gfx_rv retval;
1712 
1713     if ( NULL == pinst )
1714     {
1715         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1716         return gfx_error;
1717     }
1718 
1719     retval = chr_instance_set_action( pinst, action, action_ready, override_action );
1720     if ( gfx_success != retval ) return retval;
1721 
1722     retval = chr_instance_set_frame( pinst, frame );
1723 
1724     return retval;
1725 }
1726 
1727 //--------------------------------------------------------------------------------------------
chr_instance_start_anim(chr_instance_t * pinst,int action,bool_t action_ready,bool_t override_action)1728 gfx_rv chr_instance_start_anim( chr_instance_t * pinst, int action, bool_t action_ready, bool_t override_action )
1729 {
1730     mad_t * pmad;
1731 
1732     if ( NULL == pinst )
1733     {
1734         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1735         return gfx_error;
1736     }
1737 
1738     if ( action < 0 || action >= ACTION_COUNT )
1739     {
1740         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, action, "invalid action range" );
1741         return gfx_error;
1742     }
1743 
1744     if ( !LOADED_MAD( pinst->imad ) )
1745     {
1746         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1747         return gfx_error;
1748     }
1749     pmad = MadStack.lst + pinst->imad;
1750 
1751     return chr_instance_set_anim( pinst, action, pmad->action_stt[action], action_ready, override_action );
1752 }
1753 
1754 //--------------------------------------------------------------------------------------------
chr_instance_increment_action(chr_instance_t * pinst)1755 gfx_rv chr_instance_increment_action( chr_instance_t * pinst )
1756 {
1757     /// @details BB@> This function starts the next action for a character
1758 
1759     gfx_rv retval;
1760 
1761     int     action, action_old;
1762     bool_t  action_ready;
1763 
1764     if ( NULL == pinst )
1765     {
1766         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1767         return gfx_error;
1768     }
1769 
1770     // save the old action
1771     action_old = pinst->action_which;
1772 
1773     if ( !LOADED_MAD( pinst->imad ) )
1774     {
1775         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1776         return gfx_error;
1777     }
1778 
1779     // get the correct action
1780     action = mad_get_action_ref( pinst->imad, pinst->action_next );
1781 
1782     // determine if the action is one of the types that can be broken at any time
1783     // D == "dance" and "W" == walk
1784     action_ready = ACTION_IS_TYPE( action, D ) || ACTION_IS_TYPE( action, W );
1785 
1786     retval = chr_instance_start_anim( pinst, action, action_ready, btrue );
1787 
1788     return retval;
1789 }
1790 
1791 //--------------------------------------------------------------------------------------------
chr_instance_increment_frame(chr_instance_t * pinst,mad_t * pmad,const CHR_REF imount,const int mount_action)1792 gfx_rv chr_instance_increment_frame( chr_instance_t * pinst, mad_t * pmad, const CHR_REF imount, const int mount_action )
1793 {
1794     /// @details BB@> all the code necessary to move on to the next frame of the animation
1795 
1796     if ( NULL == pmad )
1797     {
1798         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL mad" );
1799         return gfx_error;
1800     }
1801 
1802     if ( NULL == pinst )
1803     {
1804         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1805         return gfx_error;
1806     }
1807 
1808     // fix the ilip and flip
1809     pinst->ilip = pinst->ilip % 4;
1810     pinst->flip = fmod( pinst->flip, 1.0f );
1811 
1812     // Change frames
1813     pinst->frame_lst = pinst->frame_nxt;
1814     pinst->frame_nxt++;
1815 
1816     // detect the end of the animation and handle special end conditions
1817     if ( pinst->frame_nxt > pmad->action_end[pinst->action_which] )
1818     {
1819         if ( pinst->action_keep )
1820         {
1821             // Freeze that animation at the last frame
1822             pinst->frame_nxt = pinst->frame_lst;
1823 
1824             // Break a kept action at any time
1825             pinst->action_ready = btrue;
1826         }
1827         else if ( pinst->action_loop )
1828         {
1829             // Convert the action into a riding action if the character is mounted
1830             if ( INGAME_CHR( imount ) )
1831             {
1832                 chr_instance_start_anim( pinst, mount_action, btrue, btrue );
1833             }
1834 
1835             // set the frame to the beginning of the action
1836             pinst->frame_nxt = pmad->action_stt[pinst->action_which];
1837 
1838             // Break a looped action at any time
1839             pinst->action_ready = btrue;
1840         }
1841         else
1842         {
1843             // make sure that the frame_nxt points to a valid frame in this action
1844             pinst->frame_nxt = pmad->action_end[pinst->action_which];
1845 
1846             // Go on to the next action. don't let just anything interrupt it?
1847             chr_instance_increment_action( pinst );
1848         }
1849     }
1850 
1851     vlst_cache_test( &( pinst->save ), pinst );
1852 
1853     return gfx_success;
1854 }
1855 
1856 //--------------------------------------------------------------------------------------------
chr_instance_play_action(chr_instance_t * pinst,int action,bool_t action_ready)1857 gfx_rv chr_instance_play_action( chr_instance_t * pinst, int action, bool_t action_ready )
1858 {
1859     /// @details ZZ@> This function starts a generic action for a character
1860     mad_t * pmad;
1861 
1862     if ( NULL == pinst )
1863     {
1864         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1865         return gfx_error;
1866     }
1867 
1868     if ( !LOADED_MAD( pinst->imad ) )
1869     {
1870         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pinst->imad, "invalid mad" );
1871         return gfx_error;
1872     }
1873     pmad = MadStack.lst + pinst->imad;
1874 
1875     action = mad_get_action_ref( pinst->imad, action );
1876 
1877     return chr_instance_start_anim( pinst, action, action_ready, btrue );
1878 }
1879 
1880 //--------------------------------------------------------------------------------------------
chr_instance_clear_cache(chr_instance_t * pinst)1881 void chr_instance_clear_cache( chr_instance_t * pinst )
1882 {
1883     /// @details BB@> force chr_instance_update_vertices() recalculate the vertices the next time
1884     ///     the function is called
1885 
1886     vlst_cache_init( &( pinst->save ) );
1887 
1888     matrix_cache_init( &( pinst->matrix_cache ) );
1889 
1890     chr_reflection_cache_init( &( pinst->ref ) );
1891 
1892     pinst->lighting_update_wld = 0;
1893     pinst->lighting_frame_all  = 0;
1894 }
1895 
1896 //--------------------------------------------------------------------------------------------
chr_instance_dtor(chr_instance_t * pinst)1897 chr_instance_t * chr_instance_dtor( chr_instance_t * pinst )
1898 {
1899     if ( NULL == pinst ) return pinst;
1900 
1901     chr_instance_free( pinst );
1902 
1903     EGOBOO_ASSERT( NULL == pinst->vrt_lst );
1904 
1905     memset( pinst, 0, sizeof( *pinst ) );
1906 
1907     return pinst;
1908 }
1909 
1910 //--------------------------------------------------------------------------------------------
chr_instance_ctor(chr_instance_t * pinst)1911 chr_instance_t * chr_instance_ctor( chr_instance_t * pinst )
1912 {
1913     Uint32 cnt;
1914 
1915     if ( NULL == pinst ) return pinst;
1916 
1917     memset( pinst, 0, sizeof( *pinst ) );
1918 
1919     // model parameters
1920     pinst->imad = MAX_MAD;
1921     pinst->vrt_count = 0;
1922 
1923     // set the initial cache parameters
1924     chr_instance_clear_cache( pinst );
1925 
1926     // Set up initial fade in lighting
1927     pinst->color_amb = 0;
1928     for ( cnt = 0; cnt < pinst->vrt_count; cnt++ )
1929     {
1930         pinst->vrt_lst[cnt].color_dir = 0;
1931     }
1932 
1933     // clear out the matrix cache
1934     matrix_cache_init( &( pinst->matrix_cache ) );
1935 
1936     // the matrix should never be referenced if the cache is not valid,
1937     // but it never pays to have a 0 matrix...
1938     pinst->matrix = IdentityMatrix();
1939 
1940     // set the animation state
1941     pinst->rate         = 1.0f;
1942     pinst->action_next  = ACTION_DA;
1943     pinst->action_ready = btrue;                     // argh! this must be set at the beginning, script's spawn animations do not work!
1944     pinst->frame_nxt    = pinst->frame_lst = 0;
1945 
1946     // the vlst_cache parameters are not valid
1947     pinst->save.valid = bfalse;
1948 
1949     return pinst;
1950 }
1951 
1952 //--------------------------------------------------------------------------------------------
chr_instance_free(chr_instance_t * pinst)1953 gfx_rv chr_instance_free( chr_instance_t * pinst )
1954 {
1955     if ( NULL == pinst )
1956     {
1957         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1958         return gfx_error;
1959     }
1960 
1961     EGOBOO_DELETE_ARY( pinst->vrt_lst );
1962     pinst->vrt_count = 0;
1963 
1964     return gfx_success;
1965 }
1966 
1967 //--------------------------------------------------------------------------------------------
chr_instance_alloc(chr_instance_t * pinst,size_t vlst_size)1968 gfx_rv chr_instance_alloc( chr_instance_t * pinst, size_t vlst_size )
1969 {
1970     if ( NULL == pinst )
1971     {
1972         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1973         return gfx_error;
1974     }
1975 
1976     chr_instance_free( pinst );
1977 
1978     if ( 0 == vlst_size ) return gfx_success;
1979 
1980     pinst->vrt_lst = EGOBOO_NEW_ARY( GLvertex, vlst_size );
1981     if ( NULL != pinst->vrt_lst )
1982     {
1983         pinst->vrt_count = vlst_size;
1984     }
1985 
1986     return ( NULL != pinst->vrt_lst ) ? gfx_success : gfx_fail;
1987 }
1988 
1989 //--------------------------------------------------------------------------------------------
chr_instance_set_mad(chr_instance_t * pinst,const MAD_REF imad)1990 gfx_rv chr_instance_set_mad( chr_instance_t * pinst, const MAD_REF imad )
1991 {
1992     /// @details BB@> try to set the model used by the character instance.
1993     ///     If this fails, it leaves the old data. Just to be safe it
1994     ///     would be best to check whether the old modes is valid, and
1995     ///     if not, the data chould be set to safe values...
1996 
1997     mad_t * pmad;
1998     bool_t updated = bfalse;
1999     size_t vlst_size;
2000 
2001     if ( NULL == pinst )
2002     {
2003         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2004         return gfx_error;
2005     }
2006 
2007     if ( !LOADED_MAD( imad ) ) return gfx_fail;
2008     pmad = MadStack.lst + imad;
2009 
2010     if ( pmad->md2_ptr == NULL )
2011     {
2012         log_error( "Invalid pmad instance spawn. (Slot number %i)\n", imad );
2013         return gfx_fail;
2014     }
2015 
2016     if ( pinst->imad != imad )
2017     {
2018         updated = btrue;
2019         pinst->imad = imad;
2020     }
2021 
2022     // set the vertex size
2023     vlst_size = md2_get_numVertices( pmad->md2_ptr );
2024     if ( pinst->vrt_count != vlst_size )
2025     {
2026         updated = btrue;
2027         chr_instance_alloc( pinst, vlst_size );
2028     }
2029 
2030     // set the frames to frame 0 of this object's data
2031     if ( 0 != pinst->frame_nxt || 0 != pinst->frame_lst )
2032     {
2033         updated = btrue;
2034         pinst->frame_nxt = pinst->frame_lst = 0;
2035 
2036         // the vlst_cache parameters are not valid
2037         pinst->save.valid = bfalse;
2038     }
2039 
2040     if ( updated )
2041     {
2042         // update the vertex and lighting cache
2043         chr_instance_clear_cache( pinst );
2044         chr_instance_update_vertices( pinst, -1, -1, btrue );
2045     }
2046 
2047     return updated ? gfx_success : gfx_fail;
2048 }
2049 
2050 //--------------------------------------------------------------------------------------------
chr_instance_update_ref(chr_instance_t * pinst,float grid_level,bool_t need_matrix)2051 gfx_rv chr_instance_update_ref( chr_instance_t * pinst, float grid_level, bool_t need_matrix )
2052 {
2053     int startalpha;
2054 
2055     if ( NULL == pinst )
2056     {
2057         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2058         return gfx_error;
2059     }
2060 
2061     if ( need_matrix )
2062     {
2063         // reflect the ordinary matrix
2064         apply_reflection_matrix( pinst, grid_level );
2065     }
2066 
2067     startalpha = 255;
2068     if ( pinst->ref.matrix_valid )
2069     {
2070         float pos_z;
2071 
2072         // determine the reflection alpha
2073         pos_z = grid_level - pinst->ref.matrix.CNV( 3, 2 );
2074         if ( pos_z < 0.0f ) pos_z = 0.0f;
2075 
2076         startalpha -= 2.0f * pos_z;
2077         startalpha *= 0.5f;
2078         startalpha = CLIP( startalpha, 0, 255 );
2079     }
2080 
2081     pinst->ref.alpha = ( pinst->alpha * startalpha * INV_FF );
2082     pinst->ref.light = ( 255 == pinst->light ) ? 255 : ( pinst->light * startalpha * INV_FF );
2083 
2084     pinst->ref.redshift = pinst->redshift + 1;
2085     pinst->ref.grnshift = pinst->grnshift + 1;
2086     pinst->ref.blushift = pinst->blushift + 1;
2087 
2088     pinst->ref.sheen    = pinst->sheen >> 1;
2089 
2090     return gfx_success;
2091 }
2092 
2093 //--------------------------------------------------------------------------------------------
chr_instance_spawn(chr_instance_t * pinst,const PRO_REF profile,Uint8 skin)2094 gfx_rv chr_instance_spawn( chr_instance_t * pinst, const PRO_REF profile, Uint8 skin )
2095 {
2096     Sint8 greensave = 0, redsave = 0, bluesave = 0;
2097 
2098     pro_t * pobj;
2099     cap_t * pcap;
2100 
2101     if ( NULL == pinst )
2102     {
2103         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2104         return gfx_error;
2105     }
2106 
2107     // Remember any previous color shifts in case of lasting enchantments
2108     greensave = pinst->grnshift;
2109     redsave   = pinst->redshift;
2110     bluesave  = pinst->blushift;
2111 
2112     // clear the instance
2113     chr_instance_ctor( pinst );
2114 
2115     if ( !LOADED_PRO( profile ) ) return gfx_fail;
2116     pobj = ProList.lst + profile;
2117 
2118     pcap = pro_get_pcap( profile );
2119 
2120     // lighting parameters
2121     chr_instance_set_texture( pinst, pobj->tex_ref[skin] );
2122     pinst->enviro    = pcap->enviro;
2123     pinst->alpha     = pcap->alpha;
2124     pinst->light     = pcap->light;
2125     pinst->sheen     = pcap->sheen;
2126     pinst->grnshift  = greensave;
2127     pinst->redshift  = redsave;
2128     pinst->blushift  = bluesave;
2129     pinst->dont_cull_backfaces = pcap->dont_cull_backfaces;
2130 
2131     // model parameters
2132     chr_instance_set_mad( pinst, pro_get_imad( profile ) );
2133 
2134     // set the initial action, all actions override it
2135     chr_instance_play_action( pinst, ACTION_DA, btrue );
2136 
2137     // upload these parameters to the reflection cache, but don't compute the matrix
2138     chr_instance_update_ref( pinst, 0, bfalse );
2139 
2140     return gfx_success;
2141 }
2142 
2143 //--------------------------------------------------------------------------------------------
chr_instance_get_framefx(chr_instance_t * pinst)2144 BIT_FIELD chr_instance_get_framefx( chr_instance_t * pinst )
2145 {
2146     int           frame_count;
2147     MD2_Frame_t * frame_list, * pframe_nxt;
2148     mad_t       * pmad;
2149     MD2_Model_t * pmd2;
2150 
2151     if ( NULL == pinst ) return 0;
2152 
2153     if ( !LOADED_MAD( pinst->imad ) ) return 0;
2154     pmad = MadStack.lst + pinst->imad;
2155 
2156     if ( NULL == pmad->md2_ptr ) return 0;
2157     pmd2 = pmad->md2_ptr;
2158 
2159     frame_count = md2_get_numFrames( pmd2 );
2160     if ( pinst->frame_nxt > frame_count )
2161     {
2162         log_error( "chr_instance_get_framefx() - invalid frame %d/%d\n", pinst->frame_nxt, frame_count );
2163     }
2164 
2165     frame_list  = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
2166     pframe_nxt  = frame_list + pinst->frame_nxt;
2167 
2168     return pframe_nxt->framefx;
2169 }
2170 
2171 //--------------------------------------------------------------------------------------------
chr_instance_set_frame_full(chr_instance_t * pinst,int frame_along,int ilip,MAD_REF mad_override)2172 gfx_rv chr_instance_set_frame_full( chr_instance_t * pinst, int frame_along, int ilip, MAD_REF mad_override )
2173 {
2174     MAD_REF imad;
2175     mad_t * pmad;
2176     int     frame_stt, frame_end, frame_count;
2177 
2178     int    new_nxt;
2179 
2180     if ( NULL == pinst )
2181     {
2182         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2183         return gfx_error;
2184     }
2185 
2186     // handle optional parameters
2187     if ( VALID_MAD_RANGE( mad_override ) )
2188     {
2189         imad = mad_override;
2190     }
2191     else
2192     {
2193         imad = pinst->imad;
2194     }
2195 
2196     if ( !LOADED_MAD( imad ) )
2197     {
2198         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, imad, "invalid mad" );
2199         return gfx_error;
2200     }
2201     pmad = MadStack.lst + imad;
2202 
2203     // we have to have a valid action range
2204     if ( pinst->action_which > ACTION_COUNT ) return gfx_fail;
2205 
2206     // try to heal a bad action
2207     if ( pinst->action_which != pmad->action_map[pinst->action_which] )
2208     {
2209         pinst->action_which = pmad->action_map[pinst->action_which];
2210     }
2211 
2212     // reject the action if it is cannot be made valid
2213     if ( pinst->action_which == ACTION_COUNT ) return gfx_fail;
2214 
2215     // get some frame info
2216     frame_stt   = pmad->action_stt[pinst->action_which];
2217     frame_end   = pmad->action_end[pinst->action_which];
2218     frame_count = 1 + ( frame_end - frame_stt );
2219 
2220     // try to heal an out of range value
2221     frame_along %= frame_count;
2222 
2223     //get the next frames
2224     new_nxt = frame_stt + frame_along;
2225     new_nxt = MIN( new_nxt, frame_end - 1 );
2226 
2227     pinst->frame_nxt  = new_nxt;
2228     pinst->ilip       = ilip;
2229     pinst->flip       = ilip * 0.25f;
2230 
2231     // set the validity of the cache
2232     vlst_cache_test( &( pinst->save ), pinst );
2233 
2234     return gfx_success;
2235 }
2236 
2237 //--------------------------------------------------------------------------------------------
chr_instance_set_action_keep(chr_instance_t * pinst,bool_t val)2238 gfx_rv chr_instance_set_action_keep( chr_instance_t * pinst, bool_t val )
2239 {
2240     if ( NULL == pinst )
2241     {
2242         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2243         return gfx_error;
2244     }
2245 
2246     pinst->action_keep = val;
2247 
2248     return gfx_success;
2249 }
2250 
2251 //--------------------------------------------------------------------------------------------
chr_instance_set_action_ready(chr_instance_t * pinst,bool_t val)2252 gfx_rv chr_instance_set_action_ready( chr_instance_t * pinst, bool_t val )
2253 {
2254     if ( NULL == pinst )
2255     {
2256         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2257         return gfx_error;
2258     }
2259 
2260     pinst->action_ready = val;
2261 
2262     return gfx_success;
2263 }
2264 
2265 //--------------------------------------------------------------------------------------------
chr_instance_set_action_loop(chr_instance_t * pinst,bool_t val)2266 gfx_rv chr_instance_set_action_loop( chr_instance_t * pinst, bool_t val )
2267 {
2268     if ( NULL == pinst )
2269     {
2270         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2271         return gfx_error;
2272     }
2273 
2274     pinst->action_loop = val;
2275 
2276     return gfx_success;
2277 }
2278 
2279 //--------------------------------------------------------------------------------------------
chr_instance_set_action_next(chr_instance_t * pinst,int val)2280 gfx_rv chr_instance_set_action_next( chr_instance_t * pinst, int val )
2281 {
2282     if ( NULL == pinst )
2283     {
2284         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2285         return gfx_error;
2286     }
2287 
2288     if ( val < 0 || val > ACTION_COUNT ) return gfx_fail;
2289 
2290     pinst->action_next = val;
2291 
2292     return gfx_success;
2293 }
2294 
2295 //--------------------------------------------------------------------------------------------
chr_instance_remove_interpolation(chr_instance_t * pinst)2296 gfx_rv chr_instance_remove_interpolation( chr_instance_t * pinst )
2297 {
2298     if ( NULL == pinst )
2299     {
2300         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2301         return gfx_error;
2302     }
2303 
2304     if ( pinst->frame_lst != pinst->frame_nxt )
2305     {
2306         pinst->frame_lst = pinst->frame_nxt;
2307         pinst->ilip      = 0;
2308         pinst->flip      = 0.0f;
2309 
2310         vlst_cache_test( &( pinst->save ), pinst );
2311     }
2312 
2313     return gfx_success;
2314 }
2315 
2316 //--------------------------------------------------------------------------------------------
chr_instnce_get_frame_nxt(chr_instance_t * pinst)2317 MD2_Frame_t * chr_instnce_get_frame_nxt( chr_instance_t * pinst )
2318 {
2319     mad_t       * pmad;
2320     MD2_Model_t * pmd2;
2321     MD2_Frame_t * frame_list;
2322     int           frame_count;
2323 
2324     if ( NULL == pinst ) return NULL;
2325 
2326     if ( !LOADED_MAD( pinst->imad ) ) return NULL;
2327     pmad = MadStack.lst + pinst->imad;
2328 
2329     if ( NULL == pmad->md2_ptr ) return NULL;
2330     pmd2 = pmad->md2_ptr;
2331 
2332     frame_count = md2_get_numFrames( pmd2 );
2333     if ( pinst->frame_nxt < 0 || pinst->frame_nxt > frame_count ) return NULL;
2334 
2335     frame_list  = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
2336 
2337     return frame_list + pinst->frame_nxt;
2338 }
2339 
2340 //--------------------------------------------------------------------------------------------
chr_instnce_get_frame_lst(chr_instance_t * pinst)2341 MD2_Frame_t * chr_instnce_get_frame_lst( chr_instance_t * pinst )
2342 {
2343     mad_t       * pmad;
2344     MD2_Model_t * pmd2;
2345     MD2_Frame_t * frame_list;
2346     int           frame_count;
2347 
2348     if ( NULL == pinst ) return NULL;
2349 
2350     if ( !LOADED_MAD( pinst->imad ) ) return NULL;
2351     pmad = MadStack.lst + pinst->imad;
2352 
2353     if ( NULL == pmad->md2_ptr ) return NULL;
2354     pmd2 = pmad->md2_ptr;
2355 
2356     frame_count = md2_get_numFrames( pmd2 );
2357     if ( pinst->frame_lst < 0 || pinst->frame_lst > frame_count ) return NULL;
2358 
2359     frame_list  = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
2360 
2361     return frame_list + pinst->frame_lst;
2362 }
2363 
2364 //--------------------------------------------------------------------------------------------
chr_instance_update_one_lip(chr_instance_t * pinst)2365 gfx_rv chr_instance_update_one_lip( chr_instance_t * pinst )
2366 {
2367     if ( NULL == pinst )
2368     {
2369         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2370         return gfx_error;
2371     }
2372 
2373     pinst->ilip += 1;
2374     pinst->flip = 0.25f * pinst->ilip;
2375 
2376     vlst_cache_test( &( pinst->save ), pinst );
2377 
2378     return gfx_success;
2379 }
2380 
2381 //--------------------------------------------------------------------------------------------
chr_instance_update_one_flip(chr_instance_t * pinst,float dflip)2382 gfx_rv chr_instance_update_one_flip( chr_instance_t * pinst, float dflip )
2383 {
2384     if ( NULL == pinst )
2385     {
2386         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2387         return gfx_error;
2388     }
2389 
2390     if ( 0.0f == dflip ) return gfx_fail;
2391 
2392     // update the lips
2393     pinst->flip += dflip;
2394     pinst->ilip  = (( int )FLOOR( pinst->flip * 4 ) ) % 4;
2395 
2396     vlst_cache_test( &( pinst->save ), pinst );
2397 
2398     return gfx_success;
2399 }
2400 
2401 //--------------------------------------------------------------------------------------------
chr_instance_get_remaining_flip(chr_instance_t * pinst)2402 float chr_instance_get_remaining_flip( chr_instance_t * pinst )
2403 {
2404     float remaining = 0.0f;
2405 
2406     if ( NULL == pinst ) return 0.0f;
2407 
2408     remaining = ( pinst->ilip + 1 ) * 0.25f - pinst->flip;
2409 
2410     return remaining;
2411 }
2412 
2413 //--------------------------------------------------------------------------------------------
2414 //--------------------------------------------------------------------------------------------
chr_reflection_cache_init(chr_reflection_cache_t * pcache)2415 chr_reflection_cache_t * chr_reflection_cache_init( chr_reflection_cache_t * pcache )
2416 {
2417     if ( NULL == pcache ) return pcache;
2418 
2419     memset( pcache, 0, sizeof( *pcache ) );
2420 
2421     pcache->alpha = 127;
2422     pcache->light = 255;
2423 
2424     return pcache;
2425 }
2426 
2427 //--------------------------------------------------------------------------------------------
2428 //--------------------------------------------------------------------------------------------
vlst_cache_init(vlst_cache_t * pcache)2429 vlst_cache_t * vlst_cache_init( vlst_cache_t * pcache )
2430 {
2431     if ( NULL == pcache ) return NULL;
2432 
2433     memset( pcache, 0, sizeof( *pcache ) );
2434 
2435     pcache->vmin = -1;
2436     pcache->vmax = -1;
2437 
2438     return pcache;
2439 }
2440 
2441 //--------------------------------------------------------------------------------------------
vlst_cache_test(vlst_cache_t * pcache,chr_instance_t * pinst)2442 gfx_rv vlst_cache_test( vlst_cache_t * pcache, chr_instance_t * pinst )
2443 {
2444     if ( NULL == pcache )
2445     {
2446         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL cache" );
2447         return gfx_error;
2448     }
2449 
2450     if ( !pcache->valid ) return gfx_success;
2451 
2452     if ( NULL == pinst )
2453     {
2454         pcache->valid = bfalse;
2455         return gfx_success;
2456     }
2457 
2458     if ( pinst->frame_lst != pcache->frame_nxt )
2459     {
2460         pcache->valid = bfalse;
2461     }
2462 
2463     if ( pinst->frame_lst != pcache->frame_lst )
2464     {
2465         pcache->valid = bfalse;
2466     }
2467 
2468     if (( pinst->frame_lst != pinst->frame_lst )  && ABS( pcache->flip - pinst->flip ) > flip_tolerance )
2469     {
2470         pcache->valid = bfalse;
2471     }
2472 
2473     return gfx_success;
2474 }
2475 
2476 //--------------------------------------------------------------------------------------------
2477 //--------------------------------------------------------------------------------------------
matrix_cache_init(matrix_cache_t * mcache)2478 matrix_cache_t * matrix_cache_init( matrix_cache_t * mcache )
2479 {
2480     /// @details BB@> clear out the matrix cache data
2481 
2482     int cnt;
2483 
2484     if ( NULL == mcache ) return mcache;
2485 
2486     memset( mcache, 0, sizeof( *mcache ) );
2487 
2488     mcache->type_bits = MAT_UNKNOWN;
2489     mcache->grip_chr  = ( CHR_REF )MAX_CHR;
2490     for ( cnt = 0; cnt < GRIP_VERTS; cnt++ )
2491     {
2492         mcache->grip_verts[cnt] = 0xFFFF;
2493     }
2494 
2495     mcache->rotate.x = 0;
2496     mcache->rotate.y = 0;
2497     mcache->rotate.z = 0;
2498 
2499     return mcache;
2500 }
2501 
2502 //--------------------------------------------------------------------------------------------
chr_instance_set_texture(chr_instance_t * pinst,TX_REF itex)2503 gfx_rv chr_instance_set_texture( chr_instance_t * pinst, TX_REF itex )
2504 {
2505     oglx_texture_t * ptex;
2506 
2507     if ( NULL == pinst )
2508     {
2509         gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
2510         return gfx_error;
2511     }
2512 
2513     // grab the texture
2514     ptex = TxTexture_get_ptr( itex );
2515 
2516     // get the transparency info from the texture
2517     pinst->skin_has_transparency = bfalse;
2518     if ( NULL != ptex )
2519     {
2520         pinst->skin_has_transparency = ( bool_t )ptex->has_alpha;
2521     }
2522 
2523     // set the texture index
2524     pinst->texture = itex;
2525 
2526     return gfx_success;
2527 }
2528 
2529