2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Weapon/Trails.cpp $
15 * Code for missile trails
18 * Revision 1.5 2004/09/20 01:31:45 theoddone33
21 * Revision 1.4 2002/06/17 06:33:11 relnev
22 * ryan's struct patch for gcc 2.95
24 * Revision 1.3 2002/06/09 04:41:29 relnev
25 * added copyright header
27 * Revision 1.2 2002/05/07 03:16:53 theoddone33
28 * The Great Newline Fix
30 * Revision 1.1.1.1 2002/05/03 03:28:11 root
34 * 7 6/23/99 2:23p Mattk
35 * Fixed detail level trail rendering problem.
37 * 6 6/22/99 7:03p Dave
38 * New detail options screen.
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.
44 * 4 2/17/99 2:11p Dave
45 * First full run of squad war. All freespace and tracker side stuff
48 * 3 11/14/98 5:33p Dave
49 * Lots of nebula work. Put in ship contrails.
51 * 2 10/07/98 10:54a Dave
54 * 1 10/07/98 10:51a Dave
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
61 * 8 5/08/98 7:09p Dave
62 * Lots of UI tweaking.
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.
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.
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.
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.
85 * 3 1/15/98 11:13a John
86 * Added code for specifying weapon trail bitmaps in weapons.tbl
88 * 2 12/21/97 6:15p John
89 * Made a seperate system for missile trails
91 * 1 12/21/97 5:30p John
98 #include "freespace.h"
100 #include "linklist.h"
102 #include "3dinternal.h"
107 #define MAX_TRAILS MAX_WEAPONS
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
118 trail_info info; // this is passed when creating a trail
126 trail Trails[MAX_TRAILS];
128 trail Trail_free_list;
129 trail Trail_used_list;
131 // Reset everything between levels
132 void trail_level_init()
137 list_init( &Trail_free_list );
138 list_init( &Trail_used_list );
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] );
146 //returns the number of a free trail
147 //returns -1 if no free trails
148 int trail_create(trail_info info)
153 // standalone server should never create trails
154 if(Game_mode & GM_STANDALONE_SERVER){
159 if ( !Detail.weapon_extras ) {
161 if ( !Detail.weapon_detail ) {
163 // No trails at slot 0
167 if (Num_trails >= MAX_TRAILS ) {
169 mprintf(("Trail creation failed - too many trails!\n" ));
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
178 // remove trailp from the free list
179 list_remove( &Trail_free_list, trailp );
181 // insert trailp onto the end of used list
182 list_append( &Trail_used_list, trailp );
188 trail_num = trailp-Trails;
190 // Init the trail data
194 trailp->object_died = 0;
195 trailp->trail_stamp = timestamp(trailp->info.stamp);
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 )
208 vm_vec_sub( &rvec, &Eye_position, pos );
209 vm_vec_normalize( &rvec );
211 vm_vec_crossprod(&uvec,fvec,&rvec);
212 vm_vec_normalize(&uvec);
214 vm_vec_scale_add( top, pos, &uvec, w/2.0f );
215 vm_vec_scale_add( bot, pos, &uvec, -w/2.0f );
219 int trail_is_on_ship(int trail_index, ship *shipp)
223 for(idx=0; idx<MAX_SHIP_CONTRAILS; idx++){
224 if(shipp->trail_num[idx] == (short)trail_index){
233 // Render the trail behind a missile.
234 // Basically a queue of points that face the viewer.
235 void trail_render( trail * trailp )
239 if ( trailp->tail == trailp->head ) return;
243 vector topv, botv, *fvec, last_pos, tmp_fvec;
244 vertex last_top, last_bot, top, bot;
246 int sections[NUM_TRAIL_SECTIONS];
247 int num_sections = 0;
249 int n = trailp->tail;
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)) ){
258 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
261 if ( trailp->val[n] > 1.0f ) {
265 sections[num_sections++] = n;
267 } while ( n != trailp->head );
271 for (i=0; i<num_sections; i++ ) {
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);
283 pos = trailp->pos[n];
287 //&objp->orient.fvec;
288 if ( num_sections > 1 ) {
290 vm_vec_sub(&tmp_fvec, &pos, &trailp->pos[sections[i+1]] );
291 vm_vec_normalize_safe(&tmp_fvec);
301 vm_vec_sub(&tmp_fvec, &last_pos, &pos );
302 vm_vec_normalize_safe(&tmp_fvec);
306 trail_calc_facing_pts( &topv, &botv, fvec, &pos, w );
308 g3_rotate_vertex( &top, &topv );
309 g3_rotate_vertex( &bot, &botv );
314 if ( i == num_sections-1 ) {
317 vm_vec_avg( ¢erv, &topv, &botv );
319 g3_rotate_vertex( ¢er, ¢erv );
323 vlist[0] = &last_top;
324 vlist[1] = &last_bot;
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;
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 );
336 vlist[0] = &last_bot;
339 vlist[3] = &last_top;
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;
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 );
357 void trail_add_segment( int trail_num, vector *pos )
359 if (trail_num < 0 ) return;
360 if (trail_num >= MAX_TRAILS ) return;
362 trail *trailp = &Trails[trail_num];
364 int next = trailp->tail;
366 if ( trailp->tail >= NUM_TRAIL_SECTIONS )
369 if ( trailp->head == trailp->tail ) {
372 if ( trailp->head >= NUM_TRAIL_SECTIONS )
376 trailp->pos[next] = *pos;
377 trailp->val[next] = 0.0f;
380 void trail_set_segment( int trail_num, vector *pos )
382 if (trail_num < 0 ) return;
383 if (trail_num >= MAX_TRAILS ) return;
385 trail *trailp = &Trails[trail_num];
387 int next = trailp->tail-1;
389 next = NUM_TRAIL_SECTIONS-1;
392 trailp->pos[next] = *pos;
395 void trail_move_all(float frametime)
399 trailp=GET_FIRST(&Trail_used_list);
401 while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
403 int num_alive_segments = 0;
405 if ( trailp->tail != trailp->head ) {
406 int n = trailp->tail;
407 float time_delta = frametime / trailp->info.max_life;
410 if ( n < 0 ) n = NUM_TRAIL_SECTIONS-1;
412 trailp->val[n] += time_delta;
414 if ( trailp->val[n] <= 1.0f ) {
415 num_alive_segments++; // Record how many still alive.
418 } while ( n != trailp->head );
421 if ( trailp->object_died && (num_alive_segments < 1) ) {
422 // delete it from the list!
423 trail *next_one = GET_NEXT(trailp);
425 // remove objp from the used list
426 list_remove( &Trail_used_list, trailp);
428 // add objp to the end of the free
429 list_append( &Trail_free_list, trailp );
434 SDL_assert(Num_trails >= 0);
438 trailp=GET_NEXT(trailp);
443 void trail_object_died( int trail_num )
445 if (trail_num < 0 ) return;
446 if (trail_num >= MAX_TRAILS ) return;
448 trail *trailp = &Trails[trail_num];
450 trailp->object_died++;
453 void trail_render_all()
458 if ( !Detail.weapon_extras ) {
460 if ( !Detail.weapon_detail ) {
462 // No trails at slot 0
466 trailp=GET_FIRST(&Trail_used_list);
468 while ( trailp!=END_OF_LIST(&Trail_used_list) ) {
469 trail_render(trailp);
470 trailp=GET_NEXT(trailp);
474 int trail_stamp_elapsed(int trail_num)
476 return timestamp_elapsed(Trails[trail_num].trail_stamp);
479 void trail_set_stamp(int trail_num)
481 Trails[trail_num].trail_stamp = timestamp(Trails[trail_num].info.stamp);