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