]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/trails.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / weapon / trails.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Weapon/Trails.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code for missile trails
16  *
17  * $Log$
18  * Revision 1.5  2004/09/20 01:31:45  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.4  2002/06/17 06:33:11  relnev
22  * ryan's struct patch for gcc 2.95
23  *
24  * Revision 1.3  2002/06/09 04:41:29  relnev
25  * added copyright header
26  *
27  * Revision 1.2  2002/05/07 03:16:53  theoddone33
28  * The Great Newline Fix
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:11  root
31  * Initial import.
32  *
33  * 
34  * 7     6/23/99 2:23p Mattk
35  * Fixed detail level trail rendering problem.
36  * 
37  * 6     6/22/99 7:03p Dave
38  * New detail options screen.
39  * 
40  * 5     2/23/99 8:11p Dave
41  * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
42  * Small pass over todolist items.
43  * 
44  * 4     2/17/99 2:11p Dave
45  * First full run of squad war. All freespace and tracker side stuff
46  * works.
47  * 
48  * 3     11/14/98 5:33p Dave
49  * Lots of nebula work. Put in ship contrails.
50  * 
51  * 2     10/07/98 10:54a Dave
52  * Initial checkin.
53  * 
54  * 1     10/07/98 10:51a Dave
55  * 
56  * 9     5/13/98 3:10p John
57  * made detail slider for weapon rendering change the distance that lasers
58  * become non-textured.  The lowest setting turns off missile trail
59  * rendering.
60  * 
61  * 8     5/08/98 7:09p Dave
62  * Lots of UI tweaking.
63  * 
64  * 7     4/10/98 5:20p John
65  * Changed RGB in lighting structure to be ubytes.  Removed old
66  * not-necessary 24 bpp software stuff.
67  * 
68  * 6     3/31/98 5:19p John
69  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
70  * bunch of debug stuff out of player file.  Made model code be able to
71  * unload models and malloc out only however many models are needed.
72  *  
73  * 
74  * 5     3/23/98 5:00p John
75  * Improved missile trails.  Made smooth alpha under hardware.  Made end
76  * taper.  Made trail touch weapon.
77  * 
78  * 4     1/23/98 5:08p John
79  * Took L out of vertex structure used B (blue) instead.   Took all small
80  * fireballs out of fireball types and used particles instead.  Fixed some
81  * debris explosion things.  Restructured fireball code.   Restructured
82  * some lighting code.   Made dynamic lighting on by default. Made groups
83  * of lasers only cast one light.  Made fireballs not cast light.
84  * 
85  * 3     1/15/98 11:13a John
86  * Added code for specifying weapon trail bitmaps in weapons.tbl
87  * 
88  * 2     12/21/97 6:15p John
89  * Made a seperate system for missile trails
90  * 
91  * 1     12/21/97 5:30p John
92  * Initial version
93  *
94  * $NoKeywords: $
95  */
96
97 #include "pstypes.h"
98 #include "freespace.h"
99 #include "weapon.h"
100 #include "linklist.h"
101 #include "3d.h" 
102 #include "3dinternal.h" 
103 #include "bmpman.h"
104 #include "trails.h"
105 #include "timer.h"
106
107 #define MAX_TRAILS MAX_WEAPONS
108
109 // Stuff for missile trails doesn't need to be saved or restored... or does it?
110 typedef struct trail {
111         int             head, tail;                                             // pointers into the queue for the trail points
112         vector  pos[NUM_TRAIL_SECTIONS];        // positions of trail points
113         float           val[NUM_TRAIL_SECTIONS];        // for each point, a value that tells how much to fade out      
114         int             object_died;                                    // set to zero as long as object        
115         int             trail_stamp;                                    // trail timestamp      
116
117         // trail info
118         trail_info info;                                                        // this is passed when creating a trail
119
120         struct  trail * prev;
121         struct  trail * next;
122 } trail;
123
124
125 int Num_trails = 0;
126 trail Trails[MAX_TRAILS];
127
128 trail Trail_free_list;
129 trail Trail_used_list;
130
131 // Reset everything between levels
132 void trail_level_init()
133 {
134         int i;
135
136         Num_trails = 0;
137         list_init( &Trail_free_list );
138         list_init( &Trail_used_list );
139
140         // Link all object slots into the free list
141         for (i=0; i<MAX_TRAILS; i++)    {
142                 list_append(&Trail_free_list, &Trails[i] );
143         }
144 }
145
146 //returns the number of a free trail
147 //returns -1 if no free trails
148 int trail_create(trail_info info)
149 {
150         int trail_num;
151         trail *trailp;
152
153         // standalone server should never create trails
154         if(Game_mode & GM_STANDALONE_SERVER){
155                 return -1;
156         }
157
158 #ifndef MAKE_FS1
159         if ( !Detail.weapon_extras )    {
160 #else
161         if ( !Detail.weapon_detail ) {
162 #endif
163                 // No trails at slot 0
164                 return -1;
165         }
166
167         if (Num_trails >= MAX_TRAILS ) {
168                 #ifndef NDEBUG
169                 mprintf(("Trail creation failed - too many trails!\n" ));
170                 #endif
171                 return -1;
172         }
173
174         // Find next available trail
175         trailp = GET_FIRST(&Trail_free_list);
176         SDL_assert( trailp != &Trail_free_list );               // shouldn't have the dummy element
177
178         // remove trailp from the free list
179         list_remove( &Trail_free_list, trailp );
180         
181         // insert trailp onto the end of used list
182         list_append( &Trail_used_list, trailp );
183
184         // increment counter
185         Num_trails++;
186
187         // get objnum
188         trail_num = trailp-Trails;
189
190         // Init the trail data
191         trailp->info = info;
192         trailp->tail = 0;
193         trailp->head = 0;       
194         trailp->object_died = 0;                
195         trailp->trail_stamp = timestamp(trailp->info.stamp);
196
197         return trail_num;
198 }
199
200 // output top and bottom vectors
201 // fvec == forward vector (eye viewpoint basically. in world coords)
202 // pos == world coordinate of the point we're calculating "around"
203 // w == width of the diff between top and bottom around pos
204 void trail_calc_facing_pts( vector *top, vector *bot, vector *fvec, vector *pos, float w )
205 {
206         vector uvec, rvec;
207
208         vm_vec_sub( &rvec, &Eye_position, pos );
209         vm_vec_normalize( &rvec );
210
211         vm_vec_crossprod(&uvec,fvec,&rvec);
212         vm_vec_normalize(&uvec);
213
214         vm_vec_scale_add( top, pos, &uvec, w/2.0f );
215         vm_vec_scale_add( bot, pos, &uvec, -w/2.0f );
216 }
217
218 // trail is on ship
219 int trail_is_on_ship(int trail_index, ship *shipp)
220 {
221         int idx;
222
223         for(idx=0; idx<MAX_SHIP_CONTRAILS; idx++){
224                 if(shipp->trail_num[idx] == (short)trail_index){
225                         return 1;
226                 }
227         }
228
229         // nope
230         return 0;
231 }
232
233 // Render the trail behind a missile.
234 // Basically a queue of points that face the viewer.
235 void trail_render( trail * trailp )
236 {               
237         trail_info *ti; 
238
239         if ( trailp->tail == trailp->head ) return;
240
241         ti = &trailp->info;     
242
243         vector topv, botv, *fvec, last_pos, tmp_fvec;
244         vertex last_top, last_bot, top, bot;
245
246         int sections[NUM_TRAIL_SECTIONS];
247         int num_sections = 0;
248
249         int n = trailp->tail;
250
251         // if this trail is on the player ship, and he's in any padlock view except rear view, don't draw       
252         if((Player_ship != NULL) && trail_is_on_ship(trailp - Trails, Player_ship) && (Viewer_mode & (VM_PADLOCK_UP | VM_PADLOCK_LEFT | VM_PADLOCK_RIGHT)) ){
253                 return;
254         }
255
256         do      {
257                 n--;
258                 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
259
260
261                 if ( trailp->val[n] > 1.0f ) {
262                         break;
263                 }
264
265                 sections[num_sections++] = n;
266
267         } while ( n != trailp->head );
268
269         int i;
270
271         for (i=0; i<num_sections; i++ ) {
272
273                 n = sections[i];
274
275                 float w;
276                 ubyte l;
277
278                 w = trailp->val[n]*(ti->w_end - ti->w_start) + ti->w_start;
279                 l = (ubyte)fl2i((trailp->val[n]*(ti->a_end - ti->a_start) + ti->a_start)*255.0f);
280
281                 vector pos;
282
283                 pos = trailp->pos[n];
284
285                 if ( i == 0 )   {
286                         //fvec = 
287                         //&objp->orient.fvec;
288                         if ( num_sections > 1 ) {
289         
290                                 vm_vec_sub(&tmp_fvec, &pos, &trailp->pos[sections[i+1]] );
291                                 vm_vec_normalize_safe(&tmp_fvec);
292                                 fvec = &tmp_fvec;
293
294                         } else {
295                                 fvec = &tmp_fvec;
296                                 fvec->xyz.x = 0.0f;
297                                 fvec->xyz.y = 0.0f;
298                                 fvec->xyz.z = 1.0f;
299                         }
300                 } else {
301                         vm_vec_sub(&tmp_fvec, &last_pos, &pos );
302                         vm_vec_normalize_safe(&tmp_fvec);
303                         fvec = &tmp_fvec;
304                 }
305                         
306                 trail_calc_facing_pts( &topv, &botv, fvec, &pos, w );
307
308                 g3_rotate_vertex( &top, &topv );
309                 g3_rotate_vertex( &bot, &botv );
310                 top.a = bot.a = l;      
311
312                 if ( i > 0 )    {
313
314                         if ( i == num_sections-1 )      {
315                                 // Last one...
316                                 vector centerv;
317                                 vm_vec_avg( &centerv, &topv, &botv );
318                                 vertex center;
319                                 g3_rotate_vertex( &center, &centerv );
320                                 center.a = l;   
321
322                                 vertex *vlist[3];
323                                 vlist[0] = &last_top;
324                                 vlist[1] = &last_bot;
325                                 vlist[2] = &center;
326
327                                 vlist[0]->u = 0.0f;  vlist[0]->v = 1.0f;
328                                 vlist[1]->u = 0.0f;  vlist[1]->v = 0.0f;
329                                 vlist[2]->u = 1.0f;  vlist[2]->v = 0.5f;
330
331                                 gr_set_bitmap(ti->bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, l/255.0f, -1, -1);
332                                 g3_draw_poly( 3, vlist, TMAP_FLAG_TEXTURED|TMAP_FLAG_ALPHA|TMAP_FLAG_GOURAUD );
333
334                         } else {
335                                 vertex *vlist[4];
336                                 vlist[0] = &last_bot;
337                                 vlist[1] = &bot;
338                                 vlist[2] = &top;
339                                 vlist[3] = &last_top;
340
341                                 vlist[0]->u = 0.0f;  vlist[0]->v = 0.0f;
342                                 vlist[1]->u = 1.0f;  vlist[1]->v = 0.0f;
343                                 vlist[2]->u = 1.0f;  vlist[2]->v = 1.0f;
344                                 vlist[3]->u = 0.0f;  vlist[3]->v = 1.0f;
345
346                                 gr_set_bitmap(ti->bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, l/255.0f, -1, -1);
347                                 g3_draw_poly( 4, vlist, TMAP_FLAG_TEXTURED|TMAP_FLAG_ALPHA|TMAP_FLAG_GOURAUD );
348                         }
349                 }
350                 last_pos = pos;
351                 last_top = top;
352                 last_bot = bot;
353         }
354 }
355
356
357 void trail_add_segment( int trail_num, vector *pos )
358 {
359         if (trail_num < 0 ) return;
360         if (trail_num >= MAX_TRAILS ) return;
361
362         trail *trailp = &Trails[trail_num];
363
364         int next = trailp->tail;
365         trailp->tail++;
366         if ( trailp->tail >= NUM_TRAIL_SECTIONS )
367                 trailp->tail = 0;
368
369         if ( trailp->head == trailp->tail )     {
370                 // wrapped!!
371                 trailp->head++;
372                 if ( trailp->head >= NUM_TRAIL_SECTIONS )
373                         trailp->head = 0;
374         }
375         
376         trailp->pos[next] = *pos;
377         trailp->val[next] = 0.0f;
378 }               
379
380 void trail_set_segment( int trail_num, vector *pos )
381 {
382         if (trail_num < 0 ) return;
383         if (trail_num >= MAX_TRAILS ) return;
384
385         trail *trailp = &Trails[trail_num];
386
387         int next = trailp->tail-1;
388         if ( next < 0 ) {
389                 next = NUM_TRAIL_SECTIONS-1;
390         }
391         
392         trailp->pos[next] = *pos;
393 }
394
395 void trail_move_all(float frametime)
396 {
397         trail *trailp;  
398
399         trailp=GET_FIRST(&Trail_used_list);
400
401         while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
402
403                 int num_alive_segments = 0;
404
405                 if ( trailp->tail != trailp->head )     {
406                         int n = trailp->tail;                   
407                         float time_delta = frametime / trailp->info.max_life;
408                         do      {
409                                 n--;
410                                 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
411
412                                 trailp->val[n] += time_delta;
413
414                                 if ( trailp->val[n] <= 1.0f ) {
415                                         num_alive_segments++;   // Record how many still alive.
416                                 }
417
418                         } while ( n != trailp->head );
419                 }               
420         
421                 if ( trailp->object_died && (num_alive_segments < 1) )  {
422                         // delete it from the list!
423                         trail *next_one = GET_NEXT(trailp);
424
425                         // remove objp from the used list
426                         list_remove( &Trail_used_list, trailp);
427
428                         // add objp to the end of the free
429                         list_append( &Trail_free_list, trailp );
430
431                         // decrement counter
432                         Num_trails--;
433
434                         SDL_assert(Num_trails >= 0);
435                         
436                         trailp = next_one;
437                 } else {
438                         trailp=GET_NEXT(trailp);
439                 }
440         }
441 }
442
443 void trail_object_died( int trail_num )
444 {
445         if (trail_num < 0 ) return;
446         if (trail_num >= MAX_TRAILS ) return;
447
448         trail *trailp = &Trails[trail_num];
449         
450         trailp->object_died++;
451 }
452
453 void trail_render_all()
454 {
455         trail *trailp;
456
457 #ifndef MAKE_FS1
458         if ( !Detail.weapon_extras )    {
459 #else
460         if ( !Detail.weapon_detail ) {
461 #endif
462                 // No trails at slot 0
463                 return;
464         }
465
466         trailp=GET_FIRST(&Trail_used_list);
467
468         while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
469                 trail_render(trailp);
470                 trailp=GET_NEXT(trailp);
471         }
472
473 }
474 int trail_stamp_elapsed(int trail_num)
475 {
476         return timestamp_elapsed(Trails[trail_num].trail_stamp);
477 }
478
479 void trail_set_stamp(int trail_num)
480 {
481         Trails[trail_num].trail_stamp = timestamp(Trails[trail_num].info.stamp);
482 }