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