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, &center);
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(&center);
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, &center);
1372 
1373 		batching_add_beam(texture, &center, &end, ray[i].width*rad, intinsity);
1374 	}
1375 }
1376