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 "bmpman/bmpman.h"
13 #include "cmdline/cmdline.h"
14 #include "globalincs/alphacolors.h"
15 #include "graphics/grbatch.h"
16 #include "graphics/tmapper.h"
17 #include "graphics/matrix.h"
18 #include "io/key.h"
19 #include "physics/physics.h" // For Physics_viewer_bank for g3_draw_rotated_bitmap
20 #include "render/3dinternal.h"
21 #include "render/batching.h"
22
23 /**
24 * Deal with a clipped line
25 */
must_clip_line(vertex * p0,vertex * p1,ubyte codes_or,uint flags)26 int must_clip_line(vertex *p0, vertex *p1, ubyte codes_or, uint flags)
27 {
28 int ret = 0;
29
30 clip_line(&p0, &p1, codes_or, flags);
31
32 if (p0->codes & p1->codes) goto free_points;
33
34 codes_or = (unsigned char)(p0->codes | p1->codes);
35
36 if (codes_or & CC_BEHIND) goto free_points;
37
38 if (!(p0->flags&PF_PROJECTED))
39 g3_project_vertex(p0);
40
41 if (p0->flags&PF_OVERFLOW) goto free_points;
42
43 if (!(p1->flags&PF_PROJECTED))
44 g3_project_vertex(p1);
45
46 if (p1->flags&PF_OVERFLOW) goto free_points;
47
48 gr_aaline( p0, p1 );
49
50 ret = 1;
51
52 //frees temp points
53 free_points:
54
55 if (p0->flags & PF_TEMP_POINT)
56 free_temp_point(p0);
57
58 if (p1->flags & PF_TEMP_POINT)
59 free_temp_point(p1);
60
61 return ret;
62 }
63
64 /**
65 * Draws a line. takes two points. returns true if drew
66 */
g3_draw_line(vertex * p0,vertex * p1)67 int g3_draw_line(vertex *p0, vertex *p1)
68 {
69 #ifdef FRED_OGL_COMMENT_OUT_FOR_NOW
70 if(Fred_running)
71 {
72 gr_aaline( p0, p1 );
73 return 0;
74 }
75 #endif
76
77 ubyte codes_or;
78
79 Assert( G3_count == 1 );
80
81 if (p0->codes & p1->codes)
82 return 0;
83
84 codes_or = (unsigned char)(p0->codes | p1->codes);
85
86 if (codes_or & CC_BEHIND)
87 return must_clip_line(p0,p1,codes_or,0);
88
89 if (!(p0->flags&PF_PROJECTED))
90 g3_project_vertex(p0);
91
92 if (p0->flags&PF_OVERFLOW)
93 return must_clip_line(p0,p1,codes_or,0);
94
95
96 if (!(p1->flags&PF_PROJECTED))
97 g3_project_vertex(p1);
98
99 if (p1->flags&PF_OVERFLOW)
100 return must_clip_line(p0,p1,codes_or,0);
101
102 gr_aaline( p0, p1 );
103
104 return 0;
105 }
106
107
108 //returns true if a plane is facing the viewer. takes the unrotated surface
109 //normal of the plane, and a point on it. The normal need not be normalized
g3_check_normal_facing(const vec3d * v,const vec3d * norm)110 int g3_check_normal_facing(const vec3d *v, const vec3d *norm)
111 {
112 vec3d tempv;
113
114 Assert( G3_count == 1 );
115
116 vm_vec_sub(&tempv,&View_position,v);
117
118 return (vm_vec_dot(&tempv,norm) > 0.0f);
119 }
120
121 //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
122 //radius, but not to the distance from the eye
g3_draw_sphere(vertex * pnt,float rad)123 int g3_draw_sphere(vertex *pnt, float rad)
124 {
125 Assert( G3_count == 1 );
126
127 if (! (pnt->codes & CC_BEHIND)) {
128
129 if (! (pnt->flags & PF_PROJECTED))
130 g3_project_vertex(pnt);
131
132 if (! (pnt->codes & PF_OVERFLOW)) {
133 float r2,t;
134
135 r2 = rad*Matrix_scale.xyz.x;
136
137 t=r2*Canv_w2/pnt->world.xyz.z;
138
139 gr_circle(fl2i(pnt->screen.xyw.x),fl2i(pnt->screen.xyw.y),fl2i(t*2.0f),GR_RESIZE_NONE);
140 }
141 }
142
143 return 0;
144 }
145
g3_draw_sphere_ez(const vec3d * pnt,float rad)146 int g3_draw_sphere_ez(const vec3d *pnt, float rad)
147 {
148 vertex pt;
149 ubyte flags;
150
151 Assert( G3_count == 1 );
152
153 flags = g3_rotate_vertex(&pt, pnt);
154
155 if (flags == 0) {
156
157 g3_project_vertex(&pt);
158
159 if (!(pt.flags & PF_OVERFLOW)) {
160
161 g3_draw_sphere( &pt, rad );
162 }
163 }
164
165 return 0;
166 }
167
168 // get bitmap dims onscreen as if g3_draw_bitmap() had been called
g3_get_bitmap_dims(int bitmap,vertex * pnt,float rad,int * x,int * y,int * w,int * h,int * size)169 int g3_get_bitmap_dims(int bitmap, vertex *pnt, float rad, int *x, int *y, int *w, int *h, int *size)
170 {
171 float t;
172 float width, height;
173
174 int bw, bh;
175
176 bm_get_info( bitmap, &bw, &bh, NULL );
177
178 if ( bw < bh ) {
179 width = rad*2.0f;
180 height = width*i2fl(bh)/i2fl(bw);
181 } else if ( bw > bh ) {
182 height = rad*2.0f;
183 width = height*i2fl(bw)/i2fl(bh);
184 } else {
185 width = height = rad*2.0f;
186 }
187
188 Assert( G3_count == 1 );
189
190 if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) {
191 return 1;
192 }
193
194 if (!(pnt->flags&PF_PROJECTED)){
195 g3_project_vertex(pnt);
196 }
197
198 if (pnt->flags & PF_OVERFLOW){
199 return 1;
200 }
201
202 t = (width*Canv_w2)/pnt->world.xyz.z;
203 *w = (int)(t*Matrix_scale.xyz.x);
204
205 t = (height*Canv_h2)/pnt->world.xyz.z;
206 *h = (int)(t*Matrix_scale.xyz.y);
207
208 *x = (int)(pnt->screen.xyw.x - *w/2.0f);
209 *y = (int)(pnt->screen.xyw.y - *h/2.0f);
210
211 *size = MAX(bw, bh);
212
213 return 0;
214 }
215
216 #include "graphics/2d.h"
217
218 //draws a horizon. takes eax=sky_color, edx=ground_color
g3_draw_horizon_line()219 void g3_draw_horizon_line()
220 {
221 int s1, s2;
222 int cpnt;
223 horz_pt horz_pts[4]; // 0 = left, 1 = right
224 vec3d horizon_vec;
225 float up_right, down_right,down_left,up_left;
226
227 Assert( G3_count == 1 );
228
229 //compute horizon_vector
230 horizon_vec.xyz.x = Unscaled_matrix.vec.rvec.xyz.y*Matrix_scale.xyz.y*Matrix_scale.xyz.z;
231 horizon_vec.xyz.y = Unscaled_matrix.vec.uvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.z;
232 horizon_vec.xyz.z = Unscaled_matrix.vec.fvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.y;
233
234 // now compute values & flag for 4 corners.
235 up_right = horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
236 down_right = horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
237 down_left = -horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
238 up_left = -horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
239
240 //check flags for all sky or all ground.
241 if ( (up_right<0.0f)&&(down_right<0.0f)&&(down_left<0.0f)&&(up_left<0.0f) ) {
242 return;
243 }
244
245 if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) ) {
246 return;
247 }
248
249 // check for intesection with each of four edges & compute horizon line
250 cpnt = 0;
251
252 // check intersection with left edge
253 s1 = up_left > 0.0f;
254 s2 = down_left > 0.0f;
255 if ( s1 != s2 ) {
256 horz_pts[cpnt].x = 0.0f;
257 horz_pts[cpnt].y = fl_abs(up_left * Canv_h2 / horizon_vec.xyz.y);
258 horz_pts[cpnt].edge = 0;
259 cpnt++;
260 }
261
262 // check intersection with top edge
263 s1 = up_left > 0.0f;
264 s2 = up_right > 0.0f;
265 if ( s1 != s2 ) {
266 horz_pts[cpnt].x = fl_abs(up_left * Canv_w2 / horizon_vec.xyz.x);
267 horz_pts[cpnt].y = 0.0f;
268 horz_pts[cpnt].edge = 1;
269 cpnt++;
270 }
271
272 // check intersection with right edge
273 s1 = up_right > 0.0f;
274 s2 = down_right > 0.0f;
275 if ( s1 != s2 ) {
276 horz_pts[cpnt].x = i2fl(Canvas_width)-1;
277 horz_pts[cpnt].y = fl_abs(up_right * Canv_h2 / horizon_vec.xyz.y);
278 horz_pts[cpnt].edge = 2;
279 cpnt++;
280 }
281
282 //check intersection with bottom edge
283 s1 = down_right > 0.0f;
284 s2 = down_left > 0.0f;
285 if ( s1 != s2 ) {
286 horz_pts[cpnt].x = fl_abs(down_left * Canv_w2 / horizon_vec.xyz.x);
287 horz_pts[cpnt].y = i2fl(Canvas_height)-1;
288 horz_pts[cpnt].edge = 3;
289 cpnt++;
290 }
291
292 if ( cpnt != 2 ) {
293 mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
294 return;
295 }
296
297 //make sure first edge is left
298 if ( horz_pts[0].x > horz_pts[1].x ) {
299 horz_pt tmp;
300 tmp = horz_pts[0];
301 horz_pts[0] = horz_pts[1];
302 horz_pts[1] = tmp;
303 }
304
305 // draw from left to right.
306 gr_line( fl2i(horz_pts[0].x),fl2i(horz_pts[0].y),fl2i(horz_pts[1].x),fl2i(horz_pts[1].y), GR_RESIZE_NONE );
307 }
308
309 // draw a perspective bitmap based on angles and radius
310 vec3d g3_square[4] = {
311 { { { -1.0f, -1.0f, 20.0f } } },
312 { { { -1.0f, 1.0f, 20.0f } } },
313 { { { 1.0f, 1.0f, 20.0f } } },
314 { { { 1.0f, -1.0f, 20.0f } } }
315 };
316
stars_project_2d_onto_sphere(vec3d * pnt,float rho,float phi,float theta)317 void stars_project_2d_onto_sphere( vec3d *pnt, float rho, float phi, float theta )
318 {
319 float a = PI * phi;
320 float b = PI2 * theta;
321 float sin_a = sinf(a);
322
323 // coords
324 pnt->xyz.z = rho * sin_a * cosf(b);
325 pnt->xyz.y = rho * sin_a * sinf(b);
326 pnt->xyz.x = rho * cosf(a);
327 }
328
g3_draw_htl_line(const vec3d * start,const vec3d * end)329 void g3_draw_htl_line(const vec3d *start, const vec3d *end)
330 {
331 //gr_line_htl(start, end);
332 g3_render_line_3d(true, start, end);
333 }
334
g3_draw_htl_sphere(color * clr,const vec3d * position,float radius)335 void g3_draw_htl_sphere(color *clr, const vec3d* position, float radius)
336 {
337 g3_start_instance_matrix(position, &vmd_identity_matrix, true);
338
339 material material_def;
340
341 material_def.set_blend_mode(ALPHA_BLEND_NONE);
342 material_def.set_depth_mode(ZBUFFER_TYPE_FULL);
343 material_def.set_color(*clr);
344
345 gr_sphere(&material_def, radius);
346
347 g3_done_instance(true);
348 }
349
g3_draw_htl_sphere(const vec3d * position,float radius)350 void g3_draw_htl_sphere(const vec3d* position, float radius)
351 {
352 g3_draw_htl_sphere(&gr_screen.current_color, position, radius);
353 }
354
g3_render_primitives(material * mat,vertex * verts,int n_verts,primitive_type prim_type,bool orthographic)355 void g3_render_primitives(material* mat, vertex* verts, int n_verts, primitive_type prim_type, bool orthographic)
356 {
357 vertex_layout layout;
358
359 if ( orthographic ) {
360 layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), (int)offsetof(vertex, screen));
361 } else {
362 layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vertex), (int)offsetof(vertex, world));
363 }
364
365 if ( orthographic ) {
366 gr_render_primitives_2d_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
367 } else {
368 gr_render_primitives_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
369 }
370 }
371
g3_render_primitives_textured(material * mat,vertex * verts,int n_verts,primitive_type prim_type,bool orthographic)372 void g3_render_primitives_textured(material* mat, vertex* verts, int n_verts, primitive_type prim_type, bool orthographic)
373 {
374 vertex_layout layout;
375
376 if ( orthographic ) {
377 layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), (int)offsetof(vertex, screen));
378 } else {
379 layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vertex), (int)offsetof(vertex, world));
380 }
381
382 layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex), (int)offsetof(vertex, texture_position));
383
384 if ( orthographic ) {
385 gr_render_primitives_2d_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
386 } else {
387 gr_render_primitives_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
388 }
389 }
390
g3_render_primitives_colored(material * mat,vertex * verts,int n_verts,primitive_type prim_type,bool orthographic)391 void g3_render_primitives_colored(material* mat, vertex* verts, int n_verts, primitive_type prim_type, bool orthographic)
392 {
393 vertex_layout layout;
394
395 if ( orthographic ) {
396 layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), (int)offsetof(vertex, screen));
397 } else {
398 layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vertex), (int)offsetof(vertex, world));
399 }
400
401 layout.add_vertex_component(vertex_format_data::COLOR4, sizeof(vertex), (int)offsetof(vertex, r));
402
403 if ( orthographic ) {
404 gr_render_primitives_2d_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
405 } else {
406 gr_render_primitives_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
407 }
408 }
409
g3_render_primitives_colored_textured(material * mat,vertex * verts,int n_verts,primitive_type prim_type,bool orthographic)410 void g3_render_primitives_colored_textured(material* mat, vertex* verts, int n_verts, primitive_type prim_type, bool orthographic)
411 {
412 vertex_layout layout;
413
414 if ( orthographic ) {
415 layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex), (int)offsetof(vertex, screen));
416 } else {
417 layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vertex), (int)offsetof(vertex, world));
418 }
419
420 layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex), (int)offsetof(vertex, texture_position));
421 layout.add_vertex_component(vertex_format_data::COLOR4, sizeof(vertex), (int)offsetof(vertex, r));
422
423 if ( orthographic ) {
424 gr_render_primitives_2d_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
425 } else {
426 gr_render_primitives_immediate(mat, prim_type, &layout, n_verts, verts, n_verts * sizeof(vertex));
427 }
428 }
429
430 // adapted from g3_draw_polygon()
g3_render_rect_oriented_internal(material * material_params,vec3d * pos,matrix * ori,float width,float height)431 void g3_render_rect_oriented_internal(material* material_params, vec3d *pos, matrix *ori, float width, float height)
432 {
433 //idiot-proof
434 if ( width == 0 || height == 0 )
435 return;
436
437 Assert(pos != NULL);
438 Assert(ori != NULL);
439
440 //Let's begin.
441
442 const int NUM_VERTICES = 4;
443 vec3d p[NUM_VERTICES] = { ZERO_VECTOR };
444 vertex v[NUM_VERTICES];
445
446 memset(v, 0, sizeof(v));
447
448 p[0].xyz.x = width;
449 p[0].xyz.y = height;
450
451 p[1].xyz.x = -width;
452 p[1].xyz.y = height;
453
454 p[2].xyz.x = -width;
455 p[2].xyz.y = -height;
456
457 p[3].xyz.x = width;
458 p[3].xyz.y = -height;
459
460 for ( int i = 0; i < NUM_VERTICES; i++ ) {
461 vec3d tmp = vmd_zero_vector;
462
463 //Rotate correctly
464 vm_vec_unrotate(&tmp, &p[i], ori);
465 //Move to point in space
466 vm_vec_add2(&tmp, pos);
467
468 //Convert to vertex
469 g3_transfer_vertex(&v[i], &tmp);
470 }
471
472 v[0].texture_position.u = 1.0f;
473 v[0].texture_position.v = 0.0f;
474
475 v[1].texture_position.u = 0.0f;
476 v[1].texture_position.v = 0.0f;
477
478 v[2].texture_position.u = 0.0f;
479 v[2].texture_position.v = 1.0f;
480
481 v[3].texture_position.u = 1.0f;
482 v[3].texture_position.v = 1.0f;
483
484 g3_render_primitives_textured(material_params, v, 4, PRIM_TYPE_TRIFAN, false);
485 }
486
g3_render_rect_oriented(material * mat_info,vec3d * pos,matrix * ori,float width,float height)487 void g3_render_rect_oriented(material* mat_info, vec3d *pos, matrix *ori, float width, float height)
488 {
489 g3_render_rect_oriented_internal(mat_info, pos, ori, width, height);
490 }
491
g3_render_rect_oriented(material * mat_info,vec3d * pos,vec3d * norm,float width,float height)492 void g3_render_rect_oriented(material* mat_info, vec3d *pos, vec3d *norm, float width, float height)
493 {
494 matrix m;
495 vm_vector_2_matrix(&m, norm, NULL, NULL);
496
497 g3_render_rect_oriented_internal(mat_info, pos, &m, width, height);
498 }
499
500 // adapted g3_draw_rotated_bitmap_3d()
501 //void render_rotated_bitmap(int texture, float alpha, vertex *pnt, float angle, float rad)
g3_render_rect_screen_aligned_rotated(material * mat_params,vertex * pnt,float angle,float rad)502 void g3_render_rect_screen_aligned_rotated(material *mat_params, vertex *pnt, float angle, float rad)
503 {
504 // holdover mistake from retail causes these bitmaps to be rendered 41% bigger than rad
505 // this turns radius into the diagonal distance, but the methods below presume manhattan distance (unadjusted radius)
506 rad *= 1.41421356f;
507
508 angle -= Physics_viewer_bank;
509 if ( angle < 0.0f ) {
510 angle += PI2;
511 } else if ( angle > PI2 ) {
512 angle -= PI2;
513 }
514
515 vec3d PNT(pnt->world);
516 vec3d p[4];
517 vertex P[4];
518 vec3d fvec, rvec, uvec;
519
520 vm_vec_sub(&fvec, &View_position, &PNT);
521 vm_vec_normalize_safe(&fvec);
522
523 vm_rot_point_around_line(&uvec, &View_matrix.vec.uvec, angle, &vmd_zero_vector, &View_matrix.vec.fvec);
524 vm_vec_normalize(&uvec);
525
526 vm_vec_cross(&rvec, &View_matrix.vec.fvec, &uvec);
527 vm_vec_normalize(&rvec);
528
529 vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
530 vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
531
532 vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
533 vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
534 vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
535 vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
536
537 //move all the data from the vecs into the verts
538 g3_transfer_vertex(&P[0], &p[3]);
539 g3_transfer_vertex(&P[1], &p[2]);
540 g3_transfer_vertex(&P[2], &p[1]);
541 g3_transfer_vertex(&P[3], &p[0]);
542
543 //set up the UV coords
544 P[0].texture_position.u = 0.0f; P[0].texture_position.v = 0.0f;
545 P[1].texture_position.u = 1.0f; P[1].texture_position.v = 0.0f;
546 P[2].texture_position.u = 1.0f; P[2].texture_position.v = 1.0f;
547 P[3].texture_position.u = 0.0f; P[3].texture_position.v = 1.0f;
548
549 g3_render_primitives_textured(mat_params, P, 4, PRIM_TYPE_TRIFAN, false);
550 }
551
552 // adapted from gr_opengl_scaler()
g3_render_rect_scaler(material * mat_params,vertex * va,vertex * vb)553 void g3_render_rect_scaler(material *mat_params, vertex *va, vertex *vb)
554 {
555 float x0, y0, x1, y1;
556 float u0, v0, u1, v1;
557 float clipped_x0, clipped_y0, clipped_x1, clipped_y1;
558 float clipped_u0, clipped_v0, clipped_u1, clipped_v1;
559 float xmin, xmax, ymin, ymax;
560 int dx0, dy0, dx1, dy1;
561
562 x0 = va->screen.xyw.x;
563 y0 = va->screen.xyw.y;
564 x1 = vb->screen.xyw.x;
565 y1 = vb->screen.xyw.y;
566
567 xmin = i2fl(gr_screen.clip_left);
568 ymin = i2fl(gr_screen.clip_top);
569 xmax = i2fl(gr_screen.clip_right);
570 ymax = i2fl(gr_screen.clip_bottom);
571
572 u0 = va->texture_position.u; v0 = va->texture_position.v;
573 u1 = vb->texture_position.u; v1 = vb->texture_position.v;
574
575 // Check for obviously offscreen bitmaps...
576 if ( (y1 <= y0) || (x1 <= x0) ) {
577 return;
578 }
579
580 if ( (x1 < xmin) || (x0 > xmax) ) {
581 return;
582 }
583
584 if ( (y1 < ymin) || (y0 > ymax) ) {
585 return;
586 }
587
588 clipped_u0 = u0;
589 clipped_v0 = v0;
590 clipped_u1 = u1;
591 clipped_v1 = v1;
592
593 clipped_x0 = x0;
594 clipped_y0 = y0;
595 clipped_x1 = x1;
596 clipped_y1 = y1;
597
598 // Clip the left, moving u0 right as necessary
599 if ( x0 < xmin ) {
600 clipped_u0 = FIND_SCALED_NUM(xmin, x0, x1, u0, u1);
601 clipped_x0 = xmin;
602 }
603
604 // Clip the right, moving u1 left as necessary
605 if ( x1 > xmax ) {
606 clipped_u1 = FIND_SCALED_NUM(xmax, x0, x1, u0, u1);
607 clipped_x1 = xmax;
608 }
609
610 // Clip the top, moving v0 down as necessary
611 if ( y0 < ymin ) {
612 clipped_v0 = FIND_SCALED_NUM(ymin, y0, y1, v0, v1);
613 clipped_y0 = ymin;
614 }
615
616 // Clip the bottom, moving v1 up as necessary
617 if ( y1 > ymax ) {
618 clipped_v1 = FIND_SCALED_NUM(ymax, y0, y1, v0, v1);
619 clipped_y1 = ymax;
620 }
621
622 dx0 = fl2i(clipped_x0);
623 dx1 = fl2i(clipped_x1);
624 dy0 = fl2i(clipped_y0);
625 dy1 = fl2i(clipped_y1);
626
627 if ( (dx1 <= dx0) || (dy1 <= dy0) ) {
628 return;
629 }
630
631 vertex v[4];
632
633 v[0].screen.xyw.x = clipped_x0;
634 v[0].screen.xyw.y = clipped_y0;
635 v[0].screen.xyw.w = va->screen.xyw.w;
636 v[0].world.xyz.z = va->world.xyz.z;
637 v[0].texture_position.u = clipped_u0;
638 v[0].texture_position.v = clipped_v0;
639
640 v[1].screen.xyw.x = clipped_x1;
641 v[1].screen.xyw.y = clipped_y0;
642 v[1].screen.xyw.w = va->screen.xyw.w;
643 v[1].world.xyz.z = va->world.xyz.z;
644 v[1].texture_position.u = clipped_u1;
645 v[1].texture_position.v = clipped_v0;
646
647 v[2].screen.xyw.x = clipped_x1;
648 v[2].screen.xyw.y = clipped_y1;
649 v[2].screen.xyw.w = va->screen.xyw.w;
650 v[2].world.xyz.z = va->world.xyz.z;
651 v[2].texture_position.u = clipped_u1;
652 v[2].texture_position.v = clipped_v1;
653
654 v[3].screen.xyw.x = clipped_x0;
655 v[3].screen.xyw.y = clipped_y1;
656 v[3].screen.xyw.w = va->screen.xyw.w;
657 v[3].world.xyz.z = va->world.xyz.z;
658 v[3].texture_position.u = clipped_u0;
659 v[3].texture_position.v = clipped_v1;
660
661 g3_render_primitives_textured(mat_params, v, 4, PRIM_TYPE_TRIFAN, true);
662 }
663
664 // adapted from g3_draw_bitmap()
665 //void render_oriented_bitmap_2d(int texture, float alpha, bool blending, vertex *pnt, int orient, float rad)
g3_render_rect_screen_aligned_2d(material * mat_params,vertex * pnt,int orient,float rad)666 void g3_render_rect_screen_aligned_2d(material *mat_params, vertex *pnt, int orient, float rad)
667 {
668 vertex va, vb;
669 float t, w, h;
670 float width, height;
671
672 int bw, bh;
673
674 bm_get_info(mat_params->get_texture_map(TM_BASE_TYPE), &bw, &bh, NULL);
675
676 if ( bw < bh ) {
677 width = rad*2.0f;
678 height = width*i2fl(bh) / i2fl(bw);
679 } else if ( bw > bh ) {
680 height = rad*2.0f;
681 width = height*i2fl(bw) / i2fl(bh);
682 } else {
683 width = height = rad*2.0f;
684 }
685
686 Assert(G3_count == 1);
687
688 if ( pnt->codes & (CC_BEHIND | CC_OFF_USER) )
689 return;
690
691 if ( !(pnt->flags&PF_PROJECTED) )
692 g3_project_vertex(pnt);
693
694 if ( pnt->flags & PF_OVERFLOW )
695 return;
696
697 t = (width * gr_screen.clip_width * 0.5f) / pnt->world.xyz.z;
698 w = t*Matrix_scale.xyz.x;
699
700 t = (height * gr_screen.clip_height * 0.5f) / pnt->world.xyz.z;
701 h = t*Matrix_scale.xyz.y;
702
703 float z, sw;
704 z = pnt->world.xyz.z - rad / 2.0f;
705 if ( z <= 0.0f ) {
706 z = 0.0f;
707 sw = 0.0f;
708 } else {
709 sw = 1.0f / z;
710 }
711
712 va.screen.xyw.x = pnt->screen.xyw.x - w / 2.0f;
713 va.screen.xyw.y = pnt->screen.xyw.y - h / 2.0f;
714 va.screen.xyw.w = sw;
715 va.world.xyz.z = z;
716
717 vb.screen.xyw.x = va.screen.xyw.x + w;
718 vb.screen.xyw.y = va.screen.xyw.y + h;
719 vb.screen.xyw.w = sw;
720 vb.world.xyz.z = z;
721
722 if ( orient & 1 ) {
723 va.texture_position.u = 1.0f;
724 vb.texture_position.u = 0.0f;
725 } else {
726 va.texture_position.u = 0.0f;
727 vb.texture_position.u = 1.0f;
728 }
729
730 if ( orient & 2 ) {
731 va.texture_position.v = 1.0f;
732 vb.texture_position.v = 0.0f;
733 } else {
734 va.texture_position.v = 0.0f;
735 vb.texture_position.v = 1.0f;
736 }
737
738 g3_render_rect_scaler(mat_params, &va, &vb);
739 }
740
741 // adapted from g3_draw_bitmap_3d
g3_render_rect_screen_aligned(material * mat_params,vertex * pnt,int orient,float rad,float depth)742 void g3_render_rect_screen_aligned(material *mat_params, vertex *pnt, int orient, float rad, float depth)
743 {
744 // holdover mistake from retail causes these bitmaps to be rendered 41% bigger than rad
745 // this turns radius into the diagonal distance, but the methods below presume manhattan distance (unadjusted radius)
746 rad *= 1.41421356f;
747
748 vec3d PNT(pnt->world);
749 vec3d p[4];
750 vertex P[4];
751 vec3d fvec, rvec, uvec;
752
753 vm_vec_sub(&fvec, &View_position, &PNT);
754 vm_vec_normalize(&fvec);
755
756 uvec = View_matrix.vec.uvec;
757 vm_vec_normalize(&uvec);
758 rvec = View_matrix.vec.rvec;
759 vm_vec_normalize(&rvec);
760
761 vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
762 vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
763 vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
764
765 vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
766 vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
767 vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
768 vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
769
770 //move all the data from the vecs into the verts
771 g3_transfer_vertex(&P[0], &p[3]);
772 g3_transfer_vertex(&P[1], &p[2]);
773 g3_transfer_vertex(&P[2], &p[1]);
774 g3_transfer_vertex(&P[3], &p[0]);
775
776 // set up the UV coords
777 if ( orient & 1 ) {
778 P[0].texture_position.u = 1.0f;
779 P[1].texture_position.u = 0.0f;
780 P[2].texture_position.u = 0.0f;
781 P[3].texture_position.u = 1.0f;
782 } else {
783 P[0].texture_position.u = 0.0f;
784 P[1].texture_position.u = 1.0f;
785 P[2].texture_position.u = 1.0f;
786 P[3].texture_position.u = 0.0f;
787 }
788
789 if ( orient & 2 ) {
790 P[0].texture_position.v = 1.0f;
791 P[1].texture_position.v = 1.0f;
792 P[2].texture_position.v = 0.0f;
793 P[3].texture_position.v = 0.0f;
794 } else {
795 P[0].texture_position.v = 0.0f;
796 P[1].texture_position.v = 0.0f;
797 P[2].texture_position.v = 1.0f;
798 P[3].texture_position.v = 1.0f;
799 }
800
801 g3_render_primitives_textured(mat_params, P, 4, PRIM_TYPE_TRIFAN, false);
802 }
803
804 // adapted from g3_draw_laser()
805 //void render_laser_2d(int texture, color* clr, float alpha, vec3d *headp, float head_width, vec3d *tailp, float tail_width, float max_len)
g3_render_laser_2d(material * mat_params,vec3d * headp,float head_width,vec3d * tailp,float tail_width,float max_len)806 void g3_render_laser_2d(material *mat_params, vec3d *headp, float head_width, vec3d *tailp, float tail_width, float max_len)
807 {
808 float headx, heady, headr, tailx, taily, tailr;
809 vertex pt1, pt2;
810 float depth;
811
812 Assert(G3_count == 1);
813
814 g3_rotate_vertex(&pt1, headp);
815
816 g3_project_vertex(&pt1);
817 if ( pt1.flags & PF_OVERFLOW )
818 return;
819
820 g3_rotate_vertex(&pt2, tailp);
821
822 g3_project_vertex(&pt2);
823 if ( pt2.flags & PF_OVERFLOW )
824 return;
825
826 if ( (pt1.codes & pt2.codes) != 0 ) {
827 // Both off the same side
828 return;
829 }
830
831 headx = pt1.screen.xyw.x;
832 heady = pt1.screen.xyw.y;
833 headr = (head_width*Matrix_scale.xyz.x*Canv_w2*pt1.screen.xyw.w);
834
835 tailx = pt2.screen.xyw.x;
836 taily = pt2.screen.xyw.y;
837 tailr = (tail_width*Matrix_scale.xyz.x*Canv_w2*pt2.screen.xyw.w);
838
839 float len_2d = fl_sqrt((tailx - headx)*(tailx - headx) + (taily - heady)*(taily - heady));
840
841 // Cap the length if needed.
842 if ( (max_len > 1.0f) && (len_2d > max_len) ) {
843 float ratio = max_len / len_2d;
844
845 tailx = headx + (tailx - headx) * ratio;
846 taily = heady + (taily - heady) * ratio;
847 tailr = headr + (tailr - headr) * ratio;
848
849 len_2d = fl_sqrt((tailx - headx)*(tailx - headx) + (taily - heady)*(taily - heady));
850 }
851
852 depth = (pt1.world.xyz.z + pt2.world.xyz.z)*0.5f;
853
854 float max_r = headr;
855 float a;
856 if ( tailr > max_r )
857 max_r = tailr;
858
859 if ( max_r < 1.0f )
860 max_r = 1.0f;
861
862 float mx, my, w, h1, h2;
863
864 if ( len_2d < max_r ) {
865
866 h1 = headr + (max_r - len_2d);
867 if ( h1 > max_r ) h1 = max_r;
868 h2 = tailr + (max_r - len_2d);
869 if ( h2 > max_r ) h2 = max_r;
870
871 len_2d = max_r;
872 if ( fl_abs(tailx - headx) > 0.01f ) {
873 a = (float)atan2(taily - heady, tailx - headx);
874 } else {
875 a = 0.0f;
876 }
877
878 w = len_2d;
879
880 } else {
881 a = atan2_safe(taily - heady, tailx - headx);
882
883 w = len_2d;
884
885 h1 = headr;
886 h2 = tailr;
887 }
888
889 mx = (tailx + headx) / 2.0f;
890 my = (taily + heady) / 2.0f;
891
892 // Draw box with width 'w' and height 'h' at angle 'a' from horizontal
893 // centered around mx, my
894
895 if ( h1 < 1.0f ) h1 = 1.0f;
896 if ( h2 < 1.0f ) h2 = 1.0f;
897
898 float sa, ca;
899
900 sa = (float)sin(a);
901 ca = (float)cos(a);
902
903 vertex v[4];
904 memset(v, 0, sizeof(vertex) * 4);
905
906 if ( depth < 0.0f ) depth = 0.0f;
907
908 v[0].screen.xyw.x = (-w / 2.0f)*ca + (-h1 / 2.0f)*sa + mx;
909 v[0].screen.xyw.y = (-w / 2.0f)*sa - (-h1 / 2.0f)*ca + my;
910 v[0].world.xyz.z = pt1.world.xyz.z;
911 v[0].screen.xyw.w = pt1.screen.xyw.w;
912 v[0].texture_position.u = 0.0f;
913 v[0].texture_position.v = 0.0f;
914 v[0].b = 191;
915
916 v[1].screen.xyw.x = (w / 2.0f)*ca + (-h2 / 2.0f)*sa + mx;
917 v[1].screen.xyw.y = (w / 2.0f)*sa - (-h2 / 2.0f)*ca + my;
918 v[1].world.xyz.z = pt2.world.xyz.z;
919 v[1].screen.xyw.w = pt2.screen.xyw.w;
920 v[1].texture_position.u = 1.0f;
921 v[1].texture_position.v = 0.0f;
922 v[1].b = 191;
923
924 v[2].screen.xyw.x = (w / 2.0f)*ca + (h2 / 2.0f)*sa + mx;
925 v[2].screen.xyw.y = (w / 2.0f)*sa - (h2 / 2.0f)*ca + my;
926 v[2].world.xyz.z = pt2.world.xyz.z;
927 v[2].screen.xyw.w = pt2.screen.xyw.w;
928 v[2].texture_position.u = 1.0f;
929 v[2].texture_position.v = 1.0f;
930 v[2].b = 191;
931
932 v[3].screen.xyw.x = (-w / 2.0f)*ca + (h1 / 2.0f)*sa + mx;
933 v[3].screen.xyw.y = (-w / 2.0f)*sa - (h1 / 2.0f)*ca + my;
934 v[3].world.xyz.z = pt1.world.xyz.z;
935 v[3].screen.xyw.w = pt1.screen.xyw.w;
936 v[3].texture_position.u = 0.0f;
937 v[3].texture_position.v = 1.0f;
938 v[3].b = 191;
939
940 g3_render_primitives_textured(mat_params, v, 4, PRIM_TYPE_TRIFAN, true);
941 }
942
943 // adapted from g3_draw_rod()
g3_render_rod(color * clr,int num_points,vec3d * pvecs,float width)944 void g3_render_rod(color *clr, int num_points, vec3d *pvecs, float width)
945 {
946 const int MAX_ROD_VERTS = 100;
947 vec3d uvec, fvec, rvec;
948 vec3d vecs[2];
949 vertex pts[MAX_ROD_VERTS];
950 int i, nv = 0;
951
952 Assert(num_points >= 2);
953 Assert((num_points * 2) <= MAX_ROD_VERTS);
954
955 for ( i = 0; i < num_points; i++ ) {
956 vm_vec_sub(&fvec, &View_position, &pvecs[i]);
957 vm_vec_normalize_safe(&fvec);
958
959 int first = i + 1;
960 int second = i - 1;
961
962 if ( i == 0 ) {
963 first = 1;
964 second = 0;
965 } else if ( i == num_points - 1 ) {
966 first = i;
967 }
968
969 vm_vec_sub(&rvec, &pvecs[first], &pvecs[second]);
970 vm_vec_normalize_safe(&rvec);
971
972 vm_vec_cross(&uvec, &rvec, &fvec);
973
974 vm_vec_scale_add(&vecs[0], &pvecs[i], &uvec, width * 0.5f);
975 vm_vec_scale_add(&vecs[1], &pvecs[i], &uvec, -width * 0.5f);
976
977 if ( nv > MAX_ROD_VERTS - 2 ) {
978 Warning(LOCATION, "Hit high-water mark (%i) in g3_draw_rod()!!\n", MAX_ROD_VERTS);
979 break;
980 }
981
982 g3_transfer_vertex(&pts[nv], &vecs[0]);
983 g3_transfer_vertex(&pts[nv + 1], &vecs[1]);
984
985 pts[nv].texture_position.u = 1.0f;
986 pts[nv].texture_position.v = i2fl(i);
987 pts[nv].r = clr->red;
988 pts[nv].g = clr->green;
989 pts[nv].b = clr->blue;
990 pts[nv].a = clr->alpha;
991
992 pts[nv + 1].texture_position.u = 0.0f;
993 pts[nv + 1].texture_position.v = i2fl(i);
994 pts[nv + 1].r = clr->red;
995 pts[nv + 1].g = clr->green;
996 pts[nv + 1].b = clr->blue;
997 pts[nv + 1].a = clr->alpha;
998
999 nv += 2;
1000 }
1001
1002 // we should always have at least 4 verts, and there should always be an even number
1003 Assert((nv >= 4) && !(nv % 2));
1004
1005 material material_params;
1006
1007 material_params.set_depth_mode(ZBUFFER_TYPE_READ);
1008 material_params.set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
1009
1010 g3_render_primitives_colored(&material_params, pts, nv, PRIM_TYPE_TRISTRIP, false);
1011 }
1012
1013 // adapted from g3_draw_2d_shield_icon()
g3_render_shield_icon(color * clr,coord2d coords[6],int resize_mode)1014 void g3_render_shield_icon(color *clr, coord2d coords[6], int resize_mode)
1015 {
1016 GR_DEBUG_SCOPE("Render shield icon");
1017
1018 vertex v[6];
1019
1020 memset(v, 0, sizeof(vertex) * 6);
1021
1022 if ( resize_mode != GR_RESIZE_NONE ) {
1023 gr_resize_screen_pos(&coords[0].x, &coords[0].y, NULL, NULL, resize_mode);
1024 gr_resize_screen_pos(&coords[1].x, &coords[1].y, NULL, NULL, resize_mode);
1025 gr_resize_screen_pos(&coords[2].x, &coords[2].y, NULL, NULL, resize_mode);
1026 gr_resize_screen_pos(&coords[3].x, &coords[3].y, NULL, NULL, resize_mode);
1027 gr_resize_screen_pos(&coords[4].x, &coords[4].y, NULL, NULL, resize_mode);
1028 gr_resize_screen_pos(&coords[5].x, &coords[5].y, NULL, NULL, resize_mode);
1029 }
1030
1031 float sw = 0.1f;
1032
1033 // stuff coords
1034 v[0].screen.xyw.x = i2fl(coords[0].x);
1035 v[0].screen.xyw.y = i2fl(coords[0].y);
1036 v[0].screen.xyw.w = sw;
1037 v[0].texture_position.u = 0.0f;
1038 v[0].texture_position.v = 0.0f;
1039 v[0].flags = PF_PROJECTED;
1040 v[0].codes = 0;
1041 v[0].r = (ubyte)clr->red;
1042 v[0].g = (ubyte)clr->green;
1043 v[0].b = (ubyte)clr->blue;
1044 v[0].a = 0;
1045
1046 v[1].screen.xyw.x = i2fl(coords[1].x);
1047 v[1].screen.xyw.y = i2fl(coords[1].y);
1048 v[1].screen.xyw.w = sw;
1049 v[1].texture_position.u = 0.0f;
1050 v[1].texture_position.v = 0.0f;
1051 v[1].flags = PF_PROJECTED;
1052 v[1].codes = 0;
1053 v[1].r = (ubyte)clr->red;
1054 v[1].g = (ubyte)clr->green;
1055 v[1].b = (ubyte)clr->blue;
1056 v[1].a = (ubyte)clr->alpha;
1057
1058 v[2].screen.xyw.x = i2fl(coords[2].x);
1059 v[2].screen.xyw.y = i2fl(coords[2].y);
1060 v[2].screen.xyw.w = sw;
1061 v[2].texture_position.u = 0.0f;
1062 v[2].texture_position.v = 0.0f;
1063 v[2].flags = PF_PROJECTED;
1064 v[2].codes = 0;
1065 v[2].r = (ubyte)clr->red;
1066 v[2].g = (ubyte)clr->green;
1067 v[2].b = (ubyte)clr->blue;
1068 v[2].a = 0;
1069
1070 v[3].screen.xyw.x = i2fl(coords[3].x);
1071 v[3].screen.xyw.y = i2fl(coords[3].y);
1072 v[3].screen.xyw.w = sw;
1073 v[3].texture_position.u = 0.0f;
1074 v[3].texture_position.v = 0.0f;
1075 v[3].flags = PF_PROJECTED;
1076 v[3].codes = 0;
1077 v[3].r = (ubyte)clr->red;
1078 v[3].g = (ubyte)clr->green;
1079 v[3].b = (ubyte)clr->blue;
1080 v[3].a = (ubyte)clr->alpha;
1081
1082 v[4].screen.xyw.x = i2fl(coords[4].x);
1083 v[4].screen.xyw.y = i2fl(coords[4].y);
1084 v[4].screen.xyw.w = sw;
1085 v[4].texture_position.u = 0.0f;
1086 v[4].texture_position.v = 0.0f;
1087 v[4].flags = PF_PROJECTED;
1088 v[4].codes = 0;
1089 v[4].r = (ubyte)clr->red;
1090 v[4].g = (ubyte)clr->green;
1091 v[4].b = (ubyte)clr->blue;
1092 v[4].a = 0;
1093
1094 v[5].screen.xyw.x = i2fl(coords[5].x);
1095 v[5].screen.xyw.y = i2fl(coords[5].y);
1096 v[5].screen.xyw.w = sw;
1097 v[5].texture_position.u = 0.0f;
1098 v[5].texture_position.v = 0.0f;
1099 v[5].flags = PF_PROJECTED;
1100 v[5].codes = 0;
1101 v[5].r = (ubyte)clr->red;
1102 v[5].g = (ubyte)clr->green;
1103 v[5].b = (ubyte)clr->blue;
1104 v[5].a = 0;
1105
1106 material material_instance;
1107 material_instance.set_depth_mode(ZBUFFER_TYPE_NONE);
1108 material_instance.set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
1109 material_instance.set_cull_mode(false);
1110 material_instance.set_color(1.0f, 1.0f, 1.0f, 1.0f);
1111
1112 // draw the polys
1113 g3_render_primitives_colored(&material_instance, v, 6, PRIM_TYPE_TRISTRIP, true);
1114 }
1115
g3_render_shield_icon(coord2d coords[6],int resize_mode)1116 void g3_render_shield_icon(coord2d coords[6], int resize_mode)
1117 {
1118 g3_render_shield_icon(&gr_screen.current_color, coords, resize_mode);
1119 }
1120
1121 // adapted from gr_opengl_line_htl()
g3_render_line_3d(color * clr,bool depth_testing,const vec3d * start,const vec3d * end)1122 void g3_render_line_3d(color *clr, bool depth_testing, const vec3d *start, const vec3d *end)
1123 {
1124 material mat;
1125
1126 mat.set_depth_mode((depth_testing) ? ZBUFFER_TYPE_READ : ZBUFFER_TYPE_NONE);
1127 mat.set_color(*clr);
1128 mat.set_cull_mode(false);
1129
1130 if ( clr->is_alphacolor ) {
1131 mat.set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
1132 } else {
1133 mat.set_blend_mode(ALPHA_BLEND_NONE);
1134 }
1135
1136 float line[6] = {
1137 start->xyz.x, start->xyz.y, start->xyz.z,
1138 end->xyz.x, end->xyz.y, end->xyz.z
1139 };
1140
1141 vertex_layout vert_def;
1142
1143 vert_def.add_vertex_component(vertex_format_data::POSITION3, sizeof(float) * 3, 0);
1144
1145 gr_render_primitives_immediate(&mat, PRIM_TYPE_LINES, &vert_def, 2, line, sizeof(float) * 6);
1146 }
1147
g3_render_line_3d(bool depth_testing,const vec3d * start,const vec3d * end)1148 void g3_render_line_3d(bool depth_testing, const vec3d *start, const vec3d *end)
1149 {
1150 g3_render_line_3d(&gr_screen.current_color, depth_testing, start, end);
1151 }
1152
g3_render_sphere(color * clr,vec3d * position,float radius)1153 void g3_render_sphere(color *clr, vec3d* position, float radius)
1154 {
1155 g3_start_instance_matrix(position, &vmd_identity_matrix, true);
1156
1157 vec3d scale = {{{ radius, radius, radius }}};
1158 gr_push_scale_matrix(&scale);
1159
1160 material material_def;
1161
1162 material_def.set_blend_mode(ALPHA_BLEND_NONE);
1163 material_def.set_depth_mode(ZBUFFER_TYPE_FULL);
1164 material_def.set_color(*clr);
1165
1166 gr_sphere(&material_def, radius);
1167
1168 gr_pop_scale_matrix();
1169 g3_done_instance(true);
1170 }
1171
g3_render_sphere(vec3d * position,float radius)1172 void g3_render_sphere(vec3d* position, float radius)
1173 {
1174 g3_render_sphere(&gr_screen.current_color, position, radius);
1175 }
1176
1177 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
1178 //flash ball stuff
1179
initialize(int number,float min_ray_width,float max_ray_width,const vec3d * dir,const vec3d * pcenter,float outer,float inner,ubyte max_r,ubyte max_g,ubyte max_b,ubyte min_r,ubyte min_g,ubyte min_b)1180 void flash_ball::initialize(int number, float min_ray_width, float max_ray_width, const vec3d* dir, const vec3d* pcenter, float outer, float inner, ubyte max_r, ubyte max_g, ubyte max_b, ubyte min_r, ubyte min_g, ubyte min_b)
1181 {
1182 if(number < 1)
1183 return;
1184
1185 center = *pcenter;
1186
1187 if(n_rays < number){
1188 if(ray)vm_free(ray);
1189 ray = (flash_beam*)vm_malloc(sizeof(flash_beam)*number);
1190 n_rays = number;
1191 }
1192
1193 int i;
1194 for(i = 0; i<n_rays; i++){
1195 //colors
1196 if(min_r != 255){
1197 ray[i].start.r = (ubyte)Random::next(min_r, max_r);
1198 }else{
1199 ray[i].start.r = 255;
1200 }
1201 if(min_g != 255){
1202 ray[i].start.g = (ubyte)Random::next(min_g, max_g);
1203 }else{
1204 ray[i].start.g = 255;
1205 }
1206 if(min_b != 255){
1207 ray[i].start.b = (ubyte)Random::next(min_b, max_b);
1208 }else{
1209 ray[i].start.b = 255;
1210 }
1211
1212 //rays
1213 if(dir == &vmd_zero_vector || outer >= PI2){
1214 //random sphere
1215 vec3d start, end;
1216
1217 vm_vec_rand_vec_quick(&start);
1218 vm_vec_rand_vec_quick(&end);
1219
1220 ray[i].start.world = start;
1221 ray[i].end.world = end;
1222 }else{
1223 //random cones
1224 vec3d start, end;
1225
1226 vm_vec_random_cone(&start, dir, inner, outer);
1227 vm_vec_random_cone(&end, dir, inner, outer);
1228
1229 ray[i].start.world = start;
1230 ray[i].end.world = end;
1231 }
1232 if(max_ray_width == 0.0f)ray[i].width=min_ray_width;
1233 else ray[i].width = frand_range(min_ray_width, max_ray_width);
1234 }
1235
1236
1237 }
1238
1239 #define uw(p) (*((uint *) (p)))
1240 #define w(p) (*((int *) (p)))
1241 #define wp(p) ((int *) (p))
1242 #define vp(p) ((vec3d *) (p))
1243 #define fl(p) (*((float *) (p)))
1244
defpoint(int off,ubyte * bsp_data)1245 void flash_ball::defpoint(int off, ubyte *bsp_data)
1246 {
1247 int n;
1248 int nverts = w(off+bsp_data+8);
1249 int offset = w(off+bsp_data+16);
1250 ubyte * normcount = off+bsp_data+20;
1251 vec3d *src = vp(off+bsp_data+offset);
1252
1253 if(n_rays < nverts){
1254 if(ray)vm_free(ray);
1255 ray = (flash_beam*)vm_malloc(sizeof(flash_beam)*nverts);
1256 n_rays = nverts;
1257 }
1258
1259 {
1260 vec3d temp;
1261 for (n=0; n<nverts; n++ ) {
1262
1263 temp = *src;
1264 vm_vec_sub2(&temp, ¢er);
1265 vm_vec_normalize(&temp);
1266 ray[n].start.world = temp;
1267
1268 src++; // move to normal
1269
1270 src+=normcount[n];
1271 }
1272 }
1273 }
1274
1275 #define OP_EOF 0
1276 #define OP_DEFPOINTS 1
1277 #define OP_FLATPOLY 2
1278 #define OP_TMAPPOLY 3
1279 #define OP_SORTNORM 4
1280 #define OP_BOUNDBOX 5
1281
1282
parse_bsp(int offset,ubyte * bsp_data)1283 void flash_ball::parse_bsp(int offset, ubyte *bsp_data){
1284 int ID, SIZE;
1285
1286 memcpy(&ID, &bsp_data[offset], sizeof(int));
1287 memcpy(&SIZE, &bsp_data[offset+sizeof(int)], sizeof(int));
1288
1289 while(ID!=0){
1290 switch(ID){
1291 case OP_EOF:
1292 return;
1293 break;
1294 case OP_DEFPOINTS: defpoint(offset, bsp_data);
1295 break;
1296 case OP_SORTNORM:
1297 break;
1298 case OP_FLATPOLY:
1299 break;
1300 case OP_TMAPPOLY:
1301 break;
1302 case OP_BOUNDBOX:
1303 break;
1304 default:
1305 return;
1306 }
1307 offset += SIZE;
1308 memcpy(&ID, &bsp_data[offset], sizeof(int));
1309 memcpy(&SIZE, &bsp_data[offset+sizeof(int)], sizeof(int));
1310
1311 if(SIZE < 1)ID=OP_EOF;
1312 }
1313 }
1314
1315
initialize(ubyte * bsp_data,float min_ray_width,float max_ray_width,const vec3d * dir,const vec3d * pcenter,float outer,float inner,ubyte max_r,ubyte max_g,ubyte max_b,ubyte min_r,ubyte min_g,ubyte min_b)1316 void flash_ball::initialize(ubyte *bsp_data, float min_ray_width, float max_ray_width, const vec3d* dir, const vec3d* pcenter, float outer, float inner, ubyte max_r, ubyte max_g, ubyte max_b, ubyte min_r, ubyte min_g, ubyte min_b)
1317 {
1318 center = *pcenter;
1319 vm_vec_negate(¢er);
1320 parse_bsp(0,bsp_data);
1321 center = vmd_zero_vector;
1322
1323 int i;
1324 for(i = 0; i<n_rays; i++){
1325 //colors
1326 if(min_r != 255){
1327 ray[i].start.r = (ubyte)Random::next(min_r, max_r);
1328 }else{
1329 ray[i].start.r = 255;
1330 }
1331 if(min_g != 255){
1332 ray[i].start.g = (ubyte)Random::next(min_g, max_g);
1333 }else{
1334 ray[i].start.g = 255;
1335 }
1336 if(min_b != 255){
1337 ray[i].start.b = (ubyte)Random::next(min_b, max_b);
1338 }else{
1339 ray[i].start.b = 255;
1340 }
1341
1342 //rays
1343 if(dir == &vmd_zero_vector || outer >= PI2){
1344 //random sphere
1345 vec3d end;
1346
1347 vm_vec_rand_vec_quick(&end);
1348
1349 ray[i].end.world = end;
1350 }else{
1351 //random cones
1352 vec3d end;
1353
1354 vm_vec_random_cone(&end, dir, inner, outer);
1355
1356 ray[i].end.world = end;
1357 }
1358 if(max_ray_width == 0.0f)ray[i].width=min_ray_width;
1359 else ray[i].width = frand_range(min_ray_width, max_ray_width);
1360 }
1361 }
1362
1363 //rad how wide the ball should be
1364 //intinsity how visable it should be
1365 //life how far along from start to end should it be
render(int texture,float rad,float intinsity,float life)1366 void flash_ball::render(int texture, float rad, float intinsity, float life){
1367 for(int i = 0; i < n_rays; i++){
1368 vec3d end;
1369 vm_vec_interp_constant(&end, &ray[i].start.world, &ray[i].end.world, life);
1370 vm_vec_scale(&end, rad);
1371 vm_vec_add2(&end, ¢er);
1372
1373 batching_add_beam(texture, ¢er, &end, ray[i].width*rad, intinsity);
1374 }
1375 }
1376