FS2_Open
Open source remastering of the Freespace 2 engine
3dlaser.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "cmdline/cmdline.h"
13 #include "debugconsole/console.h"
14 #include "globalincs/systemvars.h"
15 #include "graphics/2d.h"
16 #include "io/key.h"
17 #include "render/3dinternal.h"
18 
19 
20 
21 int Lasers = 1;
22 DCF_BOOL( lasers, Lasers )
23 
24 float g3_draw_laser_htl(const vec3d *p0, float width1, const vec3d *p1, float width2, int r, int g, int b, uint tmap_flags)
25 {
26  width1 *= 0.5f;
27  width2 *= 0.5f;
28  vec3d uvec, fvec, rvec, center, reye, rfvec;
29 
30  vm_vec_sub( &fvec, p0, p1 );
31  vm_vec_normalize_safe( &fvec );
32  vm_vec_copy_scale(&rfvec, &fvec, -1.0f);
33 
34  vm_vec_avg( &center, p0, p1 ); //needed for the return value only
35  vm_vec_sub(&reye, &Eye_position, &center);
36  vm_vec_normalize(&reye);
37 
38  // code intended to prevent possible null vector normalize issue - start
39  if (vm_test_parallel(&reye,&fvec)){
40  fvec.xyz.x = -reye.xyz.z;
41  fvec.xyz.y = 0.0f;
42  fvec.xyz.z = -reye.xyz.x;
43  }
44 
45  if (vm_test_parallel(&reye,&rfvec)){
46  fvec.xyz.x = reye.xyz.z;
47  fvec.xyz.y = 0.0f;
48  fvec.xyz.z = reye.xyz.x;
49  }
50  // code intended to prevent possible null vector normalize issue - end
51 
52  vm_vec_cross(&uvec,&fvec,&reye);
53  vm_vec_normalize(&uvec);
54  vm_vec_cross(&fvec,&uvec,&reye);
55  vm_vec_normalize(&fvec);
56 
57  //now recompute right vector, in case it wasn't entirely perpendiclar
58  vm_vec_cross(&rvec,&uvec,&fvec);
59 
60  // Now have uvec, which is up vector and rvec which is the normal
61  // of the face.
62 
63  int i;
64  vec3d start, end;
65  vm_vec_scale_add(&start, p0, &fvec, -width1);
66  vm_vec_scale_add(&end, p1, &fvec, width2);
67  vec3d vecs[4];
68  vertex pts[4];
69  vertex *ptlist[8] =
70  { &pts[3], &pts[2], &pts[1], &pts[0],
71  &pts[0], &pts[1], &pts[2], &pts[3]};
72 
73  vm_vec_scale_add( &vecs[0], &start, &uvec, width1 );
74  vm_vec_scale_add( &vecs[1], &end, &uvec, width2 );
75  vm_vec_scale_add( &vecs[2], &end, &uvec, -width2 );
76  vm_vec_scale_add( &vecs[3], &start, &uvec, -width1 );
77 
78  for (i=0; i<4; i++ ) {
79  g3_transfer_vertex( &pts[i], &vecs[i] );
80  }
81  ptlist[0]->texture_position.u = 0.0f;
82  ptlist[0]->texture_position.v = 0.0f;
83  ptlist[1]->texture_position.u = 1.0f;
84  ptlist[1]->texture_position.v = 0.0f;
85  ptlist[2]->texture_position.u = 1.0f;
86  ptlist[2]->texture_position.v = 1.0f;
87  ptlist[3]->texture_position.u = 0.0f;
88  ptlist[3]->texture_position.v = 1.0f;
89  ptlist[0]->r = (ubyte)r;
90  ptlist[0]->g = (ubyte)g;
91  ptlist[0]->b = (ubyte)b;
92  ptlist[0]->a = 255;
93  ptlist[1]->r = (ubyte)r;
94  ptlist[1]->g = (ubyte)g;
95  ptlist[1]->b = (ubyte)b;
96  ptlist[1]->a = 255;
97  ptlist[2]->r = (ubyte)r;
98  ptlist[2]->g = (ubyte)g;
99  ptlist[2]->b = (ubyte)b;
100  ptlist[2]->a = 255;
101  ptlist[3]->r = (ubyte)r;
102  ptlist[3]->g = (ubyte)g;
103  ptlist[3]->b = (ubyte)b;
104  ptlist[3]->a = 255;
105 
106  gr_tmapper(4, ptlist,tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT);
107 
108  return center.xyz.z;
109 }
110 
111 
112 // This assumes you have already set a color with gr_set_color or gr_set_color_fast
113 // and a bitmap with gr_set_bitmap. If it is very far away, it draws the laser
114 // as flat-shaded using current color, else textured using current texture.
115 // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels.
116 float g3_draw_laser(const vec3d *headp, float head_width, const vec3d *tailp, float tail_width, uint tmap_flags, float max_len )
117 {
118  if (!Lasers) {
119  return 0.0f;
120  }
121 
122  if ( !Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT) ) {
123  return g3_draw_laser_htl(headp, head_width, tailp, tail_width, 255,255,255, tmap_flags | TMAP_HTL_3D_UNLIT);
124  }
125 
126  float headx, heady, headr, tailx, taily, tailr;
127  vertex pt1, pt2;
128  float depth;
129 
130  Assert( G3_count == 1 );
131 
132  g3_rotate_vertex(&pt1,headp);
133 
134  g3_project_vertex(&pt1);
135  if (pt1.flags & PF_OVERFLOW)
136  return 0.0f;
137 
138  g3_rotate_vertex(&pt2,tailp);
139 
140  g3_project_vertex(&pt2);
141  if (pt2.flags & PF_OVERFLOW)
142  return 0.0f;
143 
144  if ( (pt1.codes & pt2.codes) != 0 ) {
145  // Both off the same side
146  return 0.0f;
147  }
148 
149  headx = pt1.screen.xyw.x;
150  heady = pt1.screen.xyw.y;
151  headr = (head_width*Matrix_scale.xyz.x*Canv_w2*pt1.screen.xyw.w);
152 
153  tailx = pt2.screen.xyw.x;
154  taily = pt2.screen.xyw.y;
155  tailr = (tail_width*Matrix_scale.xyz.x*Canv_w2*pt2.screen.xyw.w);
156 
157  float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
158 
159  // Cap the length if needed.
160  if ( (max_len > 1.0f) && (len_2d > max_len) ) {
161  float ratio = max_len / len_2d;
162 
163  tailx = headx + ( tailx - headx ) * ratio;
164  taily = heady + ( taily - heady ) * ratio;
165  tailr = headr + ( tailr - headr ) * ratio;
166 
167  len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
168  }
169 
170  depth = (pt1.world.xyz.z+pt2.world.xyz.z)*0.5f;
171 
172  float max_r = headr;
173  float a;
174  if ( tailr > max_r )
175  max_r = tailr;
176 
177  if ( max_r < 1.0f )
178  max_r = 1.0f;
179 
180  float mx, my, w, h1,h2;
181 
182  if ( len_2d < max_r ) {
183 
184  h1 = headr + (max_r-len_2d);
185  if ( h1 > max_r ) h1 = max_r;
186  h2 = tailr + (max_r-len_2d);
187  if ( h2 > max_r ) h2 = max_r;
188 
189  len_2d = max_r;
190  if ( fl_abs(tailx - headx) > 0.01f ) {
191  a = (float)atan2( taily-heady, tailx-headx );
192  } else {
193  a = 0.0f;
194  }
195 
196  w = len_2d;
197 
198  } else {
199  a = atan2_safe( taily-heady, tailx-headx );
200 
201  w = len_2d;
202 
203  h1 = headr;
204  h2 = tailr;
205  }
206 
207  mx = (tailx+headx)/2.0f;
208  my = (taily+heady)/2.0f;
209 
210  // Draw box with width 'w' and height 'h' at angle 'a' from horizontal
211  // centered around mx, my
212 
213  if ( h1 < 1.0f ) h1 = 1.0f;
214  if ( h2 < 1.0f ) h2 = 1.0f;
215 
216  float sa, ca;
217 
218  sa = sinf(a);
219  ca = cosf(a);
220 
221  vertex v[4];
222  vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
223  memset(v,0,sizeof(vertex)*4);
224 
225  if ( depth < 0.0f ) depth = 0.0f;
226 
227  v[0].screen.xyw.x = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx;
228  v[0].screen.xyw.y = (-w/2.0f)*sa - (-h1/2.0f)*ca + my;
229  v[0].world.xyz.z = pt1.world.xyz.z;
230  v[0].screen.xyw.w = pt1.screen.xyw.w;
231  v[0].texture_position.u = 0.0f;
232  v[0].texture_position.v = 0.0f;
233  v[0].b = 191;
234 
235  v[1].screen.xyw.x = (w/2.0f)*ca + (-h2/2.0f)*sa + mx;
236  v[1].screen.xyw.y = (w/2.0f)*sa - (-h2/2.0f)*ca + my;
237  v[1].world.xyz.z = pt2.world.xyz.z;
238  v[1].screen.xyw.w = pt2.screen.xyw.w;
239  v[1].texture_position.u = 1.0f;
240  v[1].texture_position.v = 0.0f;
241  v[1].b = 191;
242 
243  v[2].screen.xyw.x = (w/2.0f)*ca + (h2/2.0f)*sa + mx;
244  v[2].screen.xyw.y = (w/2.0f)*sa - (h2/2.0f)*ca + my;
245  v[2].world.xyz.z = pt2.world.xyz.z;
246  v[2].screen.xyw.w = pt2.screen.xyw.w;
247  v[2].texture_position.u = 1.0f;
248  v[2].texture_position.v = 1.0f;
249  v[2].b = 191;
250 
251  v[3].screen.xyw.x = (-w/2.0f)*ca + (h1/2.0f)*sa + mx;
252  v[3].screen.xyw.y = (-w/2.0f)*sa - (h1/2.0f)*ca + my;
253  v[3].world.xyz.z = pt1.world.xyz.z;
254  v[3].screen.xyw.w = pt1.screen.xyw.w;
255  v[3].texture_position.u = 0.0f;
256  v[3].texture_position.v = 1.0f;
257  v[3].b = 191;
258 
259  gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_CORRECT);
260 
261  return depth;
262 }
263 
264 
265 // Draw a laser shaped 3d looking thing using vertex coloring (useful for things like colored laser glows)
266 // If max_len is > 1.0, then this caps the length to be no longer than max_len pixels
267 float g3_draw_laser_rgb(const vec3d *headp, float head_width, const vec3d *tailp, float tail_width, int r, int g, int b, uint tmap_flags, float max_len )
268 {
269  if (!Lasers){
270  return 0.0f;
271  }
272  if((!Cmdline_nohtl) && tmap_flags & TMAP_HTL_3D_UNLIT){
273  return g3_draw_laser_htl(headp, head_width, tailp, tail_width, r, g, b, tmap_flags | TMAP_HTL_3D_UNLIT);
274  }
275  float headx, heady, headr, tailx, taily, tailr;
276  vertex pt1, pt2;
277  float depth;
278 
279  Assert( G3_count == 1 );
280 
281  g3_rotate_vertex(&pt1,headp);
282 
283  g3_project_vertex(&pt1);
284  if (pt1.flags & PF_OVERFLOW)
285  return 0.0f;
286 
287  g3_rotate_vertex(&pt2,tailp);
288 
289  g3_project_vertex(&pt2);
290  if (pt2.flags & PF_OVERFLOW)
291  return 0.0f;
292 
293  if ( (pt1.codes & pt2.codes) != 0 ) {
294  // Both off the same side
295  return 0.0f;
296  }
297 
298  headx = pt1.screen.xyw.x;
299  heady = pt1.screen.xyw.y;
300  headr = (head_width*Matrix_scale.xyz.x*Canv_w2*pt1.screen.xyw.w);
301 
302  tailx = pt2.screen.xyw.x;
303  taily = pt2.screen.xyw.y;
304  tailr = (tail_width*Matrix_scale.xyz.x*Canv_w2*pt2.screen.xyw.w);
305 
306  float len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
307 
308  // Cap the length if needed.
309  if ( (max_len > 1.0f) && (len_2d > max_len) ) {
310  float ratio = max_len / len_2d;
311 
312  tailx = headx + ( tailx - headx ) * ratio;
313  taily = heady + ( taily - heady ) * ratio;
314  tailr = headr + ( tailr - headr ) * ratio;
315 
316  len_2d = fl_sqrt( (tailx-headx)*(tailx-headx) + (taily-heady)*(taily-heady) );
317  }
318 
319  depth = (pt1.world.xyz.z+pt2.world.xyz.z)*0.5f;
320 
321  float max_r = headr;
322  float a;
323  if ( tailr > max_r )
324  max_r = tailr;
325 
326  if ( max_r < 1.0f )
327  max_r = 1.0f;
328 
329  float mx, my, w, h1,h2;
330 
331  if ( len_2d < max_r ) {
332 
333  h1 = headr + (max_r-len_2d);
334  if ( h1 > max_r ) h1 = max_r;
335  h2 = tailr + (max_r-len_2d);
336  if ( h2 > max_r ) h2 = max_r;
337 
338  len_2d = max_r;
339  if ( fl_abs(tailx - headx) > 0.01f ) {
340  a = (float)atan2( taily-heady, tailx-headx );
341  } else {
342  a = 0.0f;
343  }
344 
345  w = len_2d;
346 
347  } else {
348  a = atan2_safe( taily-heady, tailx-headx );
349 
350  w = len_2d;
351 
352  h1 = headr;
353  h2 = tailr;
354  }
355 
356  mx = (tailx+headx)/2.0f;
357  my = (taily+heady)/2.0f;
358 
359  // Draw box with width 'w' and height 'h' at angle 'a' from horizontal
360  // centered around mx, my
361 
362  if ( h1 < 1.0f ) h1 = 1.0f;
363  if ( h2 < 1.0f ) h2 = 1.0f;
364 
365  float sa, ca;
366 
367  sa = sinf(a);
368  ca = cosf(a);
369 
370  vertex v[4];
371  vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
372  memset(v,0,sizeof(vertex)*4);
373 
374  if ( depth < 0.0f ) depth = 0.0f;
375 
376  v[0].screen.xyw.x = (-w/2.0f)*ca + (-h1/2.0f)*sa + mx;
377  v[0].screen.xyw.y = (-w/2.0f)*sa - (-h1/2.0f)*ca + my;
378  v[0].world.xyz.z = pt1.world.xyz.z;
379  v[0].screen.xyw.w = pt1.screen.xyw.w;
380  v[0].texture_position.u = 0.0f;
381  v[0].texture_position.v = 0.0f;
382  v[0].r = (ubyte)r;
383  v[0].g = (ubyte)g;
384  v[0].b = (ubyte)b;
385  v[0].a = 255;
386 
387  v[1].screen.xyw.x = (w/2.0f)*ca + (-h2/2.0f)*sa + mx;
388  v[1].screen.xyw.y = (w/2.0f)*sa - (-h2/2.0f)*ca + my;
389  v[1].world.xyz.z = pt2.world.xyz.z;
390  v[1].screen.xyw.w = pt2.screen.xyw.w;
391  v[1].texture_position.u = 1.0f;
392  v[1].texture_position.v = 0.0f;
393  v[1].r = (ubyte)r;
394  v[1].g = (ubyte)g;
395  v[1].b = (ubyte)b;
396  v[1].a = 255;
397 
398  v[2].screen.xyw.x = (w/2.0f)*ca + (h2/2.0f)*sa + mx;
399  v[2].screen.xyw.y = (w/2.0f)*sa - (h2/2.0f)*ca + my;
400  v[2].world.xyz.z = pt2.world.xyz.z;
401  v[2].screen.xyw.w = pt2.screen.xyw.w;
402  v[2].texture_position.u = 1.0f;
403  v[2].texture_position.v = 1.0f;
404  v[2].r = (ubyte)r;
405  v[2].g = (ubyte)g;
406  v[2].b = (ubyte)b;
407  v[2].a = 255;
408 
409  v[3].screen.xyw.x = (-w/2.0f)*ca + (h1/2.0f)*sa + mx;
410  v[3].screen.xyw.y = (-w/2.0f)*sa - (h1/2.0f)*ca + my;
411  v[3].world.xyz.z = pt1.world.xyz.z;
412  v[3].screen.xyw.w = pt1.screen.xyw.w;
413  v[3].texture_position.u = 0.0f;
414  v[3].texture_position.v = 1.0f;
415  v[3].r = (ubyte)r;
416  v[3].g = (ubyte)g;
417  v[3].b = (ubyte)b;
418  v[3].a = 255;
419 
420  gr_tmapper(4, vertlist, tmap_flags | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT);
421 
422  return depth;
423 }
#define gr_tmapper
Definition: 2d.h:804
struct screen3d::@234::@236 xyw
int i
Definition: multi_pxo.cpp:466
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
float v
Definition: pstypes.h:135
ubyte g
Definition: pstypes.h:175
ubyte g3_transfer_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:84
Assert(pm!=NULL)
Definition: pstypes.h:88
GLint GLint GLsizei GLsizei GLsizei depth
Definition: Glext.h:5180
hull_check p0
Definition: lua.cpp:5051
struct vec3d::@225::@227 xyz
#define TMAP_HTL_3D_UNLIT
Definition: tmapper.h:63
GLclampf f
Definition: Glext.h:7097
float atan2_safe(float y, float x)
Definition: vecmat.cpp:68
uv_pair texture_position
Definition: pstypes.h:174
ubyte a
Definition: pstypes.h:175
#define PF_OVERFLOW
Definition: 3d.h:22
int Cmdline_nohtl
Definition: cmdline.cpp:438
float g3_draw_laser_rgb(const vec3d *headp, float head_width, const vec3d *tailp, float tail_width, int r, int g, int b, uint tmap_flags, float max_len)
Definition: 3dlaser.cpp:267
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
unsigned int uint
Definition: pstypes.h:64
screen3d screen
Definition: pstypes.h:173
GLboolean GLboolean g
Definition: Glext.h:5781
#define TMAP_FLAG_GOURAUD
Definition: tmapper.h:40
float g3_draw_laser(const vec3d *headp, float head_width, const vec3d *tailp, float tail_width, uint tmap_flags, float max_len)
Definition: 3dlaser.cpp:116
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
int vm_test_parallel(const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:655
#define w(p)
Definition: modelsinc.h:68
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
hull_check p1
Definition: lua.cpp:5052
#define fl_abs(fl)
Definition: floating.h:31
float u
Definition: pstypes.h:135
int Lasers
Definition: 3dlaser.cpp:21
float vm_vec_normalize_safe(vec3d *v)
Definition: vecmat.cpp:471
int g3_project_vertex(vertex *point)
Definition: 3dmath.cpp:202
vec3d Matrix_scale
Definition: 3dsetup.cpp:34
unsigned char ubyte
Definition: pstypes.h:62
#define TMAP_FLAG_RGB
Definition: tmapper.h:39
GLuint start
Definition: Gl.h:1502
ubyte b
Definition: pstypes.h:175
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define TMAP_FLAG_CORRECT
Definition: tmapper.h:37
ubyte flags
Definition: pstypes.h:178
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
float g3_draw_laser_htl(const vec3d *p0, float width1, const vec3d *p1, float width2, int r, int g, int b, uint tmap_flags)
Definition: 3dlaser.cpp:24
vec3d Eye_position
Definition: 3dsetup.cpp:27
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
#define DCF_BOOL(function_name, bool_variable)
Definition: console.h:71
#define fl_sqrt(fl)
Definition: floating.h:29
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
vec3d * vm_vec_avg(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:217
vec3d world
Definition: pstypes.h:172
float Canv_w2
Definition: 3dsetup.cpp:39
int G3_count
Definition: 3dsetup.cpp:59
ubyte codes
Definition: pstypes.h:177
vec3d * vm_vec_cross(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:645
const GLdouble * v
Definition: Glext.h:5322
GLuint GLuint end
Definition: Gl.h:1502
ubyte r
Definition: pstypes.h:175
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460