2 * $Logfile: /Freespace2/code/Weapon/Trails.cpp $
7 * Code for missile trails
10 * Revision 1.1 2002/05/03 03:28:11 root
14 * 7 6/23/99 2:23p Mattk
15 * Fixed detail level trail rendering problem.
17 * 6 6/22/99 7:03p Dave
18 * New detail options screen.
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.
24 * 4 2/17/99 2:11p Dave
25 * First full run of squad war. All freespace and tracker side stuff
28 * 3 11/14/98 5:33p Dave
29 * Lots of nebula work. Put in ship contrails.
31 * 2 10/07/98 10:54a Dave
34 * 1 10/07/98 10:51a Dave
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
41 * 8 5/08/98 7:09p Dave
42 * Lots of UI tweaking.
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.
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.
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.
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.
65 * 3 1/15/98 11:13a John
66 * Added code for specifying weapon trail bitmaps in weapons.tbl
68 * 2 12/21/97 6:15p John
69 * Made a seperate system for missile trails
71 * 1 12/21/97 5:30p John
78 #include "freespace.h"
82 #include "3dinternal.h"
87 #define MAX_TRAILS MAX_WEAPONS
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
98 trail_info info; // this is passed when creating a trail
106 trail Trails[MAX_TRAILS];
108 trail Trail_free_list;
109 trail Trail_used_list;
111 // Reset everything between levels
112 void trail_level_init()
117 list_init( &Trail_free_list );
118 list_init( &Trail_used_list );
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] );
126 //returns the number of a free trail
127 //returns -1 if no free trails
128 int trail_create(trail_info info)
133 // standalone server should never create trails
134 if(Game_mode & GM_STANDALONE_SERVER){
138 if ( !Detail.weapon_extras ) {
139 // No trails at slot 0
143 if (Num_trails >= MAX_TRAILS ) {
145 mprintf(("Trail creation failed - too many trails!\n" ));
150 // Find next available trail
151 trailp = GET_FIRST(&Trail_free_list);
152 Assert( trailp != &Trail_free_list ); // shouldn't have the dummy element
154 // remove trailp from the free list
155 list_remove( &Trail_free_list, trailp );
157 // insert trailp onto the end of used list
158 list_append( &Trail_used_list, trailp );
164 trail_num = trailp-Trails;
166 // Init the trail data
170 trailp->object_died = 0;
171 trailp->trail_stamp = timestamp(trailp->info.stamp);
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 )
184 vm_vec_sub( &rvec, &Eye_position, pos );
185 vm_vec_normalize( &rvec );
187 vm_vec_crossprod(&uvec,fvec,&rvec);
188 vm_vec_normalize(&uvec);
190 vm_vec_scale_add( top, pos, &uvec, w/2.0f );
191 vm_vec_scale_add( bot, pos, &uvec, -w/2.0f );
195 int trail_is_on_ship(int trail_index, ship *shipp)
199 for(idx=0; idx<MAX_SHIP_CONTRAILS; idx++){
200 if(shipp->trail_num[idx] == (short)trail_index){
209 // Render the trail behind a missile.
210 // Basically a queue of points that face the viewer.
211 void trail_render( trail * trailp )
215 if ( trailp->tail == trailp->head ) return;
219 vector topv, botv, *fvec, last_pos, tmp_fvec;
220 vertex last_top, last_bot, top, bot;
222 int sections[NUM_TRAIL_SECTIONS];
223 int num_sections = 0;
225 int n = trailp->tail;
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)) ){
234 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
237 if ( trailp->val[n] > 1.0f ) {
241 sections[num_sections++] = n;
243 } while ( n != trailp->head );
247 for (i=0; i<num_sections; i++ ) {
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);
259 pos = trailp->pos[n];
263 //&objp->orient.fvec;
264 if ( num_sections > 1 ) {
266 vm_vec_sub(&tmp_fvec, &pos, &trailp->pos[sections[i+1]] );
267 vm_vec_normalize_safe(&tmp_fvec);
277 vm_vec_sub(&tmp_fvec, &last_pos, &pos );
278 vm_vec_normalize_safe(&tmp_fvec);
282 trail_calc_facing_pts( &topv, &botv, fvec, &pos, w );
284 g3_rotate_vertex( &top, &topv );
285 g3_rotate_vertex( &bot, &botv );
290 if ( i == num_sections-1 ) {
293 vm_vec_avg( ¢erv, &topv, &botv );
295 g3_rotate_vertex( ¢er, ¢erv );
299 vlist[0] = &last_top;
300 vlist[1] = &last_bot;
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;
307 gr_set_bitmap(ti->bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, l/255.0f );
309 g3_draw_poly( 3, vlist, TMAP_FLAG_TEXTURED|TMAP_FLAG_ALPHA|TMAP_FLAG_GOURAUD );
311 g3_draw_poly( 3, vlist, TMAP_FLAG_TEXTURED );
317 vlist[0] = &last_bot;
320 vlist[3] = &last_top;
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;
327 gr_set_bitmap(ti->bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, l/255.0f );
329 g3_draw_poly( 4, vlist, TMAP_FLAG_TEXTURED|TMAP_FLAG_ALPHA|TMAP_FLAG_GOURAUD );
331 g3_draw_poly( 4, vlist, TMAP_FLAG_TEXTURED );
342 void trail_add_segment( int trail_num, vector *pos )
344 if (trail_num < 0 ) return;
345 if (trail_num >= MAX_TRAILS ) return;
347 trail *trailp = &Trails[trail_num];
349 int next = trailp->tail;
351 if ( trailp->tail >= NUM_TRAIL_SECTIONS )
354 if ( trailp->head == trailp->tail ) {
357 if ( trailp->head >= NUM_TRAIL_SECTIONS )
361 trailp->pos[next] = *pos;
362 trailp->val[next] = 0.0f;
365 void trail_set_segment( int trail_num, vector *pos )
367 if (trail_num < 0 ) return;
368 if (trail_num >= MAX_TRAILS ) return;
370 trail *trailp = &Trails[trail_num];
372 int next = trailp->tail-1;
374 next = NUM_TRAIL_SECTIONS-1;
377 trailp->pos[next] = *pos;
380 void trail_move_all(float frametime)
384 trailp=GET_FIRST(&Trail_used_list);
386 while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
388 int num_alive_segments = 0;
390 if ( trailp->tail != trailp->head ) {
391 int n = trailp->tail;
392 float time_delta = frametime / trailp->info.max_life;
395 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
397 trailp->val[n] += time_delta;
399 if ( trailp->val[n] <= 1.0f ) {
400 num_alive_segments++; // Record how many still alive.
403 } while ( n != trailp->head );
406 if ( trailp->object_died && (num_alive_segments < 1) ) {
407 // delete it from the list!
408 trail *next_one = GET_NEXT(trailp);
410 // remove objp from the used list
411 list_remove( &Trail_used_list, trailp);
413 // add objp to the end of the free
414 list_append( &Trail_free_list, trailp );
419 Assert(Num_trails >= 0);
423 trailp=GET_NEXT(trailp);
428 void trail_object_died( int trail_num )
430 if (trail_num < 0 ) return;
431 if (trail_num >= MAX_TRAILS ) return;
433 trail *trailp = &Trails[trail_num];
435 trailp->object_died++;
438 void trail_render_all()
442 if ( !Detail.weapon_extras ) {
443 // No trails at slot 0
447 trailp=GET_FIRST(&Trail_used_list);
449 while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
450 trail_render(trailp);
451 trailp=GET_NEXT(trailp);
455 int trail_stamp_elapsed(int trail_num)
457 return timestamp_elapsed(Trails[trail_num].trail_stamp);
460 void trail_set_stamp(int trail_num)
462 Trails[trail_num].trail_stamp = timestamp(Trails[trail_num].info.stamp);