]> icculus.org git repositories - taylor/freespace2.git/blob - src/render/3dlaser.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / render / 3dlaser.cpp
1 /*
2  * $Logfile: /Freespace2/code/Render/3dLaser.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to draw 3d looking lasers
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:51  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:10  root
14  * Initial import.
15  *
16  * 
17  * 5     7/30/99 7:01p Dave
18  * Dogfight escort gauge. Fixed up laser rendering in Glide.
19  * 
20  * 4     7/27/99 3:09p Dave
21  * Made g400 work. Whee.
22  * 
23  * 3     5/27/99 6:17p Dave
24  * Added in laser glows.
25  * 
26  * 2     10/07/98 10:53a Dave
27  * Initial checkin.
28  * 
29  * 1     10/07/98 10:51a Dave
30  * 
31  * 26    5/13/98 3:10p John
32  * made detail slider for weapon rendering change the distance that lasers
33  * become non-textured.  The lowest setting turns off missile trail
34  * rendering.
35  * 
36  * 25    5/05/98 11:15p Lawrance
37  * Optimize weapon flyby sound determination
38  * 
39  * 24    4/10/98 5:20p John
40  * Changed RGB in lighting structure to be ubytes.  Removed old
41  * not-necessary 24 bpp software stuff.
42  * 
43  * 23    3/17/98 3:02p John
44  * made lasers draw as non-textured only on software.
45  * 
46  * 22    3/17/98 3:01p John
47  * Make thicker lasers not render as polys further away.
48  * 
49  * 21    2/26/98 3:26p John
50  * Added code to turn off laser rendering
51  * 
52  * 20    1/29/98 9:46a John
53  * Capped debris length
54  * 
55  * 19    1/23/98 5:08p John
56  * Took L out of vertex structure used B (blue) instead.   Took all small
57  * fireballs out of fireball types and used particles instead.  Fixed some
58  * debris explosion things.  Restructured fireball code.   Restructured
59  * some lighting code.   Made dynamic lighting on by default. Made groups
60  * of lasers only cast one light.  Made fireballs not cast light.
61  * 
62  * 18    1/19/98 8:51a John
63  * Did a quick out if both points of laser off same side of view pyramid.
64  * 
65  * 17    1/06/98 6:18p John
66  * Made debris render as a blur.  Had to make g3_draw_laser take tmap
67  * flags.
68  * 
69  * 16    12/15/97 10:09p John
70  * put in some debug laser code.
71  * 
72  * 15    12/15/97 11:32a John
73  * New Laser Code
74  * 
75  * 14    10/23/97 8:32p John
76  * Increased laser to dot distance
77  * 
78  * 13    9/20/97 9:45a John
79  * made lasers not draw as pixels as fast as before if viewing from the
80  * side.
81  * 
82  * 
83  * 12    8/19/97 11:42p Lawrance
84  * use atan2_safe() instead of atan2()
85  * 
86  * 11    8/19/97 12:54p Sandeep
87  * Fixed lasers to work in optimized build
88  * 
89  * 10    6/24/97 6:22p John
90  * added detail flags.
91  * sped up motion debris system a bit.
92  * 
93  * 9     5/29/97 3:10p John
94  * Took out debug menu.  
95  * Made software scaler draw larger bitmaps.
96  * Optimized Direct3D some.
97  * 
98  * 8     4/29/97 9:55a John
99  * 
100  * 7     4/22/97 4:11p John
101  * New debug var stuff
102  * 
103  * 6     3/28/97 6:10p Lawrance
104  * draw lasers so end appears at gun mount tip on first frame
105  * 
106  * 5     3/06/97 8:48a John
107  * fixed bug with lasers drawing too close.
108  * 
109  * 4     2/07/97 9:07a John
110  * made lasers not fade by default.
111  * 
112  * 3     2/03/97 8:01p John
113  * Added debug code to fade lasers out with distance.
114  * 
115  * 2     12/11/96 12:41p John
116  * Added new code to draw 3d laser using 2d ellipses.
117  * 
118  * 1     12/11/96 12:13p John
119  *
120  * $NoKeywords: $
121  */
122
123 #include "2d.h"
124 #include "3d.h"
125 #include "3dinternal.h"
126 #include "systemvars.h"
127 #include "key.h"
128
129 int Lasers = 1;
130 DCF_BOOL( lasers, Lasers );
131
132 // This assumes you have already set a color with gr_set_color or gr_set_color_fast
133 // and a bitmap with gr_set_bitmap.  If it is very far away, it draws the laser
134 // as flat-shaded using current color, else textured using current texture.
135 // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels.
136 float g3_draw_laser(vector *headp, float head_width, vector *tailp, float tail_width, uint tmap_flags, float max_len )
137 {
138         if (!Lasers){
139                 return 0.0f;
140         }
141
142         float headx, heady, headr, tailx, taily, tailr;
143         vertex pt1, pt2;
144         float depth;
145         int head_on = 0;
146
147         Assert( G3_count == 1 );
148
149         g3_rotate_vertex(&pt1,headp);
150
151         g3_project_vertex(&pt1);
152         if (pt1.flags & PF_OVERFLOW) 
153                 return 0.0f;
154
155         g3_rotate_vertex(&pt2,tailp);
156
157         g3_project_vertex(&pt2);
158         if (pt2.flags & PF_OVERFLOW) 
159                 return 0.0f;
160
161         if ( (pt1.codes & pt2.codes) != 0 )     {
162                 // Both off the same side
163                 return 0.0f;
164         }
165
166         headx = pt1.sx;
167         heady = pt1.sy;
168         headr = (head_width*Matrix_scale.x*Canv_w2*pt1.sw);
169
170         tailx = pt2.sx;
171         taily = pt2.sy;
172         tailr = (tail_width*Matrix_scale.x*Canv_w2*pt2.sw);
173
174         float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
175
176         // Cap the length if needed.
177         if ( (max_len > 1.0f) && (len_2d > max_len) )   {
178                 float ratio = max_len / len_2d;
179         
180                 tailx = headx + ( tailx - headx ) * ratio;
181                 taily = heady + ( taily - heady ) * ratio;
182                 tailr = headr + ( tailr - headr ) * ratio;
183
184                 len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
185         }
186
187         depth = (pt1.z+pt2.z)*0.5f;
188
189         float max_r  = headr;
190         float a;
191         if ( tailr > max_r ) 
192                 max_r = tailr;
193
194         if ( max_r < 1.0f )
195                 max_r = 1.0f;
196
197         float mx, my, w, h1,h2;
198
199         if ( len_2d < max_r ) {
200
201                 h1 = headr + (max_r-len_2d);
202                 if ( h1 > max_r ) h1 = max_r;
203                 h2 = tailr + (max_r-len_2d);
204                 if ( h2 > max_r ) h2 = max_r;
205
206                 len_2d = max_r;
207                 if ( fl_abs(tailx - headx) > 0.01f )    {
208                         a = (float)atan2( taily-heady, tailx-headx );
209                 } else {
210                         a = 0.0f;
211                 }
212
213                 w = len_2d;
214                 head_on = 1;
215
216         } else {
217                 a = atan2_safe( taily-heady, tailx-headx );
218
219                 w = len_2d;
220
221                 h1 = headr;
222                 h2 = tailr;
223                 head_on = 0;
224         }
225         
226         mx = (tailx+headx)/2.0f;
227         my = (taily+heady)/2.0f;
228
229 //      gr_set_color(255,0,0);
230 //      g3_draw_line( &pt1, &pt2 );
231
232 //      gr_set_color( 255, 0, 0 );
233 //      gr_pixel( fl2i(mx),fl2i(my) );
234
235         // Draw box with width 'w' and height 'h' at angle 'a' from horizontal
236         // centered around mx, my
237
238         if ( h1 < 1.0f ) h1 = 1.0f;
239         if ( h2 < 1.0f ) h2 = 1.0f;
240
241         float sa, ca;
242
243         sa = (float)sin(a);
244         ca = (float)cos(a);
245
246         vertex v[4];
247         vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
248
249         float sw;
250         if ( depth < 0.0f ) depth = 0.0f;
251         sw = 1.0f / depth;
252         
253         v[0].sx = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx;
254         v[0].sy = (-w/2.0f)*sa - (-h1/2.0f)*ca + my;
255         v[0].z = pt1.z;
256         v[0].sw = pt1.sw;
257         v[0].u = 0.0f;
258         v[0].v = 0.0f;
259         v[0].b = 191;
260
261         v[1].sx = (w/2.0f)*ca + (-h2/2.0f)*sa + mx;
262         v[1].sy = (w/2.0f)*sa - (-h2/2.0f)*ca + my;
263         v[1].z = pt2.z;
264         v[1].sw = pt2.sw;
265         v[1].u = 1.0f;
266         v[1].v = 0.0f;
267         v[1].b = 191;
268
269         v[2].sx = (w/2.0f)*ca + (h2/2.0f)*sa + mx;
270         v[2].sy = (w/2.0f)*sa - (h2/2.0f)*ca + my;
271         v[2].z = pt2.z;
272         v[2].sw = pt2.sw;
273         v[2].u = 1.0f;
274         v[2].v = 1.0f;
275         v[2].b = 191;
276
277         v[3].sx = (-w/2.0f)*ca + (h1/2.0f)*sa + mx;
278         v[3].sy = (-w/2.0f)*sa - (h1/2.0f)*ca + my;
279         v[3].z = pt1.z;
280         v[3].sw = pt1.sw;
281         v[3].u = 0.0f;
282         v[3].v = 1.0f;
283         v[3].b = 191;
284
285         if(gr_screen.mode == GR_GLIDE){
286                 gr_tmapper(4, vertlist, tmap_flags);    
287         } else {
288                 gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_CORRECT);        
289         }
290
291         return depth;
292 }
293
294 // Draw a laser shaped 3d looking thing using vertex coloring (useful for things like colored laser glows)
295 // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels
296 float g3_draw_laser_rgb(vector *headp, float head_width, vector *tailp, float tail_width, int r, int g, int b, uint tmap_flags, float max_len )
297 {
298         if (!Lasers){
299                 return 0.0f;
300         }
301
302         float headx, heady, headr, tailx, taily, tailr;
303         vertex pt1, pt2;
304         float depth;
305         int head_on = 0;
306
307         Assert( G3_count == 1 );
308
309         g3_rotate_vertex(&pt1,headp);
310
311         g3_project_vertex(&pt1);
312         if (pt1.flags & PF_OVERFLOW) 
313                 return 0.0f;
314
315         g3_rotate_vertex(&pt2,tailp);
316
317         g3_project_vertex(&pt2);
318         if (pt2.flags & PF_OVERFLOW) 
319                 return 0.0f;
320
321         if ( (pt1.codes & pt2.codes) != 0 )     {
322                 // Both off the same side
323                 return 0.0f;
324         }
325
326         headx = pt1.sx;
327         heady = pt1.sy;
328         headr = (head_width*Matrix_scale.x*Canv_w2*pt1.sw);
329
330         tailx = pt2.sx;
331         taily = pt2.sy;
332         tailr = (tail_width*Matrix_scale.x*Canv_w2*pt2.sw);
333
334         float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
335
336         // Cap the length if needed.
337         if ( (max_len > 1.0f) && (len_2d > max_len) )   {
338                 float ratio = max_len / len_2d;
339         
340                 tailx = headx + ( tailx - headx ) * ratio;
341                 taily = heady + ( taily - heady ) * ratio;
342                 tailr = headr + ( tailr - headr ) * ratio;
343
344                 len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
345         }
346
347         depth = (pt1.z+pt2.z)*0.5f;
348
349         float max_r  = headr;
350         float a;
351         if ( tailr > max_r ) 
352                 max_r = tailr;
353
354         if ( max_r < 1.0f )
355                 max_r = 1.0f;
356
357         float mx, my, w, h1,h2;
358
359         if ( len_2d < max_r ) {
360
361                 h1 = headr + (max_r-len_2d);
362                 if ( h1 > max_r ) h1 = max_r;
363                 h2 = tailr + (max_r-len_2d);
364                 if ( h2 > max_r ) h2 = max_r;
365
366                 len_2d = max_r;
367                 if ( fl_abs(tailx - headx) > 0.01f )    {
368                         a = (float)atan2( taily-heady, tailx-headx );
369                 } else {
370                         a = 0.0f;
371                 }
372
373                 w = len_2d;
374                 head_on = 1;
375
376         } else {
377                 a = atan2_safe( taily-heady, tailx-headx );
378
379                 w = len_2d;
380
381                 h1 = headr;
382                 h2 = tailr;
383                 head_on = 0;
384         }
385         
386         mx = (tailx+headx)/2.0f;
387         my = (taily+heady)/2.0f;
388
389 //      gr_set_color(255,0,0);
390 //      g3_draw_line( &pt1, &pt2 );
391
392 //      gr_set_color( 255, 0, 0 );
393 //      gr_pixel( fl2i(mx),fl2i(my) );
394
395         // Draw box with width 'w' and height 'h' at angle 'a' from horizontal
396         // centered around mx, my
397
398         if ( h1 < 1.0f ) h1 = 1.0f;
399         if ( h2 < 1.0f ) h2 = 1.0f;
400
401         float sa, ca;
402
403         sa = (float)sin(a);
404         ca = (float)cos(a);
405
406         vertex v[4];
407         vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
408
409         float sw;
410         if ( depth < 0.0f ) depth = 0.0f;
411         sw = 1.0f / depth;
412         
413         v[0].sx = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx;
414         v[0].sy = (-w/2.0f)*sa - (-h1/2.0f)*ca + my;
415         v[0].z = pt1.z;
416         v[0].sw = pt1.sw;
417         v[0].u = 0.0f;
418         v[0].v = 0.0f;
419         v[0].r = (ubyte)r;
420         v[0].g = (ubyte)g;
421         v[0].b = (ubyte)b;
422         v[0].a = 255;
423
424         v[1].sx = (w/2.0f)*ca + (-h2/2.0f)*sa + mx;
425         v[1].sy = (w/2.0f)*sa - (-h2/2.0f)*ca + my;
426         v[1].z = pt2.z;
427         v[1].sw = pt2.sw;
428         v[1].u = 1.0f;
429         v[1].v = 0.0f;
430         v[1].r = (ubyte)r;
431         v[1].g = (ubyte)g;
432         v[1].b = (ubyte)b;
433         v[1].a = 255;
434
435         v[2].sx = (w/2.0f)*ca + (h2/2.0f)*sa + mx;
436         v[2].sy = (w/2.0f)*sa - (h2/2.0f)*ca + my;
437         v[2].z = pt2.z;
438         v[2].sw = pt2.sw;
439         v[2].u = 1.0f;
440         v[2].v = 1.0f;
441         v[2].r = (ubyte)r;
442         v[2].g = (ubyte)g;
443         v[2].b = (ubyte)b;
444         v[2].a = 255;
445
446         v[3].sx = (-w/2.0f)*ca + (h1/2.0f)*sa + mx;
447         v[3].sy = (-w/2.0f)*sa - (h1/2.0f)*ca + my;
448         v[3].z = pt1.z;
449         v[3].sw = pt1.sw;
450         v[3].u = 0.0f;
451         v[3].v = 1.0f;
452         v[3].r = (ubyte)r;
453         v[3].g = (ubyte)g;
454         v[3].b = (ubyte)b;
455         v[3].a = 255;
456         
457         if(gr_screen.mode == GR_GLIDE){
458                 gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
459         } else {
460                 gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT);
461         }       
462
463         return depth;
464 }
465