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