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_prt.c
21 /// @brief Particle system drawing and management code.
22 /// @details
23
24 #include "graphic_prt.h"
25
26 #include "particle.inl"
27 #include "char.inl"
28 #include "profile.inl"
29
30 #include "game.h"
31 #include "texture.h"
32 #include "camera.h"
33 #include "input.h"
34 #include "lighting.h"
35
36 #include "egoboo_setup.h"
37 #include "egoboo.h"
38
39 //--------------------------------------------------------------------------------------------
40 //--------------------------------------------------------------------------------------------
41 // dynamically calculate the particle texture coordinates
42
43 int ptex_w[2] = {256, 256};
44 int ptex_h[2] = {256, 256};
45 float ptex_wscale[2] = {1.0f, 1.0f};
46 float ptex_hscale[2] = {1.0f, 1.0f};
47
48 //--------------------------------------------------------------------------------------------
prt_get_texture_style(const TX_REF itex)49 int prt_get_texture_style( const TX_REF itex )
50 {
51 int index;
52
53 index = -1;
54 switch ( REF_TO_INT( itex ) )
55 {
56 case TX_PARTICLE_TRANS:
57 index = 0;
58 break;
59
60 case TX_PARTICLE_LIGHT:
61 index = 1;
62 break;
63 }
64
65 return index;
66 }
67
68 //--------------------------------------------------------------------------------------------
prt_set_texture_params(const TX_REF itex)69 void prt_set_texture_params( const TX_REF itex )
70 {
71 int index;
72 oglx_texture_t * ptex;
73
74 index = prt_get_texture_style( itex );
75 if ( index < 0 ) return;
76
77 ptex = TxTexture_get_ptr( itex );
78 if ( NULL == ptex ) return;
79
80 ptex_w[index] = ptex->imgW;
81 ptex_h[index] = ptex->imgH;
82 ptex_wscale[index] = ( float )ptex->imgW / ( float )ptex->base.width;
83 ptex_hscale[index] = ( float )ptex->imgH / ( float )ptex->base.height;
84 }
85
86 //--------------------------------------------------------------------------------------------
87 //--------------------------------------------------------------------------------------------
88
89 /// The data values necessary to sort particles by their position to the camera
90 struct s_prt_registry_entity
91 {
92 PRT_REF index;
93 float dist;
94 };
95 typedef struct s_prt_registry_entity prt_registry_entity_t;
96
97 //--------------------------------------------------------------------------------------------
98 //--------------------------------------------------------------------------------------------
99 static gfx_rv prt_instance_update( camera_t * pcam, const PRT_REF particle, Uint8 trans, bool_t do_lighting );
100 static void calc_billboard_verts( GLvertex vlst[], prt_instance_t * pinst, float size, bool_t do_reflect );
101 static int cmp_prt_registry_entity( const void * vlhs, const void * vrhs );
102
103 static void draw_one_attachment_point( chr_instance_t * pinst, mad_t * pmad, int vrt_offset );
104 static void prt_draw_attached_point( prt_bundle_t * pbdl_prt );
105
106 static void render_prt_bbox( prt_bundle_t * pbdl_prt );
107
108 //--------------------------------------------------------------------------------------------
109 //--------------------------------------------------------------------------------------------
110 Uint32 instance_update = ( Uint32 )~0;
111
112 //--------------------------------------------------------------------------------------------
113 //--------------------------------------------------------------------------------------------
cmp_prt_registry_entity(const void * vlhs,const void * vrhs)114 int cmp_prt_registry_entity( const void * vlhs, const void * vrhs )
115 {
116 const prt_registry_entity_t * lhs, * rhs;
117
118 lhs = ( prt_registry_entity_t * ) vlhs;
119 rhs = ( prt_registry_entity_t * ) vrhs;
120
121 return lhs->dist - rhs->dist;
122 }
123
124 //--------------------------------------------------------------------------------------------
125 //--------------------------------------------------------------------------------------------
render_all_prt_begin(camera_t * pcam,prt_registry_entity_t reg[],size_t reg_count)126 size_t render_all_prt_begin( camera_t * pcam, prt_registry_entity_t reg[], size_t reg_count )
127 {
128 fvec3_t vfwd, vcam;
129 size_t numparticle;
130
131 update_all_prt_instance( pcam );
132
133 mat_getCamForward( pcam->mView.v, vfwd.v );
134 vcam = pcam->pos;
135
136 // Original points
137 numparticle = 0;
138 PRT_BEGIN_LOOP_DISPLAY( iprt, prt_bdl )
139 {
140 prt_instance_t * pinst;
141
142 if ( numparticle >= reg_count ) break;
143
144 pinst = &( prt_bdl.prt_ptr->inst );
145
146 if ( !pinst->indolist ) continue;
147
148 if ( 0 != pinst->size )
149 {
150 fvec3_t vpos;
151 float dist;
152
153 vpos.x = pinst->pos.x - vcam.x;
154 vpos.y = pinst->pos.y - vcam.y;
155 vpos.z = pinst->pos.z - vcam.z;
156
157 dist = fvec3_dot_product( vfwd.v, vpos.v );
158
159 if ( dist > 0 )
160 {
161 reg[numparticle].index = REF_TO_INT( prt_bdl.prt_ref );
162 reg[numparticle].dist = dist;
163 numparticle++;
164 }
165 }
166 }
167 PRT_END_LOOP();
168
169 // sort the particles from close to far
170 qsort( reg, numparticle, sizeof( prt_registry_entity_t ), cmp_prt_registry_entity );
171
172 return numparticle;
173 }
174
175 //--------------------------------------------------------------------------------------------
render_one_prt_solid(const PRT_REF iprt)176 gfx_rv render_one_prt_solid( const PRT_REF iprt )
177 {
178 /// @details BB@> Render the solid version of the particle
179
180 GLvertex vtlist[4];
181 int i;
182
183 prt_t * pprt;
184 prt_instance_t * pinst;
185
186 if ( !DISPLAY_PRT( iprt ) )
187 {
188 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, iprt, "invalid particle" );
189 return gfx_error;
190 }
191 pprt = PrtList.lst + iprt;
192
193 // if the particle is hidden, do not continue
194 if ( pprt->is_hidden ) return gfx_fail;
195
196 // if the particle instance data is not valid, do not continue
197 if ( !pprt->inst.valid ) return gfx_fail;
198 pinst = &( pprt->inst );
199
200 // only render solid sprites
201 if ( SPRITE_SOLID != pprt->type ) return gfx_fail;
202
203 // billboard for the particle
204 calc_billboard_verts( vtlist, pinst, pinst->size, bfalse );
205
206 ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT );
207 {
208 // Use the depth test to eliminate hidden portions of the particle
209 GL_DEBUG( glEnable )( GL_DEPTH_TEST ); // GL_ENABLE_BIT
210 GL_DEBUG( glDepthFunc )( GL_LESS ); // GL_DEPTH_BUFFER_BIT
211
212 // enable the depth mask for the solid portion of the particles
213 GL_DEBUG( glDepthMask )( GL_TRUE ); // GL_ENABLE_BIT
214
215 // draw draw front and back faces of polygons
216 GL_DEBUG( glDisable )( GL_CULL_FACE ); // GL_ENABLE_BIT
217
218 // Since the textures are probably mipmapped or minified with some kind of
219 // interpolation, we can never really turn blending off,
220 GL_DEBUG( glEnable )( GL_BLEND ); // GL_ENABLE_BIT
221 GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // GL_ENABLE_BIT
222
223 // only display the portion of the particle that is
224 // 100% solid
225 GL_DEBUG( glEnable )( GL_ALPHA_TEST ); // GL_ENABLE_BIT
226 GL_DEBUG( glAlphaFunc )( GL_EQUAL, 1.0f ); // GL_COLOR_BUFFER_BIT
227
228 oglx_texture_Bind( TxTexture_get_ptr(( TX_REF )TX_PARTICLE_TRANS ) );
229
230 GL_DEBUG( glColor4f )( pinst->fintens, pinst->fintens, pinst->fintens, 1.0f ); // GL_CURRENT_BIT
231
232 GL_DEBUG( glBegin )( GL_TRIANGLE_FAN );
233 {
234 for ( i = 0; i < 4; i++ )
235 {
236 GL_DEBUG( glTexCoord2fv )( vtlist[i].tex );
237 GL_DEBUG( glVertex3fv )( vtlist[i].pos );
238 }
239 }
240 GL_DEBUG_END();
241 }
242 ATTRIB_POP( __FUNCTION__ );
243
244 return gfx_success;
245 }
246
247 //--------------------------------------------------------------------------------------------
render_all_prt_solid(camera_t * pcam,prt_registry_entity_t reg[],size_t numparticle)248 void render_all_prt_solid( camera_t * pcam, prt_registry_entity_t reg[], size_t numparticle )
249 {
250 /// @details BB@> do solid sprites first
251
252 size_t cnt;
253 PRT_REF prt;
254
255 gfx_begin_3d( pcam );
256 {
257 // apply solid particles from near to far
258 for ( cnt = 0; cnt < numparticle; cnt++ )
259 {
260 // Get the index from the color slot
261 prt = reg[cnt].index;
262
263 render_one_prt_solid( prt );
264 }
265 }
266 gfx_end_3d();
267 }
268
269 //--------------------------------------------------------------------------------------------
render_one_prt_trans(const PRT_REF iprt)270 gfx_rv render_one_prt_trans( const PRT_REF iprt )
271 {
272 /// @details BB@> do all kinds of transparent sprites next
273
274 GLvertex vtlist[4];
275 int i;
276 prt_t * pprt;
277 prt_instance_t * pinst;
278
279 if ( !DISPLAY_PRT( iprt ) )
280 {
281 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, iprt, "invalid particle" );
282 return gfx_error;
283 }
284 pprt = PrtList.lst + iprt;
285
286 // if the particle is hidden, do not continue
287 if ( pprt->is_hidden ) return gfx_fail;
288
289 // if the particle instance data is not valid, do not continue
290 if ( !pprt->inst.valid ) return gfx_fail;
291 pinst = &( pprt->inst );
292
293 ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT );
294 {
295 bool_t draw_particle;
296 GLXvector4f particle_color;
297
298 // don't write into the depth buffer (disable glDepthMask for transparent objects)
299 GL_DEBUG( glDepthMask )( GL_FALSE ); // GL_DEPTH_BUFFER_BIT
300
301 // do not draw hidden surfaces
302 GL_DEBUG( glEnable )( GL_DEPTH_TEST ); // GL_ENABLE_BIT
303 GL_DEBUG( glDepthFunc )( GL_LEQUAL ); // GL_DEPTH_BUFFER_BIT
304
305 // draw draw front and back faces of polygons
306 GL_DEBUG( glDisable )( GL_CULL_FACE ); // ENABLE_BIT
307
308 draw_particle = bfalse;
309 if ( SPRITE_SOLID == pprt->type )
310 {
311 // do the alpha blended edge ("anti-aliasing") of the solid particle
312
313 // only display the alpha-edge of the particle
314 GL_DEBUG( glEnable )( GL_ALPHA_TEST ); // GL_ENABLE_BIT
315 GL_DEBUG( glAlphaFunc )( GL_LESS, 1.0f ); // GL_COLOR_BUFFER_BIT
316
317 GL_DEBUG( glEnable )( GL_BLEND ); // GL_ENABLE_BIT
318 GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // GL_COLOR_BUFFER_BIT
319
320 particle_color[RR] = pinst->fintens;
321 particle_color[GG] = pinst->fintens;
322 particle_color[BB] = pinst->fintens;
323 particle_color[AA] = 1.0f;
324
325 pinst->texture_ref = TX_PARTICLE_TRANS;
326 oglx_texture_Bind( TxTexture_get_ptr( pinst->texture_ref ) );
327
328 draw_particle = btrue;
329 }
330 else if ( SPRITE_LIGHT == pprt->type )
331 {
332 // do the light sprites
333 float intens = pinst->fintens * pinst->falpha;
334
335 GL_DEBUG( glDisable )( GL_ALPHA_TEST ); // GL_ENABLE_BIT
336
337 GL_DEBUG( glEnable )( GL_BLEND ); // GL_ENABLE_BIT
338 GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE ); // GL_COLOR_BUFFER_BIT
339
340 particle_color[RR] = intens;
341 particle_color[GG] = intens;
342 particle_color[BB] = intens;
343 particle_color[AA] = 1.0f;
344
345 pinst->texture_ref = TX_PARTICLE_LIGHT;
346 oglx_texture_Bind( TxTexture_get_ptr( pinst->texture_ref ) );
347
348 draw_particle = ( intens > 0.0f );
349 }
350 else if ( SPRITE_ALPHA == pprt->type )
351 {
352 // do the transparent sprites
353
354 // do not display the completely transparent portion
355 GL_DEBUG( glEnable )( GL_ALPHA_TEST ); // GL_ENABLE_BIT
356 GL_DEBUG( glAlphaFunc )( GL_GREATER, 0.0f ); // GL_COLOR_BUFFER_BIT
357
358 GL_DEBUG( glEnable )( GL_BLEND ); // GL_ENABLE_BIT
359 GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // GL_COLOR_BUFFER_BIT
360
361 particle_color[RR] = pinst->fintens;
362 particle_color[GG] = pinst->fintens;
363 particle_color[BB] = pinst->fintens;
364 particle_color[AA] = pinst->falpha;
365
366 pinst->texture_ref = TX_PARTICLE_TRANS;
367 oglx_texture_Bind( TxTexture_get_ptr( pinst->texture_ref ) );
368
369 draw_particle = ( pinst->falpha > 0.0f );
370 }
371 else
372 {
373 // unknown type
374 return gfx_error;
375 }
376
377 if ( draw_particle )
378 {
379 calc_billboard_verts( vtlist, pinst, pinst->size, bfalse );
380
381 GL_DEBUG( glColor4fv )( particle_color ); // GL_CURRENT_BIT
382
383 // Go on and draw it
384 GL_DEBUG( glBegin )( GL_TRIANGLE_FAN );
385 {
386 for ( i = 0; i < 4; i++ )
387 {
388 GL_DEBUG( glTexCoord2fv )( vtlist[i].tex );
389 GL_DEBUG( glVertex3fv )( vtlist[i].pos );
390 }
391 }
392 GL_DEBUG_END();
393 }
394 }
395 ATTRIB_POP( __FUNCTION__ );
396
397 return gfx_success;
398 }
399
400 //--------------------------------------------------------------------------------------------
render_all_prt_trans(camera_t * pcam,prt_registry_entity_t reg[],size_t numparticle)401 void render_all_prt_trans( camera_t * pcam, prt_registry_entity_t reg[], size_t numparticle )
402 {
403 /// @details BB@> do all kinds of transparent sprites next
404
405 int cnt;
406
407 gfx_begin_3d( pcam );
408 {
409 // apply transparent particles from far to near
410 for ( cnt = (( int )numparticle ) - 1; cnt >= 0; cnt-- )
411 {
412 // Get the index from the color slot
413 render_one_prt_trans(( PRT_REF )reg[cnt].index );
414 }
415 }
416 gfx_end_3d();
417 }
418
419 //--------------------------------------------------------------------------------------------
render_all_particles(camera_t * pcam)420 void render_all_particles( camera_t * pcam )
421 {
422 /// @details ZZ@> This function draws the sprites for particle systems
423
424 prt_registry_entity_t reg[MAX_PRT];
425 size_t numparticle;
426
427 numparticle = render_all_prt_begin( pcam, reg, MAX_PRT );
428
429 render_all_prt_solid( pcam, reg, numparticle );
430 render_all_prt_trans( pcam, reg, numparticle );
431 }
432
433 //--------------------------------------------------------------------------------------------
434 //--------------------------------------------------------------------------------------------
render_all_prt_ref_begin(camera_t * pcam,prt_registry_entity_t reg[],size_t reg_count)435 size_t render_all_prt_ref_begin( camera_t * pcam, prt_registry_entity_t reg[], size_t reg_count )
436 {
437 fvec3_t vfwd, vcam;
438 size_t numparticle;
439
440 update_all_prt_instance( pcam );
441
442 mat_getCamForward( pcam->mView.v, vfwd.v );
443 vcam = pcam->pos;
444
445 // Original points
446 numparticle = 0;
447 PRT_BEGIN_LOOP_DISPLAY( iprt, prt_bdl )
448 {
449 prt_instance_t * pinst;
450 fvec3_t vpos;
451 float dist;
452
453 if ( numparticle >= reg_count ) break;
454
455 pinst = &( prt_bdl.prt_ptr->inst );
456
457 if ( !pinst->indolist ) continue;
458
459 vpos = fvec3_sub( pinst->ref_pos.v, vcam.v );
460 dist = fvec3_dot_product( vfwd.v, vpos.v );
461
462 if ( dist > 0 )
463 {
464 reg[numparticle].index = REF_TO_INT( iprt );
465 reg[numparticle].dist = dist;
466 numparticle++;
467 }
468
469 }
470 PRT_END_LOOP();
471
472 // sort the particles from close to far
473 qsort( reg, numparticle, sizeof( prt_registry_entity_t ), cmp_prt_registry_entity );
474
475 return numparticle;
476 }
477
478 //--------------------------------------------------------------------------------------------
render_one_prt_ref(const PRT_REF iprt)479 gfx_rv render_one_prt_ref( const PRT_REF iprt )
480 {
481 /// @details BB@> render one particle
482
483 GLvertex vtlist[4];
484 int startalpha;
485 int i;
486 prt_t * pprt;
487 prt_instance_t * pinst;
488
489 if ( !DISPLAY_PRT( iprt ) )
490 {
491 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, iprt, "invalid particle" );
492 return gfx_error;
493 }
494 pprt = PrtList.lst + iprt;
495
496 // if the particle is hidden, do not continue
497 if ( pprt->is_hidden ) return gfx_fail;
498
499 if ( !pprt->inst.valid || !pprt->inst.ref_valid ) return gfx_fail;
500 pinst = &( pprt->inst );
501
502 // Fill in the rest of the data. (make it match the case for characters)
503 startalpha = 255;
504 startalpha -= 2.0f * ( pprt->enviro.floor_level - pinst->ref_pos.z );
505 startalpha *= 0.5f;
506 startalpha = CLIP( startalpha, 0, 255 );
507
508 //startalpha = ( startalpha | gfx.reffadeor ) >> 1; // Fix for Riva owners
509 //startalpha = CLIP(startalpha, 0, 255);
510
511 if ( startalpha > 0 )
512 {
513 ATTRIB_PUSH( __FUNCTION__, GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT );
514 {
515 bool_t draw_particle;
516 GLXvector4f particle_color;
517
518 // don't write into the depth buffer (disable glDepthMask for transparent objects)
519 GL_DEBUG( glDepthMask )( GL_FALSE ); // ENABLE_BIT
520
521 // do not draw hidden surfaces
522 GL_DEBUG( glEnable )( GL_DEPTH_TEST ); // ENABLE_BIT
523 GL_DEBUG( glDepthFunc )( GL_LEQUAL ); // GL_DEPTH_BUFFER_BIT
524
525 // draw draw front and back faces of polygons
526 GL_DEBUG( glDisable )( GL_CULL_FACE ); // ENABLE_BIT
527
528 draw_particle = bfalse;
529 if ( SPRITE_LIGHT == pprt->type )
530 {
531 // do the light sprites
532 float intens = startalpha * INV_FF * pinst->falpha * pinst->fintens;
533
534 GL_DEBUG( glDisable )( GL_ALPHA_TEST ); // ENABLE_BIT
535
536 GL_DEBUG( glEnable )( GL_BLEND ); // ENABLE_BIT
537 GL_DEBUG( glBlendFunc )( GL_ONE, GL_ONE ); // GL_COLOR_BUFFER_BIT
538
539 particle_color[RR] = intens;
540 particle_color[GG] = intens;
541 particle_color[BB] = intens;
542 particle_color[AA] = 1.0f;
543
544 pinst->texture_ref = TX_PARTICLE_LIGHT;
545 oglx_texture_Bind( TxTexture_get_ptr( pinst->texture_ref ) );
546
547 draw_particle = intens > 0.0f;
548 }
549 else if ( SPRITE_SOLID == pprt->type || SPRITE_ALPHA == pprt->type )
550 {
551 // do the transparent sprites
552
553 float alpha = startalpha * INV_FF;
554 if ( SPRITE_ALPHA == pprt->type )
555 {
556 alpha *= pinst->falpha;
557 }
558
559 // do not display the completely transparent portion
560 GL_DEBUG( glEnable )( GL_ALPHA_TEST ); // ENABLE_BIT
561 GL_DEBUG( glAlphaFunc )( GL_GREATER, 0.0f ); // GL_COLOR_BUFFER_BIT
562
563 GL_DEBUG( glEnable )( GL_BLEND ); // ENABLE_BIT
564 GL_DEBUG( glBlendFunc )( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // GL_COLOR_BUFFER_BIT
565
566 particle_color[RR] = pinst->fintens;
567 particle_color[GG] = pinst->fintens;
568 particle_color[BB] = pinst->fintens;
569 particle_color[AA] = alpha;
570
571 pinst->texture_ref = TX_PARTICLE_TRANS;
572 oglx_texture_Bind( TxTexture_get_ptr( pinst->texture_ref ) );
573
574 draw_particle = alpha > 0.0f;
575 }
576 else
577 {
578 // unknown type
579 return gfx_fail;
580 }
581
582 if ( draw_particle )
583 {
584 // Calculate the position of the four corners of the billboard
585 // used to display the particle.
586 calc_billboard_verts( vtlist, pinst, pinst->size, btrue );
587
588 GL_DEBUG( glColor4fv )( particle_color ); // GL_CURRENT_BIT
589
590 GL_DEBUG( glBegin )( GL_TRIANGLE_FAN );
591 {
592 for ( i = 0; i < 4; i++ )
593 {
594 GL_DEBUG( glTexCoord2fv )( vtlist[i].tex );
595 GL_DEBUG( glVertex3fv )( vtlist[i].pos );
596 }
597 }
598 GL_DEBUG_END();
599 }
600 }
601 ATTRIB_POP( __FUNCTION__ );
602
603 }
604
605 return gfx_success;
606 }
607
608 //--------------------------------------------------------------------------------------------
render_all_prt_ref(camera_t * pcam,prt_registry_entity_t reg[],size_t numparticle)609 void render_all_prt_ref( camera_t * pcam, prt_registry_entity_t reg[], size_t numparticle )
610 {
611 size_t cnt;
612 PRT_REF prt;
613
614 gfx_begin_3d( pcam );
615 {
616 // Render each particle that was on
617 for ( cnt = 0; cnt < numparticle; cnt++ )
618 {
619 // Get the index from the color slot
620 prt = reg[cnt].index;
621
622 render_one_prt_ref(( PRT_REF )reg[cnt].index );
623 }
624 }
625 gfx_end_3d();
626 }
627
628 //--------------------------------------------------------------------------------------------
render_prt_ref(camera_t * pcam)629 void render_prt_ref( camera_t * pcam )
630 {
631 /// @details ZZ@> This function draws sprites reflected in the floor
632
633 prt_registry_entity_t reg[MAX_PRT];
634 size_t numparticle;
635
636 numparticle = render_all_prt_ref_begin( pcam, reg, MAX_PRT );
637 render_all_prt_ref( pcam, reg, numparticle );
638 }
639
640 //--------------------------------------------------------------------------------------------
641 //--------------------------------------------------------------------------------------------
calc_billboard_verts(GLvertex vlst[],prt_instance_t * pinst,float size,bool_t do_reflect)642 void calc_billboard_verts( GLvertex vlst[], prt_instance_t * pinst, float size, bool_t do_reflect )
643 {
644 // Calculate the position of the four corners of the billboard
645 // used to display the particle.
646
647 int i, index;
648 fvec3_t prt_pos, prt_up, prt_right;
649
650 if ( NULL == vlst || NULL == pinst ) return;
651
652 switch ( REF_TO_INT( pinst->texture_ref ) )
653 {
654 default:
655 case TX_PARTICLE_TRANS:
656 index = 0;
657 break;
658
659 case TX_PARTICLE_LIGHT:
660 index = 1;
661 break;
662 }
663
664 // use the pre-computed reflection parameters
665 if ( do_reflect )
666 {
667 prt_pos = pinst->ref_pos;
668 prt_up = pinst->ref_up;
669 prt_right = pinst->ref_right;
670 }
671 else
672 {
673 prt_pos = pinst->pos;
674 prt_up = pinst->up;
675 prt_right = pinst->right;
676 }
677
678 for ( i = 0; i < 4; i++ )
679 {
680 vlst[i].pos[XX] = prt_pos.x;
681 vlst[i].pos[YY] = prt_pos.y;
682 vlst[i].pos[ZZ] = prt_pos.z;
683 }
684
685 vlst[0].pos[XX] += ( -prt_right.x - prt_up.x ) * size;
686 vlst[0].pos[YY] += ( -prt_right.y - prt_up.y ) * size;
687 vlst[0].pos[ZZ] += ( -prt_right.z - prt_up.z ) * size;
688
689 vlst[1].pos[XX] += ( prt_right.x - prt_up.x ) * size;
690 vlst[1].pos[YY] += ( prt_right.y - prt_up.y ) * size;
691 vlst[1].pos[ZZ] += ( prt_right.z - prt_up.z ) * size;
692
693 vlst[2].pos[XX] += ( prt_right.x + prt_up.x ) * size;
694 vlst[2].pos[YY] += ( prt_right.y + prt_up.y ) * size;
695 vlst[2].pos[ZZ] += ( prt_right.z + prt_up.z ) * size;
696
697 vlst[3].pos[XX] += ( -prt_right.x + prt_up.x ) * size;
698 vlst[3].pos[YY] += ( -prt_right.y + prt_up.y ) * size;
699 vlst[3].pos[ZZ] += ( -prt_right.z + prt_up.z ) * size;
700
701 vlst[0].tex[SS] = CALCULATE_PRT_U1( index, pinst->image_ref );
702 vlst[0].tex[TT] = CALCULATE_PRT_V1( index, pinst->image_ref );
703
704 vlst[1].tex[SS] = CALCULATE_PRT_U0( index, pinst->image_ref );
705 vlst[1].tex[TT] = CALCULATE_PRT_V1( index, pinst->image_ref );
706
707 vlst[2].tex[SS] = CALCULATE_PRT_U0( index, pinst->image_ref );
708 vlst[2].tex[TT] = CALCULATE_PRT_V0( index, pinst->image_ref );
709
710 vlst[3].tex[SS] = CALCULATE_PRT_U1( index, pinst->image_ref );
711 vlst[3].tex[TT] = CALCULATE_PRT_V0( index, pinst->image_ref );
712 }
713
714 //--------------------------------------------------------------------------------------------
715 //--------------------------------------------------------------------------------------------
render_all_prt_attachment()716 void render_all_prt_attachment()
717 {
718 GL_DEBUG( glDisable )( GL_BLEND );
719
720 PRT_BEGIN_LOOP_DISPLAY( iprt, prt_bdl )
721 {
722 prt_draw_attached_point( &prt_bdl );
723 }
724 PRT_END_LOOP();
725 }
726
727 //--------------------------------------------------------------------------------------------
render_all_prt_bbox()728 void render_all_prt_bbox()
729 {
730 PRT_BEGIN_LOOP_DISPLAY( iprt, prt_bdl )
731 {
732 render_prt_bbox( &prt_bdl );
733 }
734 PRT_END_LOOP();
735 }
736
737 //--------------------------------------------------------------------------------------------
draw_one_attachment_point(chr_instance_t * pinst,mad_t * pmad,int vrt_offset)738 void draw_one_attachment_point( chr_instance_t * pinst, mad_t * pmad, int vrt_offset )
739 {
740 /// @details BB@> a function that will draw some of the vertices of the given character.
741 /// The original idea was to use this to debug the grip for attached items.
742
743 Uint32 vrt;
744
745 GLint matrix_mode[1];
746 GLboolean texture_1d_enabled, texture_2d_enabled;
747
748 if ( NULL == pinst || NULL == pmad ) return;
749
750 vrt = ( int )pinst->vrt_count - ( int )vrt_offset;
751
752 if ( vrt < 0 || vrt >= pinst->vrt_count ) return;
753
754 texture_1d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_1D );
755 texture_2d_enabled = GL_DEBUG( glIsEnabled )( GL_TEXTURE_2D );
756
757 // disable the texturing so all the points will be white,
758 // not the texture color of the last vertex we drawn
759 if ( texture_1d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_1D );
760 if ( texture_2d_enabled ) GL_DEBUG( glDisable )( GL_TEXTURE_2D );
761
762 GL_DEBUG( glPointSize )( 5 );
763
764 // save the matrix mode
765 GL_DEBUG( glGetIntegerv )( GL_MATRIX_MODE, matrix_mode );
766
767 // store the GL_MODELVIEW matrix (this stack has a finite depth, minimum of 32)
768 GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
769 GL_DEBUG( glPushMatrix )();
770 GL_DEBUG( glMultMatrixf )( pinst->matrix.v );
771
772 GL_DEBUG( glBegin( GL_POINTS ) );
773 {
774 GL_DEBUG( glVertex3fv )( pinst->vrt_lst[vrt].pos );
775 }
776 GL_DEBUG_END();
777
778 // Restore the GL_MODELVIEW matrix
779 GL_DEBUG( glMatrixMode )( GL_MODELVIEW );
780 GL_DEBUG( glPopMatrix )();
781
782 // restore the matrix mode
783 GL_DEBUG( glMatrixMode )( matrix_mode[0] );
784
785 if ( texture_1d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_1D );
786 if ( texture_2d_enabled ) GL_DEBUG( glEnable )( GL_TEXTURE_2D );
787 }
788
789 //--------------------------------------------------------------------------------------------
prt_draw_attached_point(prt_bundle_t * pbdl_prt)790 void prt_draw_attached_point( prt_bundle_t * pbdl_prt )
791 {
792 mad_t * pholder_mad;
793 cap_t * pholder_cap;
794 chr_t * pholder;
795
796 prt_t * loc_pprt;
797
798 if ( NULL == pbdl_prt || NULL == pbdl_prt->prt_ptr ) return;
799 loc_pprt = pbdl_prt->prt_ptr;
800
801 if ( !DISPLAY_PPRT( loc_pprt ) ) return;
802
803 if ( !INGAME_CHR( loc_pprt->attachedto_ref ) ) return;
804 pholder = ChrList.lst + loc_pprt->attachedto_ref;
805
806 pholder_cap = pro_get_pcap( pholder->profile_ref );
807 if ( NULL == pholder_cap ) return;
808
809 pholder_mad = chr_get_pmad( GET_REF_PCHR( pholder ) );
810 if ( NULL == pholder_mad ) return;
811
812 draw_one_attachment_point( &( pholder->inst ), pholder_mad, loc_pprt->attachedto_vrt_off );
813 }
814
815 //--------------------------------------------------------------------------------------------
816 //--------------------------------------------------------------------------------------------
update_all_prt_instance(camera_t * pcam)817 gfx_rv update_all_prt_instance( camera_t * pcam )
818 {
819 gfx_rv retval;
820
821 if ( NULL == pcam ) pcam = PCamera;
822 if ( NULL == pcam )
823 {
824 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "cannot find a valid camera" );
825 return gfx_error;
826 }
827
828 // only one update per frame
829 if ( instance_update == update_wld ) return gfx_success;
830 instance_update = update_wld;
831
832 // assume the best
833 retval = gfx_success;
834
835 PRT_BEGIN_LOOP_DISPLAY( iprt, prt_bdl )
836 {
837 prt_instance_t * pinst;
838
839 pinst = &( prt_bdl.prt_ptr->inst );
840
841 // only do frame counting for particles that are fully activated!
842 prt_bdl.prt_ptr->obj_base.frame_count++;
843 if ( prt_bdl.prt_ptr->frames_remaining > 0 ) prt_bdl.prt_ptr->frames_remaining--;
844
845 if ( !prt_bdl.prt_ptr->inst.indolist )
846 {
847 pinst->valid = bfalse;
848 pinst->ref_valid = bfalse;
849 }
850 else
851 {
852 // calculate the "billboard" for this particle
853 if ( gfx_error == prt_instance_update( pcam, iprt, 255, btrue ) )
854 {
855 retval = gfx_error;
856 }
857 }
858 }
859 PRT_END_LOOP();
860
861 return retval;
862 }
863
864 //--------------------------------------------------------------------------------------------
prt_instance_update_vertices(camera_t * pcam,prt_instance_t * pinst,prt_t * pprt)865 gfx_rv prt_instance_update_vertices( camera_t * pcam, prt_instance_t * pinst, prt_t * pprt )
866 {
867 pip_t * ppip;
868
869 fvec3_t vfwd, vup, vright;
870 fvec3_t vfwd_ref, vup_ref, vright_ref;
871
872 if ( NULL == pinst )
873 {
874 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL particle instance" );
875 return gfx_error;
876 }
877 pinst->valid = bfalse;
878 pinst->ref_valid = bfalse;
879
880 if ( NULL == pcam ) pcam = PCamera;
881 if ( NULL == pcam )
882 {
883 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "cannot find a valid camera" );
884 return gfx_error;
885 }
886
887 if ( !DISPLAY_PPRT( pprt ) )
888 {
889 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, GET_INDEX_PPRT( pprt ), "invalid particle" );
890 return gfx_error;
891 }
892
893 if ( !LOADED_PIP( pprt->pip_ref ) )
894 {
895 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, pprt->pip_ref, "invalid pip" );
896 return gfx_error;
897 }
898 ppip = PipStack.lst + pprt->pip_ref;
899
900 pinst->type = pprt->type;
901
902 pinst->image_ref = FP8_TO_INT( pprt->image + pprt->image_stt );
903
904 // set the position
905 pinst->pos = prt_get_pos( pprt );
906 pinst->orientation = ppip->orientation;
907
908 // calculate the billboard vectors for the reflecions
909 pinst->ref_pos = prt_get_pos( pprt );
910 pinst->ref_pos.z = 2 * pprt->enviro.floor_level - pinst->pos.z;
911
912 // get the vector from the camera to the particle
913 vfwd = fvec3_sub( pinst->pos.v, pcam->pos.v );
914 vfwd = fvec3_normalize( vfwd.v );
915
916 vfwd_ref = fvec3_sub( pinst->ref_pos.v, pcam->pos.v );
917 vfwd_ref = fvec3_normalize( vfwd_ref.v );
918
919 // set the up and right vectors
920 if ( ppip->rotatetoface && !INGAME_CHR( pprt->attachedto_ref ) && ( ABS( pprt->vel.x ) + ABS( pprt->vel.y ) + ABS( pprt->vel.z ) > 0 ) )
921 {
922 // the particle points along its direction of travel
923
924 vup = pprt->vel;
925 vup = fvec3_normalize( vup.v );
926
927 // get the correct "right" vector
928 vright = fvec3_cross_product( vfwd.v, vup.v );
929 vright = fvec3_normalize( vright.v );
930
931 vup_ref = vup;
932 vright_ref = fvec3_cross_product( vfwd_ref.v, vup.v );
933 vright_ref = fvec3_normalize( vright_ref.v );
934 }
935 else if ( ORIENTATION_B == pinst->orientation )
936 {
937 // use the camera up vector
938 vup = pcam->vup;
939 vup = fvec3_normalize( vup.v );
940
941 // get the correct "right" vector
942 vright = fvec3_cross_product( vfwd.v, vup.v );
943 vright = fvec3_normalize( vright.v );
944
945 vup_ref = vup;
946 vright_ref = fvec3_cross_product( vfwd_ref.v, vup.v );
947 vright_ref = fvec3_normalize( vright_ref.v );
948 }
949 else if ( ORIENTATION_V == pinst->orientation )
950 {
951 // Using just the global up vector here is too harsh.
952 // Smoothly interpolate the global up vector with the camera up vector
953 // so that when the camera is looking straight down, the billboard's plane
954 // is turned by 45 degrees to the camera (instead of 90 degrees which is invisible)
955
956 float weight;
957 fvec3_t vup_cam;
958
959 // use the camera up vector
960 vup_cam = pcam->vup;
961
962 // use the global up vector
963 vup.x = vup.y = 0;
964 vup.z = 1;
965
966 // adjust the vector so that the particle doesn't disappear if
967 // you are viewing it from from the top or the bottom
968 weight = 1.0f - ABS( vup_cam.z );
969 if ( vup_cam.z < 0 ) weight *= -1;
970
971 vup.x = vup.x + weight * vup_cam.x;
972 vup.y = vup.y + weight * vup_cam.y;
973 vup.z = vup.z + weight * vup_cam.z;
974 vup = fvec3_normalize( vup.v );
975
976 // get the correct "right" vector
977 vright = fvec3_cross_product( vfwd.v, vup.v );
978 vright = fvec3_normalize( vright.v );
979
980 vright_ref = fvec3_cross_product( vfwd.v, vup_ref.v );
981 vright_ref = fvec3_normalize( vright_ref.v );
982
983 vup_ref = vup;
984 vright_ref = fvec3_cross_product( vfwd_ref.v, vup.v );
985 vright_ref = fvec3_normalize( vright_ref.v );
986 }
987 else if ( ORIENTATION_H == pinst->orientation )
988 {
989 vup.x = vup.y = 0;
990 vup.z = 1;
991
992 // force right to be horizontal
993 vright = fvec3_cross_product( vfwd.v, vup.v );
994
995 // force "up" to be close to the camera forward, but horizontal
996 vup = fvec3_cross_product( vup.v, vright.v );
997 vup_ref = fvec3_cross_product( vup.v, vright_ref.v );
998
999 // normalize them
1000 vright = fvec3_normalize( vright.v );
1001 vup = fvec3_normalize( vup.v );
1002
1003 vright_ref = vright;
1004 vup_ref = vup;
1005 }
1006 else if ( INGAME_CHR( pprt->attachedto_ref ) )
1007 {
1008 chr_instance_t * cinst = chr_get_pinstance( pprt->attachedto_ref );
1009
1010 if ( chr_matrix_valid( ChrList.lst + pprt->attachedto_ref ) )
1011 {
1012 // use the character matrix to orient the particle
1013 // assume that the particle "up" is in the z-direction in the object's
1014 // body fixed axes. should work for the gonnes & such
1015
1016 switch ( pinst->orientation )
1017 {
1018 case ORIENTATION_X: mat_getChrForward( cinst->matrix.v, vup.v ); break;
1019 case ORIENTATION_Y: mat_getChrRight( cinst->matrix.v, vup.v ); break;
1020
1021 default:
1022 case ORIENTATION_Z: mat_getChrUp( cinst->matrix.v, vup.v ); break;
1023 }
1024
1025 fvec3_self_normalize( vup.v );
1026 }
1027 else
1028 {
1029 // use the camera directions?
1030 switch ( pinst->orientation )
1031 {
1032 case ORIENTATION_X: vup = pcam->vfw; break;
1033 case ORIENTATION_Y: vup = pcam->vrt; break;
1034
1035 default:
1036 case ORIENTATION_Z: vup = pcam->vup; break;
1037 }
1038 }
1039
1040 vup = fvec3_normalize( vup.v );
1041
1042 // get the correct "right" vector
1043 vright = fvec3_cross_product( vfwd.v, vup.v );
1044 vright = fvec3_normalize( vright.v );
1045
1046 vup_ref = vup;
1047 vright_ref = fvec3_cross_product( vfwd_ref.v, vup.v );
1048 vright_ref = fvec3_normalize( vright_ref.v );
1049 }
1050 else
1051 {
1052 // use the camera up vector
1053 vup = pcam->vup;
1054 vup = fvec3_normalize( vup.v );
1055
1056 // get the correct "right" vector
1057 vright = fvec3_cross_product( vfwd.v, vup.v );
1058 vright = fvec3_normalize( vright.v );
1059
1060 vup_ref = vup;
1061 vright_ref = fvec3_cross_product( vfwd_ref.v, vup.v );
1062 vright_ref = fvec3_normalize( vright_ref.v );
1063 }
1064
1065 // calculate the actual vectors using the particle rotation
1066 if ( 0 == pprt->rotate )
1067 {
1068 pinst->up = vup;
1069 pinst->right = vright;
1070
1071 pinst->ref_up = vup_ref;
1072 pinst->ref_right = vright_ref;
1073 }
1074 else
1075 {
1076 float sinval, cosval;
1077 TURN_T turn = TO_TURN( pprt->rotate );
1078
1079 cosval = turntocos[ turn ];
1080 sinval = turntosin[ turn ];
1081
1082 pinst->up.x = vup.x * cosval - vright.x * sinval;
1083 pinst->up.y = vup.y * cosval - vright.y * sinval;
1084 pinst->up.z = vup.z * cosval - vright.z * sinval;
1085
1086 pinst->right.x = vup.x * sinval + vright.x * cosval;
1087 pinst->right.y = vup.y * sinval + vright.y * cosval;
1088 pinst->right.z = vup.z * sinval + vright.z * cosval;
1089
1090 pinst->ref_up.x = vup_ref.x * cosval - vright_ref.x * sinval;
1091 pinst->ref_up.y = vup_ref.y * cosval - vright_ref.y * sinval;
1092 pinst->ref_up.z = vup_ref.z * cosval - vright_ref.z * sinval;
1093
1094 pinst->ref_right.x = vup_ref.x * sinval + vright_ref.x * cosval;
1095 pinst->ref_right.y = vup_ref.y * sinval + vright_ref.y * cosval;
1096 pinst->ref_right.z = vup_ref.z * sinval + vright_ref.z * cosval;
1097 }
1098
1099 // calculate the billboard normal
1100 pinst->nrm = fvec3_cross_product( pinst->right.v, pinst->up.v );
1101
1102 // flip the normal so that the front front of the quad is toward the camera
1103 if ( fvec3_dot_product( vfwd.v, pinst->nrm.v ) < 0 )
1104 {
1105 pinst->nrm.x *= -1;
1106 pinst->nrm.y *= -1;
1107 pinst->nrm.z *= -1;
1108 }
1109
1110 // Now we have to calculate the mirror-like reflection of the particles
1111 // this was a bit hard to figure. What happens is that the components of the
1112 // up and right vectors that are in the plane of the quad and closest to the world up are reversed.
1113 //
1114 // This is easy to think about in a couple of examples:
1115 // 1) If the quad is like a picture frame then whatever component (up or right)
1116 // that actually points in the wodld up direction is reversed.
1117 // This corresponds to the case where zdot == +/- 1 in the code below
1118 //
1119 // 2) If the particle is like a rug, then basically nothing happens since
1120 // neither the up or right vectors point in the world up direction.
1121 // This corresponds to 0 == ndot in the code below.
1122 //
1123 // This process does not affect the normal the length of the vector, or the
1124 // direction of the normal to the quad.
1125
1126 {
1127 float zdot; // the dot product between the up or the right vector and the world up
1128 float ndot; // the dot product between either the up or the right vector
1129 float factor;
1130 fvec3_t world_up;
1131
1132 // the normal sense of "up"
1133 world_up.x = world_up.y = 0;
1134 world_up.z = 1.0f;
1135
1136 // the following statement could be optimized
1137 // since we know the only non-zero component of world_up is z
1138 ndot = fvec3_dot_product( pinst->nrm.v, world_up.v );
1139
1140 // do nothing if the quad is basically horizontal
1141 if ( ndot < 1.0f - 1e-6 )
1142 {
1143 //---- do the right vector first
1144 {
1145 // the following statement could be optimized
1146 // since we know the only non-zero component of world_up is z
1147 zdot = fvec3_dot_product( pinst->ref_right.v, world_up.v );
1148
1149 if ( ABS( zdot ) > 1e-6 )
1150 {
1151 factor = zdot / ( 1.0f - ndot * ndot );
1152
1153 pinst->ref_right.x += 2.0f * factor * ( ndot * pinst->nrm.x - world_up.x );
1154 pinst->ref_right.y += 2.0f * factor * ( ndot * pinst->nrm.y - world_up.y );
1155 pinst->ref_right.z += 2.0f * factor * ( ndot * pinst->nrm.z - world_up.z );
1156 }
1157 }
1158
1159 //---- do the up vector second
1160 {
1161 // the following statement could be optimized
1162 // since we know the only non-zero component of world_up is z
1163 zdot = fvec3_dot_product( pinst->ref_up.v, world_up.v );
1164
1165 if ( ABS( zdot ) > 1e-6 )
1166 {
1167 factor = zdot / ( 1.0f - ndot * ndot );
1168
1169 pinst->ref_up.x += 2.0f * factor * ( ndot * pinst->nrm.x - world_up.x );
1170 pinst->ref_up.y += 2.0f * factor * ( ndot * pinst->nrm.y - world_up.y );
1171 pinst->ref_up.z += 2.0f * factor * ( ndot * pinst->nrm.z - world_up.z );
1172 }
1173 }
1174 }
1175 }
1176
1177 // set some particle dependent properties
1178 pinst->scale = prt_get_scale( pprt );
1179 pinst->size = FP8_TO_FLOAT( pprt->size ) * pinst->scale;
1180
1181 // this instance is now completely valid
1182 pinst->valid = btrue;
1183 pinst->ref_valid = btrue;
1184
1185 return gfx_success;
1186 }
1187
1188 //--------------------------------------------------------------------------------------------
prt_instance_make_matrix(prt_instance_t * pinst)1189 fmat_4x4_t prt_instance_make_matrix( prt_instance_t * pinst )
1190 {
1191 fmat_4x4_t mat = IdentityMatrix();
1192
1193 mat.CNV( 0, 1 ) = -pinst->up.x;
1194 mat.CNV( 1, 1 ) = -pinst->up.y;
1195 mat.CNV( 2, 1 ) = -pinst->up.z;
1196
1197 mat.CNV( 0, 0 ) = pinst->right.x;
1198 mat.CNV( 1, 0 ) = pinst->right.y;
1199 mat.CNV( 2, 0 ) = pinst->right.z;
1200
1201 mat.CNV( 0, 2 ) = pinst->nrm.x;
1202 mat.CNV( 1, 2 ) = pinst->nrm.y;
1203 mat.CNV( 2, 2 ) = pinst->nrm.z;
1204
1205 return mat;
1206 }
1207
1208 //--------------------------------------------------------------------------------------------
prt_instance_update_lighting(prt_instance_t * pinst,prt_t * pprt,Uint8 trans,bool_t do_lighting)1209 gfx_rv prt_instance_update_lighting( prt_instance_t * pinst, prt_t * pprt, Uint8 trans, bool_t do_lighting )
1210 {
1211 Uint32 alpha;
1212 Sint16 self_light;
1213 lighting_cache_t global_light, loc_light;
1214 float amb, dir;
1215 fmat_4x4_t mat;
1216
1217 if ( NULL == pinst )
1218 {
1219 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL instance" );
1220 return gfx_error;
1221 }
1222 if ( NULL == pprt )
1223 {
1224 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, 0, "NULL particle" );
1225 return gfx_error;
1226 }
1227
1228 // To make life easier
1229 alpha = trans;
1230
1231 // interpolate the lighting for the origin of the object
1232 grid_lighting_interpolate( PMesh, &global_light, pinst->pos.x, pinst->pos.y );
1233
1234 // rotate the lighting data to body_centered coordinates
1235 mat = prt_instance_make_matrix( pinst );
1236 lighting_project_cache( &loc_light, &global_light, mat );
1237
1238 // determine the normal dependent amount of light
1239 lighting_evaluate_cache( &loc_light, pinst->nrm.v, pinst->pos.z, PMesh->tmem.bbox, &amb, &dir );
1240
1241 // LIGHT-blended sprites automatically glow. ALPHA-blended and SOLID
1242 // sprites need to convert the light channel into additional alpha
1243 // lighting to make them "glow"
1244 self_light = 0;
1245 if ( SPRITE_LIGHT != pinst->type )
1246 {
1247 self_light = ( 255 == pinst->light ) ? 0 : pinst->light;
1248 }
1249
1250 // determine the ambient lighting
1251 pinst->famb = 0.9f * pinst->famb + 0.1f * ( self_light + amb );
1252 pinst->fdir = 0.9f * pinst->fdir + 0.1f * dir;
1253
1254 // determine the overall lighting
1255 pinst->fintens = pinst->fdir * INV_FF;
1256 if ( do_lighting )
1257 {
1258 pinst->fintens += pinst->famb * INV_FF;
1259 }
1260 pinst->fintens = CLIP( pinst->fintens, 0.0f, 1.0f );
1261
1262 // determine the alpha component
1263 pinst->falpha = ( alpha * INV_FF ) * ( pinst->alpha * INV_FF );
1264 pinst->falpha = CLIP( pinst->falpha, 0.0f, 1.0f );
1265
1266 return gfx_success;
1267 }
1268
1269 //--------------------------------------------------------------------------------------------
prt_instance_update(camera_t * pcam,const PRT_REF particle,Uint8 trans,bool_t do_lighting)1270 gfx_rv prt_instance_update( camera_t * pcam, const PRT_REF particle, Uint8 trans, bool_t do_lighting )
1271 {
1272 prt_t * pprt;
1273 prt_instance_t * pinst;
1274 gfx_rv retval;
1275
1276 if ( !DISPLAY_PRT( particle ) )
1277 {
1278 gfx_error_add( __FILE__, __FUNCTION__, __LINE__, particle, "invalid particle" );
1279 return gfx_error;
1280 }
1281 pprt = PrtList.lst + particle;
1282 pinst = &( pprt->inst );
1283
1284 // assume the best
1285 retval = gfx_success;
1286
1287 // make sure that the vertices are interpolated
1288 if ( gfx_error == prt_instance_update_vertices( pcam, pinst, pprt ) )
1289 {
1290 retval = gfx_error;
1291 }
1292
1293 // do the lighting
1294 if ( gfx_error == prt_instance_update_lighting( pinst, pprt, trans, do_lighting ) )
1295 {
1296 retval = gfx_error;
1297 }
1298
1299 return retval;
1300 }
1301
1302 //--------------------------------------------------------------------------------------------
render_prt_bbox(prt_bundle_t * pbdl_prt)1303 void render_prt_bbox( prt_bundle_t * pbdl_prt )
1304 {
1305 prt_t * loc_pprt;
1306 pip_t * loc_ppip;
1307
1308 if ( NULL == pbdl_prt || NULL == pbdl_prt->prt_ptr ) return;
1309 loc_pprt = pbdl_prt->prt_ptr;
1310 loc_ppip = pbdl_prt->pip_ptr;
1311
1312 // only draw bullets
1313 //if ( 50 != loc_ppip->vel_hrz_pair.base ) return;
1314
1315 if ( !DISPLAY_PPRT( loc_pprt ) ) return;
1316
1317 // draw the object bounding box as a part of the graphics debug mode F7
1318 if (( cfg.dev_mode && SDLKEYDOWN( SDLK_F7 ) ) || single_frame_mode )
1319 {
1320 oct_bb_t loc_bb, tmp_bb, exp_bb;
1321
1322 // copy the bounding volume
1323 oct_bb_copy( &tmp_bb, &( loc_pprt->prt_max_cv ) );
1324
1325 // make sure that it has some minimum extent
1326 //for(cnt = 0; cnt < OCT_COUNT; cnt++ )
1327 //{
1328 // tmp_bb.mins[cnt] = MIN( tmp_bb.mins[cnt], -1 );
1329 // tmp_bb.maxs[cnt] = MAX( tmp_bb.mins[cnt], 1 );
1330 //}
1331
1332 // determine the expanded collision volumes for both objects
1333 phys_expand_oct_bb( &tmp_bb, loc_pprt->vel.v, 0, 1, &exp_bb );
1334
1335 // shift the source bounding boxes to be centered on the given positions
1336 oct_bb_add_fvec3( &exp_bb, loc_pprt->pos.v, &loc_bb );
1337
1338 GL_DEBUG( glDisable )( GL_TEXTURE_2D );
1339 {
1340 GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
1341 render_oct_bb( &loc_bb, btrue, btrue );
1342 }
1343 GL_DEBUG( glEnable )( GL_TEXTURE_2D );
1344 }
1345 }