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 "render/3dinternal.h"
13 #include "graphics/tmapper.h"
14 #include "physics/physics.h"		// For Physics_viewer_bank for g3_draw_rotated_bitmap
15 #include "bmpman/bmpman.h"
16 #include "globalincs/alphacolors.h"
17 #include "cmdline/cmdline.h"
18 #include "graphics/grbatch.h"
19 #include "io/key.h"
20 
21 
22 //vertex buffers for polygon drawing and clipping
23 static vertex **Vbuf0 = NULL;
24 static vertex **Vbuf1 = NULL;
25 static int Num_vbufs_allocated = 0;
26 
27 
g3_deallocate_vbufs()28 static void g3_deallocate_vbufs()
29 {
30 	if (Vbuf0 != NULL) {
31 		vm_free(Vbuf0);
32 		Vbuf0 = NULL;
33 	}
34 
35 	if (Vbuf1 != NULL) {
36 		vm_free(Vbuf1);
37 		Vbuf1 = NULL;
38 	}
39 }
40 
g3_allocate_vbufs(int nv)41 static void g3_allocate_vbufs(int nv)
42 {
43 	static ubyte dealloc = 0;
44 
45 	Assert( nv >= 0 );
46 	Assert( nv || Num_vbufs_allocated );
47 
48 	if (!dealloc) {
49 		atexit(g3_deallocate_vbufs);
50 		dealloc = 1;
51 	}
52 
53 	if (nv > Num_vbufs_allocated) {
54 		g3_deallocate_vbufs();
55 
56 		Vbuf0 = (vertex**) vm_malloc( nv * sizeof(vertex) );
57 		Vbuf1 = (vertex**) vm_malloc( nv * sizeof(vertex) );
58 
59 		Num_vbufs_allocated = nv;
60 	}
61 
62 	// make sure everything is valid
63 	Verify( Vbuf0 != NULL );
64 	Verify( Vbuf1 != NULL );
65 }
66 
67 
68 /**
69  * Deal with a clipped line
70  */
must_clip_line(vertex * p0,vertex * p1,ubyte codes_or,uint flags)71 int must_clip_line(vertex *p0,vertex *p1,ubyte codes_or, uint flags)
72 {
73 	int ret = 0;
74 
75 	clip_line(&p0,&p1,codes_or, flags);
76 
77 	if (p0->codes & p1->codes) goto free_points;
78 
79 	codes_or = (unsigned char)(p0->codes | p1->codes);
80 
81 	if (codes_or & CC_BEHIND) goto free_points;
82 
83 	if (!(p0->flags&PF_PROJECTED))
84 		g3_project_vertex(p0);
85 
86 	if (p0->flags&PF_OVERFLOW) goto free_points;
87 
88 	if (!(p1->flags&PF_PROJECTED))
89 		g3_project_vertex(p1);
90 
91 	if (p1->flags&PF_OVERFLOW) goto free_points;
92 
93 	gr_aaline( p0, p1 );
94 
95 	ret = 1;
96 
97 	//frees temp points
98 free_points:
99 
100 	if (p0->flags & PF_TEMP_POINT)
101 		free_temp_point(p0);
102 
103 	if (p1->flags & PF_TEMP_POINT)
104 		free_temp_point(p1);
105 
106 	return ret;
107 }
108 
109 /**
110  * Draws a line. takes two points.  returns true if drew
111  */
g3_draw_line(vertex * p0,vertex * p1)112 int g3_draw_line(vertex *p0,vertex *p1)
113 {
114 #ifdef FRED_OGL_COMMENT_OUT_FOR_NOW
115 	if(Fred_running && !Cmdline_nohtl)
116 	{
117   		gr_aaline( p0, p1 );
118 		return 0;
119 	}
120 #endif
121 
122 	ubyte codes_or;
123 
124 	Assert( G3_count == 1 );
125 
126 	if (p0->codes & p1->codes)
127 		return 0;
128 
129 	codes_or = (unsigned char)(p0->codes | p1->codes);
130 
131 	if (codes_or & CC_BEHIND)
132 		return must_clip_line(p0,p1,codes_or,0);
133 
134 	if (!(p0->flags&PF_PROJECTED))
135 		g3_project_vertex(p0);
136 
137 	if (p0->flags&PF_OVERFLOW)
138 		return must_clip_line(p0,p1,codes_or,0);
139 
140 
141 	if (!(p1->flags&PF_PROJECTED))
142 		g3_project_vertex(p1);
143 
144 	if (p1->flags&PF_OVERFLOW)
145 		return must_clip_line(p0,p1,codes_or,0);
146 
147   	gr_aaline( p0, p1 );
148 
149 	return 0;
150 }
151 
152 
153 //returns true if a plane is facing the viewer. takes the unrotated surface
154 //normal of the plane, and a point on it.  The normal need not be normalized
g3_check_normal_facing(vec3d * v,vec3d * norm)155 int g3_check_normal_facing(vec3d *v,vec3d *norm)
156 {
157 	vec3d tempv;
158 
159 	Assert( G3_count == 1 );
160 
161 	vm_vec_sub(&tempv,&View_position,v);
162 
163 	return (vm_vec_dot(&tempv,norm) > 0.0f);
164 }
165 
do_facing_check(vec3d * norm,vertex ** vertlist,vec3d * p)166 int do_facing_check(vec3d *norm,vertex **vertlist,vec3d *p)
167 {
168 	Assert( G3_count == 1 );
169 
170 	if (norm) {		//have normal
171 
172 		Assert(norm->xyz.x || norm->xyz.y || norm->xyz.z);
173 
174 		return g3_check_normal_facing(p,norm);
175 	}
176 	else {	//normal not specified, so must compute
177 
178 		vec3d tempv;
179 
180 		//get three points (rotated) and compute normal
181 
182 		vm_vec_perp(&tempv,&vertlist[0]->world,&vertlist[1]->world,&vertlist[2]->world);
183 
184 		return (vm_vec_dot(&tempv,&vertlist[1]->world ) < 0.0);
185 	}
186 }
187 
188 //like g3_draw_poly(), but checks to see if facing.  If surface normal is
189 //NULL, this routine must compute it, which will be slow.  It is better to
190 //pre-compute the normal, and pass it to this function.  When the normal
191 //is passed, this function works like g3_check_normal_facing() plus
192 //g3_draw_poly().
193 //returns -1 if not facing, 1 if off screen, 0 if drew
g3_draw_poly_if_facing(int nv,vertex ** pointlist,uint tmap_flags,vec3d * norm,vec3d * pnt)194 int g3_draw_poly_if_facing(int nv,vertex **pointlist,uint tmap_flags,vec3d *norm,vec3d *pnt)
195 {
196 	Assert( G3_count == 1 );
197 
198 	if (do_facing_check(norm,pointlist,pnt))
199 		return g3_draw_poly(nv,pointlist,tmap_flags);
200 	else
201 		return 255;
202 }
203 
204 //draw a polygon.
205 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
206 //returns 1 if off screen, 0 if drew
g3_draw_poly(int nv,vertex ** pointlist,uint tmap_flags)207 int g3_draw_poly(int nv,vertex **pointlist,uint tmap_flags)
208 {
209 	int i;
210 	vertex **bufptr;
211 	ccodes cc;
212 
213 	Assert( G3_count == 1 );
214 
215 	if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
216 		gr_tmapper( nv, pointlist, tmap_flags );
217 		return 0;
218 	}
219 	//don't clip in HT&L mode, the card does it for us
220 	if(!Cmdline_nohtl && (tmap_flags & TMAP_FLAG_TRISTRIP)) {
221 		gr_tmapper( nv, pointlist, tmap_flags );
222 		return 0;
223 	}
224 	if(Cmdline_nohtl && (tmap_flags & TMAP_FLAG_TRISTRIP)){
225 		bool starting = true;
226 		int offset = 0;
227 		for (i=0;i<nv;i++){
228 			if (!(pointlist[i]->flags&PF_PROJECTED))g3_project_vertex(pointlist[i]);
229 			if (pointlist[i]->flags&PF_OVERFLOW){
230 				if(starting)
231 					offset++;
232 				nv--;
233 			}else
234 				starting = false;
235 			if(nv<3)return 1;
236 		}
237 		if(nv<3)return 1;
238 		pointlist += offset;
239 		gr_tmapper( nv, pointlist, tmap_flags );
240 		return 0;
241 	}
242 
243 	g3_allocate_vbufs(nv);
244 
245 	cc.cc_or = 0;
246 	cc.cc_and = 0xff;
247 
248 	bufptr = Vbuf0;
249 
250 	for (i=0;i<nv;i++) {
251 		vertex *p;
252 
253 		p = bufptr[i] = pointlist[i];
254 
255 		cc.cc_and &= p->codes;
256 		cc.cc_or  |= p->codes;
257 	}
258 
259 	if (cc.cc_and)
260 		return 1;	//all points off screen
261 
262 	if (cc.cc_or)	{
263 		Assert( G3_count == 1 );
264 
265 		bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tmap_flags);
266 
267 		if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
268 
269 			for (i=0;i<nv;i++) {
270 				vertex *p = bufptr[i];
271 
272 				if (!(p->flags&PF_PROJECTED))
273 					g3_project_vertex(p);
274 
275 				if (p->flags&PF_OVERFLOW) {
276 					goto free_points;
277 				}
278 			}
279 
280 			gr_tmapper( nv, bufptr, tmap_flags );
281 		}
282 
283 free_points:
284 		;
285 
286 		for (i=0;i<nv;i++)
287 			if (bufptr[i]->flags & PF_TEMP_POINT)
288 				free_temp_point(bufptr[i]);
289 
290 	} else {
291 		//now make list of 2d coords (& check for overflow)
292 
293 		for (i=0;i<nv;i++) {
294 			vertex *p = bufptr[i];
295 
296 			if (!(p->flags&PF_PROJECTED))
297 				g3_project_vertex(p);
298 
299 			if (p->flags&PF_OVERFLOW) {
300 				return 255;
301 			}
302 
303 		}
304 
305 		gr_tmapper( nv, bufptr, tmap_flags );
306 	}
307 	return 0;	//say it drew
308 }
309 
g3_draw_polygon(vec3d * pos,matrix * ori,float width,float height,int tmap_flags)310 int g3_draw_polygon(vec3d *pos, matrix *ori, float width, float height, int tmap_flags)
311 {
312 	//idiot-proof
313 	if(width == 0 || height == 0)
314 			return 0;
315 
316 	Assert(pos != NULL);
317 	Assert(ori != NULL);
318 
319 	//Let's begin.
320 
321 	const int NUM_VERTICES = 4;
322 	vec3d p[NUM_VERTICES] = { ZERO_VECTOR };
323 	vertex v[NUM_VERTICES];
324 
325 	p[0].xyz.x = width;
326 	p[0].xyz.y = height;
327 
328 	p[1].xyz.x = -width;
329 	p[1].xyz.y = height;
330 
331 	p[2].xyz.x = -width;
332 	p[2].xyz.y = -height;
333 
334 	p[3].xyz.x = width;
335 	p[3].xyz.y = -height;
336 
337 	for(int i = 0; i < NUM_VERTICES; i++)
338 	{
339 		vec3d tmp = vmd_zero_vector;
340 
341 		//Rotate correctly
342 		vm_vec_unrotate(&tmp, &p[i], ori);
343 		//Move to point in space
344 		vm_vec_add2(&tmp, pos);
345 
346 		//Convert to vertex
347 		g3_transfer_vertex(&v[i], &tmp);
348 	}
349 
350 	v[0].texture_position.u = 1.0f;
351 	v[0].texture_position.v = 0.0f;
352 
353 	v[1].texture_position.u = 0.0f;
354 	v[1].texture_position.v = 0.0f;
355 
356 	v[2].texture_position.u = 0.0f;
357 	v[2].texture_position.v = 1.0f;
358 
359 	v[3].texture_position.u = 1.0f;
360 	v[3].texture_position.v = 1.0f;
361 
362 	gr_render(NUM_VERTICES, v, tmap_flags);
363 
364 	return 0;
365 }
366 
g3_draw_polygon(vec3d * pos,vec3d * norm,float width,float height,int tmap_flags)367 int g3_draw_polygon(vec3d *pos, vec3d *norm, float width, float height, int tmap_flags)
368 {
369 	matrix m;
370 	vm_vector_2_matrix(&m, norm, NULL, NULL);
371 
372 	return g3_draw_polygon(pos, &m, width, height, tmap_flags);
373 }
374 
375 // Draw a polygon.  Same as g3_draw_poly, but it bashes sw to a constant value
376 // for all vertexes.  Needs to be done after clipping to get them all.
377 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
378 //returns 1 if off screen, 0 if drew
g3_draw_poly_constant_sw(int nv,vertex ** pointlist,uint tmap_flags,float constant_sw)379 int g3_draw_poly_constant_sw(int nv,vertex **pointlist,uint tmap_flags, float constant_sw)
380 {
381 	int i;
382 	vertex **bufptr;
383 	ccodes cc;
384 
385 	Assert( G3_count == 1 );
386 
387 	if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
388 		gr_tmapper( nv, pointlist, tmap_flags );
389 		return 0;
390 	}
391 	if(tmap_flags & TMAP_FLAG_TRISTRIP || tmap_flags & TMAP_FLAG_TRILIST){
392 		for (i=0;i<nv;i++){
393 			if (!(pointlist[i]->flags&PF_PROJECTED))g3_project_vertex(pointlist[i]);
394 		}
395 		gr_tmapper( nv, pointlist, tmap_flags );
396 		return 0;
397 	}
398 
399 	g3_allocate_vbufs(nv);
400 
401 	cc.cc_or = 0; cc.cc_and = 0xff;
402 
403 	bufptr = Vbuf0;
404 
405 	for (i=0;i<nv;i++) {
406 		vertex *p;
407 
408 		p = bufptr[i] = pointlist[i];
409 
410 		cc.cc_and &= p->codes;
411 		cc.cc_or  |= p->codes;
412 	}
413 
414 	if (cc.cc_and)
415 		return 1;	//all points off screen
416 
417 
418 	if (cc.cc_or)	{
419 		Assert( G3_count == 1 );
420 
421 		bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
422 
423 		if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
424 
425 			for (i=0;i<nv;i++) {
426 				vertex *p = bufptr[i];
427 
428 				if (!(p->flags&PF_PROJECTED))
429 					g3_project_vertex(p);
430 
431 				if (p->flags&PF_OVERFLOW) {
432 					goto free_points;
433 				}
434 
435 				p->screen.xyw.w = constant_sw;
436 			}
437 
438 			gr_tmapper( nv, bufptr, tmap_flags );
439 		}
440 
441 free_points:
442 		;
443 
444 		for (i=0;i<nv;i++){
445 			if (bufptr[i]->flags & PF_TEMP_POINT){
446 				free_temp_point(bufptr[i]);
447 			}
448 		}
449 	} else {
450 		//now make list of 2d coords (& check for overflow)
451 
452 		for (i=0;i<nv;i++) {
453 			vertex *p = bufptr[i];
454 
455 			if (!(p->flags&PF_PROJECTED))
456 				g3_project_vertex(p);
457 
458 			if (p->flags&PF_OVERFLOW) {
459 				return 255;
460 			}
461 
462 			p->screen.xyw.w = constant_sw;
463 
464 		}
465 
466 		gr_tmapper( nv, bufptr, tmap_flags );
467 	}
468 	return 0;	//say it drew
469 }
470 
471 //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
472 //radius, but not to the distance from the eye
g3_draw_sphere(vertex * pnt,float rad)473 int g3_draw_sphere(vertex *pnt,float rad)
474 {
475 	Assert( G3_count == 1 );
476 
477 	if (! (pnt->codes & CC_BEHIND)) {
478 
479 		if (! (pnt->flags & PF_PROJECTED))
480 			g3_project_vertex(pnt);
481 
482 		if (! (pnt->codes & PF_OVERFLOW)) {
483 			float r2,t;
484 
485 			r2 = rad*Matrix_scale.xyz.x;
486 
487 			t=r2*Canv_w2/pnt->world.xyz.z;
488 
489 			gr_circle(fl2i(pnt->screen.xyw.x),fl2i(pnt->screen.xyw.y),fl2i(t*2.0f),GR_RESIZE_NONE);
490 		}
491 	}
492 
493 	return 0;
494 }
495 
g3_draw_sphere_ez(vec3d * pnt,float rad)496 int g3_draw_sphere_ez(vec3d *pnt,float rad)
497 {
498 	vertex pt;
499 	ubyte flags;
500 
501 	Assert( G3_count == 1 );
502 
503 	flags = g3_rotate_vertex(&pt,pnt);
504 
505 	if (flags == 0) {
506 
507 		g3_project_vertex(&pt);
508 
509 		if (!(pt.flags & PF_OVERFLOW))	{
510 
511 			g3_draw_sphere( &pt, rad );
512 		}
513 	}
514 
515 	return 0;
516 }
517 
518 //alternate method
g3_draw_bitmap_3d(vertex * pnt,int orient,float rad,uint tmap_flags,float depth)519 int g3_draw_bitmap_3d(vertex *pnt, int orient, float rad, uint tmap_flags, float depth)
520 {
521 	rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and hieght rad
522 
523 	vec3d PNT(pnt->world);
524 	vec3d p[4];
525 	vertex P[4];
526 	vec3d fvec, rvec, uvec;
527 
528 	vm_vec_sub(&fvec, &View_position, &PNT);
529 	vm_vec_normalize(&fvec);
530 
531 	uvec = View_matrix.vec.uvec;
532 	vm_vec_normalize(&uvec);
533 	rvec = View_matrix.vec.rvec;
534 	vm_vec_normalize(&rvec);
535 
536 	vertex *ptlist[4] = { &P[3], &P[2], &P[1], &P[0] };
537 
538 	vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
539 	vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
540 	vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
541 
542 	vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
543 	vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
544 	vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
545 	vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
546 
547 	//move all the data from the vecs into the verts
548 	g3_transfer_vertex(&P[0], &p[3]);
549 	g3_transfer_vertex(&P[1], &p[2]);
550 	g3_transfer_vertex(&P[2], &p[1]);
551 	g3_transfer_vertex(&P[3], &p[0]);
552 
553 	// set up the UV coords
554 	if ( orient & 1 ) {
555 		P[0].texture_position.u = 1.0f;
556 		P[1].texture_position.u = 0.0f;
557 		P[2].texture_position.u = 0.0f;
558 		P[3].texture_position.u = 1.0f;
559 	} else {
560 		P[0].texture_position.u = 0.0f;
561 		P[1].texture_position.u = 1.0f;
562 		P[2].texture_position.u = 1.0f;
563 		P[3].texture_position.u = 0.0f;
564 	}
565 
566 	if ( orient & 2 ) {
567 		P[0].texture_position.v = 1.0f;
568 		P[1].texture_position.v = 1.0f;
569 		P[2].texture_position.v = 0.0f;
570 		P[3].texture_position.v = 0.0f;
571 	} else {
572 		P[0].texture_position.v = 0.0f;
573 		P[1].texture_position.v = 0.0f;
574 		P[2].texture_position.v = 1.0f;
575 		P[3].texture_position.v = 1.0f;
576 	}
577 
578 	int cull = gr_set_cull(0);
579 	g3_draw_poly(4,ptlist,tmap_flags);
580 	gr_set_cull(cull);
581 
582 	return 0;
583 }
584 
g3_draw_bitmap_3d_v(vertex * pnt,int orient,float rad,uint tmap_flags,float depth,float c)585 int g3_draw_bitmap_3d_v(vertex *pnt, int orient, float rad, uint tmap_flags, float depth, float c)
586 {
587 	vec3d PNT(pnt->world);
588 	vec3d p[4];
589 	vertex P[4];
590 	int i;
591 
592 	vertex *ptlist[4] = { &P[3], &P[2], &P[1], &P[0] };
593 	float aspect = gr_screen.aspect*(float)gr_screen.clip_width/(float)gr_screen.clip_height;//seems that we have to corect for the aspect ratio
594 
595 	p[0].xyz.x = rad * aspect;	p[0].xyz.y = rad;	p[0].xyz.z = -depth;
596 	p[1].xyz.x = -rad * aspect;	p[1].xyz.y = rad;	p[1].xyz.z = -depth;
597 	p[2].xyz.x = -rad * aspect;	p[2].xyz.y = -rad;	p[2].xyz.z = -depth;
598 	p[3].xyz.x = rad * aspect;	p[3].xyz.y = -rad;	p[3].xyz.z = -depth;
599 
600 	for(i = 0; i<4; i++){
601 		vec3d t = p[i];
602 		vm_vec_unrotate(&p[i],&t,&View_matrix);//point it at the eye
603 		vm_vec_add2(&p[i],&PNT);//move it
604 	}
605 
606 	//move all the data from the vecs into the verts
607 	g3_transfer_vertex(&P[0], &p[3]);
608 	g3_transfer_vertex(&P[1], &p[2]);
609 	g3_transfer_vertex(&P[2], &p[1]);
610 	g3_transfer_vertex(&P[3], &p[0]);
611 
612 	for( i = 0; i<4; i++){
613 		P[i].r = (ubyte)(255.0f * c);
614 		P[i].g = (ubyte)(255.0f * c);
615 		P[i].b = (ubyte)(255.0f * c);
616 	}
617 
618 	//set up the UV coords
619 	P[0].texture_position.u = 0.0f;	P[0].texture_position.v = 0.0f;
620 	P[1].texture_position.u = 1.0f;	P[1].texture_position.v = 0.0f;
621 	P[2].texture_position.u = 1.0f;	P[2].texture_position.v = 1.0f;
622 	P[3].texture_position.u = 0.0f;	P[3].texture_position.v = 1.0f;
623 
624 	int cull = gr_set_cull(0);
625 	g3_draw_poly(4,ptlist,tmap_flags  | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD);
626 	gr_set_cull(cull);
627 
628 	return 0;
629 }
630 
g3_draw_bitmap_3d_volume(vertex * pnt,int orient,float rad,uint tmap_flags,float depth,int resolution)631 int g3_draw_bitmap_3d_volume(vertex *pnt, int orient, float rad, uint tmap_flags, float depth, int resolution)
632 {
633 	float s = 1.0f;
634 	float res = float(resolution);
635 	for(int i = 0; i <resolution; i++){
636 		s = (1.0f - (float(i-1)/res))/6.5f;
637 		float d = (float(i)/res);
638 		g3_draw_bitmap_3d_v(pnt,orient, rad, tmap_flags, depth * d, s);
639 	}
640 	return 0;
641 }
642 
643 
644 //draws a bitmap with the specified 3d width & height
645 //returns 1 if off screen, 0 if drew
646 // Orient
g3_draw_bitmap(vertex * pnt,int orient,float rad,uint tmap_flags,float depth)647 int g3_draw_bitmap(vertex *pnt, int orient, float rad, uint tmap_flags, float depth)
648 {
649 	if ( !Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT) ) {
650 		return g3_draw_bitmap_3d(pnt, orient, rad, tmap_flags, depth);
651 	}
652 
653 	vertex va, vb;
654 	float t,w,h;
655 	float width, height;
656 	bool bw_bitmap = false;
657 
658 	if ( tmap_flags & TMAP_FLAG_BW_TEXTURE ) {
659 		bw_bitmap = true;
660 	}
661 
662 	if ( tmap_flags & TMAP_FLAG_TEXTURED )	{
663 		int bw, bh;
664 
665 		bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
666 
667 		if ( bw < bh )	{
668 			width = rad*2.0f;
669 			height = width*i2fl(bh)/i2fl(bw);
670 		} else if ( bw > bh )	{
671 			height = rad*2.0f;
672 			width = height*i2fl(bw)/i2fl(bh);
673 		} else {
674 			width = height = rad*2.0f;
675 		}
676 	} else {
677 		width = height = rad*2.0f;
678 	}
679 
680 	Assert( G3_count == 1 );
681 
682 	if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) )
683 		return 1;
684 
685 	if (!(pnt->flags&PF_PROJECTED))
686 		g3_project_vertex(pnt);
687 
688 	if (pnt->flags & PF_OVERFLOW)
689 		return 1;
690 
691 	t = (width*Canv_w2)/pnt->world.xyz.z;
692 	w = t*Matrix_scale.xyz.x;
693 
694 	t = (height*Canv_h2)/pnt->world.xyz.z;
695 	h = t*Matrix_scale.xyz.y;
696 
697 	float z,sw;
698 	z = pnt->world.xyz.z - rad/2.0f;
699 	if ( z <= 0.0f ) {
700 		z = 0.0f;
701 		sw = 0.0f;
702 	} else {
703 		sw = 1.0f / z;
704 	}
705 
706 	va.screen.xyw.x = pnt->screen.xyw.x - w/2.0f;
707 	va.screen.xyw.y = pnt->screen.xyw.y - h/2.0f;
708 	va.screen.xyw.w = sw;
709 	va.world.xyz.z = z;
710 
711 	vb.screen.xyw.x = va.screen.xyw.x + w;
712 	vb.screen.xyw.y = va.screen.xyw.y + h;
713 	vb.screen.xyw.w = sw;
714 	vb.world.xyz.z = z;
715 
716 	if ( orient & 1 )	{
717 		va.texture_position.u = 1.0f;
718 		vb.texture_position.u = 0.0f;
719 	} else {
720 		va.texture_position.u = 0.0f;
721 		vb.texture_position.u = 1.0f;
722 	}
723 
724 	if ( orient & 2 )	{
725 		va.texture_position.v = 1.0f;
726 		vb.texture_position.v = 0.0f;
727 	} else {
728 		va.texture_position.v = 0.0f;
729 		vb.texture_position.v = 1.0f;
730 	}
731 
732 	gr_scaler(&va, &vb, bw_bitmap);
733 
734 	return 0;
735 }
736 
737 // 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)738 int g3_get_bitmap_dims(int bitmap, vertex *pnt, float rad, int *x, int *y, int *w, int *h, int *size)
739 {
740 	float t;
741 	float width, height;
742 
743 	int bw, bh;
744 
745 	bm_get_info( bitmap, &bw, &bh, NULL );
746 
747 	if ( bw < bh )	{
748 		width = rad*2.0f;
749 		height = width*i2fl(bh)/i2fl(bw);
750 	} else if ( bw > bh )	{
751 		height = rad*2.0f;
752 		width = height*i2fl(bw)/i2fl(bh);
753 	} else {
754 		width = height = rad*2.0f;
755 	}
756 
757 	Assert( G3_count == 1 );
758 
759 	if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) {
760 		return 1;
761 	}
762 
763 	if (!(pnt->flags&PF_PROJECTED)){
764 		g3_project_vertex(pnt);
765 	}
766 
767 	if (pnt->flags & PF_OVERFLOW){
768 		return 1;
769 	}
770 
771 	t = (width*Canv_w2)/pnt->world.xyz.z;
772 	*w = (int)(t*Matrix_scale.xyz.x);
773 
774 	t = (height*Canv_h2)/pnt->world.xyz.z;
775 	*h = (int)(t*Matrix_scale.xyz.y);
776 
777 	*x = (int)(pnt->screen.xyw.x - *w/2.0f);
778 	*y = (int)(pnt->screen.xyw.y - *h/2.0f);
779 
780 	*size = MAX(bw, bh);
781 
782 	return 0;
783 }
784 
785 //alternate method
g3_draw_rotated_bitmap_3d(vertex * pnt,float angle,float rad,uint tmap_flags,float depth)786 int g3_draw_rotated_bitmap_3d(vertex *pnt,float angle, float rad,uint tmap_flags, float depth)
787 {
788 	rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and hieght rad
789 
790 	angle-=Physics_viewer_bank;
791 	if ( angle < 0.0f )
792 		angle += PI2;
793 	else if ( angle > PI2 )
794 		angle -= PI2;
795 
796 	vec3d PNT(pnt->world);
797 	vec3d p[4];
798 	vertex P[4];
799 	vec3d fvec, rvec, uvec;
800 
801 	vm_vec_sub(&fvec, &View_position, &PNT);
802 	vm_vec_normalize_safe(&fvec);
803 
804 	vm_rot_point_around_line(&uvec, &View_matrix.vec.uvec, angle, &vmd_zero_vector, &View_matrix.vec.fvec);
805 	vm_vec_normalize(&uvec);
806 
807 	vm_vec_crossprod(&rvec, &View_matrix.vec.fvec, &uvec);
808 	vm_vec_normalize(&rvec);
809 
810 	vertex *ptlist[4] = { &P[3], &P[2], &P[1], &P[0] };
811 
812 	vm_vec_scale_add(&PNT, &PNT, &fvec, depth);
813 	vm_vec_scale_add(&p[0], &PNT, &rvec, rad);
814 	vm_vec_scale_add(&p[2], &PNT, &rvec, -rad);
815 
816 	vm_vec_scale_add(&p[1], &p[2], &uvec, rad);
817 	vm_vec_scale_add(&p[3], &p[0], &uvec, -rad);
818 	vm_vec_scale_add(&p[0], &p[0], &uvec, rad);
819 	vm_vec_scale_add(&p[2], &p[2], &uvec, -rad);
820 
821 	//move all the data from the vecs into the verts
822 	g3_transfer_vertex(&P[0], &p[3]);
823 	g3_transfer_vertex(&P[1], &p[2]);
824 	g3_transfer_vertex(&P[2], &p[1]);
825 	g3_transfer_vertex(&P[3], &p[0]);
826 
827 	//set up the UV coords
828 	P[0].texture_position.u = 0.0f;	P[0].texture_position.v = 0.0f;
829 	P[1].texture_position.u = 1.0f;	P[1].texture_position.v = 0.0f;
830 	P[2].texture_position.u = 1.0f;	P[2].texture_position.v = 1.0f;
831 	P[3].texture_position.u = 0.0f;	P[3].texture_position.v = 1.0f;
832 
833 	int cull = gr_set_cull(0);
834 	g3_draw_poly(4,ptlist,tmap_flags);
835 	gr_set_cull(cull);
836 
837 	return 0;
838 }
839 
840 //draws a bitmap with the specified 3d width & height
841 //returns 1 if off screen, 0 if drew
g3_draw_rotated_bitmap(vertex * pnt,float angle,float rad,uint tmap_flags,float depth)842 int g3_draw_rotated_bitmap(vertex *pnt,float angle, float rad,uint tmap_flags, float depth)
843 {
844 	if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
845 		return g3_draw_rotated_bitmap_3d(pnt, angle, rad, tmap_flags, depth);
846 	}
847 	vertex v[4];
848 	vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
849 	float sa, ca;
850 	int i;
851 
852 	memset(v,0,sizeof(vertex)*4);
853 
854 	Assert( G3_count == 1 );
855 
856 	angle+=Physics_viewer_bank;
857 	if ( angle < 0.0f )
858 		angle += PI2;
859 	else if ( angle > PI2 )
860 		angle -= PI2;
861 
862 	sa = (float)sin(angle);
863 	ca = (float)cos(angle);
864 
865 	float width, height;
866 
867 	if ( tmap_flags & TMAP_FLAG_TEXTURED )	{
868 		int bw, bh;
869 
870 		bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
871 
872 		if ( bw < bh )	{
873 			width = rad;
874 			height = width*i2fl(bh)/i2fl(bw);
875 		} else if ( bw > bh )	{
876 			height = rad;
877 			width = height*i2fl(bw)/i2fl(bh);
878 		} else {
879 			width = height = rad;
880 		}
881 	} else {
882 		width = height = rad;
883 	}
884 
885 	v[0].world.xyz.x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
886 	v[0].world.xyz.y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
887 	v[0].world.xyz.z = pnt->world.xyz.z;
888 	v[0].screen.xyw.w = 0.0f;
889 	v[0].texture_position.u = 0.0f;
890 	v[0].texture_position.v = 1.0f;
891 
892 	v[1].world.xyz.x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
893 	v[1].world.xyz.y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
894 	v[1].world.xyz.z = pnt->world.xyz.z;
895 	v[1].screen.xyw.w = 0.0f;
896 	v[1].texture_position.u = 1.0f;
897 	v[1].texture_position.v = 1.0f;
898 
899 	v[2].world.xyz.x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
900 	v[2].world.xyz.y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
901 	v[2].world.xyz.z = pnt->world.xyz.z;
902 	v[2].screen.xyw.w = 0.0f;
903 	v[2].texture_position.u = 1.0f;
904 	v[2].texture_position.v = 0.0f;
905 
906 	v[3].world.xyz.x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
907 	v[3].world.xyz.y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
908 	v[3].world.xyz.z = pnt->world.xyz.z;
909 	v[3].screen.xyw.w = 0.0f;
910 	v[3].texture_position.u = 0.0f;
911 	v[3].texture_position.v = 0.0f;
912 
913 	ubyte codes_and=0xff;
914 
915 	float sw,z;
916 	z = pnt->world.xyz.z - rad / 4.0f;
917 	if ( z < 0.0f ) z = 0.0f;
918 	sw = 1.0f / z;
919 
920 	for (i=0; i<4; i++ )	{
921 		//now code the four points
922 		codes_and &= g3_code_vertex(&v[i]);
923 		v[i].flags = 0;		// mark as not yet projected
924 	}
925 
926 	if (codes_and)
927 		return 1;		//1 means off screen
928 
929 	// clip and draw it
930 	g3_draw_poly_constant_sw(4, vertlist, tmap_flags, sw );
931 
932 	return 0;
933 }
934 
935 /** As a define only for readability. */
936 #define TRIANGLE_AREA(_p, _q, _r)	do {\
937 	vec3d a, b, cross;\
938 	\
939 	a.xyz.x = _q->world.xyz.x - _p->world.xyz.x;\
940 	a.xyz.y = _q->world.xyz.y - _p->world.xyz.y;\
941 	a.xyz.z = 0.0f;\
942 	\
943 	b.xyz.x = _r->world.xyz.x - _p->world.xyz.x;\
944 	b.xyz.y = _r->world.xyz.y - _p->world.xyz.y;\
945 	b.xyz.z = 0.0f;\
946 	\
947 	vm_vec_crossprod(&cross, &a, &b);\
948 	total_area += vm_vec_mag(&cross) * 0.5f;\
949 } while(0);
950 
g3_get_poly_area(int nv,vertex ** pointlist)951 float g3_get_poly_area(int nv, vertex **pointlist)
952 {
953 	int idx;
954 	float total_area = 0.0f;
955 
956 	// each triangle
957 	for(idx=1; idx<nv-1; idx++){
958 		TRIANGLE_AREA(pointlist[0], pointlist[idx], pointlist[idx+1]);
959 	}
960 
961 	// done
962 	return total_area;
963 }
964 
965 // Draw a polygon.  Same as g3_draw_poly, but it bashes sw to a constant value
966 // for all vertexes.  Needs to be done after clipping to get them all.
967 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
968 //returns 1 if off screen, 0 if drew
g3_draw_poly_constant_sw_area(int nv,vertex ** pointlist,uint tmap_flags,float constant_sw,float area)969 float g3_draw_poly_constant_sw_area(int nv, vertex **pointlist, uint tmap_flags, float constant_sw, float area)
970 {
971 	int i;
972 	vertex **bufptr;
973 	ccodes cc;
974 	float p_area = 0.0f;
975 
976 	Assert( G3_count == 1 );
977 
978 	g3_allocate_vbufs(nv);
979 
980 	cc.cc_or = 0;
981 	cc.cc_and = 0xff;
982 
983 	bufptr = Vbuf0;
984 
985 	for (i=0;i<nv;i++) {
986 		vertex *p;
987 
988 		p = bufptr[i] = pointlist[i];
989 
990 		cc.cc_and &= p->codes;
991 		cc.cc_or  |= p->codes;
992 	}
993 
994 	if (cc.cc_and){
995 		return 0.0f;	//all points off screen
996 	}
997 
998 	if (cc.cc_or)	{
999 		Assert( G3_count == 1 );
1000 
1001 		bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
1002 
1003 		if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
1004 
1005 			for (i=0;i<nv;i++) {
1006 				vertex *p = bufptr[i];
1007 
1008 				if (!(p->flags&PF_PROJECTED))
1009 					g3_project_vertex(p);
1010 
1011 				if (p->flags&PF_OVERFLOW) {
1012 					goto free_points;
1013 				}
1014 
1015 				p->screen.xyw.w = constant_sw;
1016 			}
1017 
1018 			// check area
1019 			p_area = g3_get_poly_area(nv, bufptr);
1020 			if(p_area > area){
1021 				return 0.0f;
1022 			}
1023 
1024 			gr_tmapper( nv, bufptr, tmap_flags );
1025 		}
1026 
1027 free_points:
1028 		;
1029 
1030 		for (i=0;i<nv;i++){
1031 			if (bufptr[i]->flags & PF_TEMP_POINT){
1032 				free_temp_point(bufptr[i]);
1033 			}
1034 		}
1035 	} else {
1036 		//now make list of 2d coords (& check for overflow)
1037 
1038 		for (i=0;i<nv;i++) {
1039 			vertex *p = bufptr[i];
1040 
1041 			if (!(p->flags&PF_PROJECTED))
1042 				g3_project_vertex(p);
1043 
1044 			if (p->flags&PF_OVERFLOW) {
1045 				return 0.0f;
1046 			}
1047 
1048 			p->screen.xyw.w = constant_sw;
1049 		}
1050 
1051 		// check area
1052 		p_area = g3_get_poly_area(nv, bufptr);
1053 		if(p_area > area){
1054 			return 0.0f;
1055 		}
1056 
1057 		gr_tmapper( nv, bufptr, tmap_flags );
1058 	}
1059 
1060 	// how much area we drew
1061 	return p_area;
1062 }
1063 
1064 
1065 //draws a bitmap with the specified 3d width & height
1066 //returns 1 if off screen, 0 if drew
g3_draw_rotated_bitmap_area(vertex * pnt,float angle,float rad,uint tmap_flags,float area)1067 float g3_draw_rotated_bitmap_area(vertex *pnt,float angle, float rad,uint tmap_flags, float area)
1068 {
1069 	vertex v[4];
1070 	vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
1071 	float sa, ca;
1072 	int i;
1073 
1074 	memset(v,0,sizeof(vertex)*4);
1075 
1076 	Assert( G3_count == 1 );
1077 
1078 	angle+=Physics_viewer_bank;
1079 	if ( angle < 0.0f ){
1080 		angle += PI2;
1081 	} else if ( angle > PI2 ) {
1082 		angle -= PI2;
1083 	}
1084 
1085 	sa = (float)sin(angle);
1086 	ca = (float)cos(angle);
1087 
1088 	float width, height;
1089 
1090 	if ( tmap_flags & TMAP_FLAG_TEXTURED )	{
1091 		int bw, bh;
1092 
1093 		bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1094 
1095 		if ( bw < bh )	{
1096 			width = rad;
1097 			height = width*i2fl(bh)/i2fl(bw);
1098 		} else if ( bw > bh )	{
1099 			height = rad;
1100 			width = height*i2fl(bw)/i2fl(bh);
1101 		} else {
1102 			width = height = rad;
1103 		}
1104 	} else {
1105 		width = height = rad;
1106 	}
1107 
1108 	v[0].world.xyz.x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
1109 	v[0].world.xyz.y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
1110 	v[0].world.xyz.z = pnt->world.xyz.z;
1111 	v[0].screen.xyw.w = 0.0f;
1112 	v[0].texture_position.u = 0.0f;
1113 	v[0].texture_position.v = 1.0f;
1114 
1115 	v[1].world.xyz.x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
1116 	v[1].world.xyz.y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
1117 	v[1].world.xyz.z = pnt->world.xyz.z;
1118 	v[1].screen.xyw.w = 0.0f;
1119 	v[1].texture_position.u = 1.0f;
1120 	v[1].texture_position.v = 1.0f;
1121 
1122 	v[2].world.xyz.x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
1123 	v[2].world.xyz.y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
1124 	v[2].world.xyz.z = pnt->world.xyz.z;
1125 	v[2].screen.xyw.w = 0.0f;
1126 	v[2].texture_position.u = 1.0f;
1127 	v[2].texture_position.v = 0.0f;
1128 
1129 	v[3].world.xyz.x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->world.xyz.x;
1130 	v[3].world.xyz.y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->world.xyz.y;
1131 	v[3].world.xyz.z = pnt->world.xyz.z;
1132 	v[3].screen.xyw.w = 0.0f;
1133 	v[3].texture_position.u = 0.0f;
1134 	v[3].texture_position.v = 0.0f;
1135 
1136 	ubyte codes_and=0xff;
1137 
1138 	float sw,z;
1139 	z = pnt->world.xyz.z - rad / 4.0f;
1140 	if ( z < 0.0f ) z = 0.0f;
1141 	sw = 1.0f / z;
1142 
1143 	for (i=0; i<4; i++ )	{
1144 		//now code the four points
1145 		codes_and &= g3_code_vertex(&v[i]);
1146 		v[i].flags = 0;		// mark as not yet projected
1147 	}
1148 
1149 	if (codes_and){
1150 		return 0.0f;
1151 	}
1152 
1153 	// clip and draw it
1154 	return g3_draw_poly_constant_sw_area(4, vertlist, tmap_flags, sw, area );
1155 }
1156 
1157 
1158 
1159 #include "graphics/2d.h"
1160 typedef struct horz_pt {
1161 	float x, y;
1162 	int edge;
1163 } horz_pt;
1164 
1165 //draws a horizon. takes eax=sky_color, edx=ground_color
g3_draw_horizon_line()1166 void g3_draw_horizon_line()
1167 {
1168 	int s1, s2;
1169 	int cpnt;
1170 	horz_pt horz_pts[4];		// 0 = left, 1 = right
1171 	vec3d horizon_vec;
1172 	float up_right, down_right,down_left,up_left;
1173 
1174 	Assert( G3_count == 1 );
1175 
1176 	//compute horizon_vector
1177 	horizon_vec.xyz.x = Unscaled_matrix.vec.rvec.xyz.y*Matrix_scale.xyz.y*Matrix_scale.xyz.z;
1178 	horizon_vec.xyz.y = Unscaled_matrix.vec.uvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.z;
1179 	horizon_vec.xyz.z = Unscaled_matrix.vec.fvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.y;
1180 
1181 	// now compute values & flag for 4 corners.
1182 	up_right = horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1183 	down_right = horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1184 	down_left = -horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1185 	up_left = -horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1186 
1187 	//check flags for all sky or all ground.
1188 	if ( (up_right<0.0f)&&(down_right<0.0f)&&(down_left<0.0f)&&(up_left<0.0f) )	{
1189 		return;
1190 	}
1191 
1192 	if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) )	{
1193 		return;
1194 	}
1195 
1196 	// check for intesection with each of four edges & compute horizon line
1197 	cpnt = 0;
1198 
1199 	// check intersection with left edge
1200 	s1 = up_left > 0.0f;
1201 	s2 = down_left > 0.0f;
1202 	if ( s1 != s2 )	{
1203 		horz_pts[cpnt].x = 0.0f;
1204 		horz_pts[cpnt].y = fl_abs(up_left * Canv_h2 / horizon_vec.xyz.y);
1205 		horz_pts[cpnt].edge = 0;
1206 		cpnt++;
1207 	}
1208 
1209 	// check intersection with top edge
1210 	s1 = up_left > 0.0f;
1211 	s2 = up_right > 0.0f;
1212 	if ( s1 != s2 )	{
1213 		horz_pts[cpnt].x = fl_abs(up_left * Canv_w2 / horizon_vec.xyz.x);
1214 		horz_pts[cpnt].y = 0.0f;
1215 		horz_pts[cpnt].edge = 1;
1216 		cpnt++;
1217 	}
1218 
1219 	// check intersection with right edge
1220 	s1 = up_right > 0.0f;
1221 	s2 = down_right > 0.0f;
1222 	if ( s1 != s2 )	{
1223 		horz_pts[cpnt].x = i2fl(Canvas_width)-1;
1224 		horz_pts[cpnt].y = fl_abs(up_right * Canv_h2 / horizon_vec.xyz.y);
1225 		horz_pts[cpnt].edge = 2;
1226 		cpnt++;
1227 	}
1228 
1229 	//check intersection with bottom edge
1230 	s1 = down_right > 0.0f;
1231 	s2 = down_left > 0.0f;
1232 	if ( s1 != s2 )	{
1233 		horz_pts[cpnt].x = fl_abs(down_left * Canv_w2 / horizon_vec.xyz.x);
1234 		horz_pts[cpnt].y = i2fl(Canvas_height)-1;
1235 		horz_pts[cpnt].edge = 3;
1236 		cpnt++;
1237 	}
1238 
1239 	if ( cpnt != 2 )	{
1240 		mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
1241 		return;
1242 	}
1243 
1244 	//make sure first edge is left
1245 	if ( horz_pts[0].x > horz_pts[1].x )	{
1246 		horz_pt tmp;
1247 		tmp = horz_pts[0];
1248 		horz_pts[0] = horz_pts[1];
1249 		horz_pts[1] = tmp;
1250 	}
1251 
1252 	// draw from left to right.
1253 	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 );
1254 
1255 }
1256 
1257 // Draws a polygon always facing the viewer.
1258 // compute the corners of a rod.  fills in vertbuf.
1259 // Verts has any needs uv's or l's or can be NULL if none needed.
g3_draw_rod(vec3d * p0,float width1,vec3d * p1,float width2,vertex * verts,uint tmap_flags)1260 int g3_draw_rod(vec3d *p0,float width1,vec3d *p1,float width2, vertex * verts, uint tmap_flags)
1261 {
1262 	vec3d uvec, fvec, rvec, center;
1263 
1264 	vm_vec_sub( &fvec, p0, p1 );
1265 	vm_vec_normalize_safe( &fvec );
1266 
1267 	vm_vec_avg( &center, p0, p1 );
1268 	vm_vec_sub( &rvec, &Eye_position, &center );
1269 	vm_vec_normalize( &rvec );
1270 
1271 	vm_vec_crossprod(&uvec,&fvec,&rvec);
1272 
1273 	//normalize new perpendicular vector
1274 	vm_vec_normalize(&uvec);
1275 
1276 	//now recompute right vector, in case it wasn't entirely perpendiclar
1277 	vm_vec_crossprod(&rvec,&uvec,&fvec);
1278 
1279 	// Now have uvec, which is up vector and rvec which is the normal
1280 	// of the face.
1281 
1282 	int i;
1283 	vec3d vecs[4];
1284 	vertex pts[4];
1285 	vertex *ptlist[4] = { &pts[3], &pts[2], &pts[1], &pts[0] };
1286 
1287 	vm_vec_scale_add( &vecs[0], p0, &uvec, width1/2.0f );
1288 	vm_vec_scale_add( &vecs[1], p1, &uvec, width2/2.0f );
1289 	vm_vec_scale_add( &vecs[2], p1, &uvec, -width2/2.0f );
1290 	vm_vec_scale_add( &vecs[3], p0, &uvec, -width1/2.0f );
1291 
1292 	for (i=0; i<4; i++ )	{
1293 		if ( verts )	{
1294 			pts[i] = verts[i];
1295 		}
1296 		if(Cmdline_nohtl)
1297 			g3_rotate_vertex( &pts[i], &vecs[i] );
1298 		else
1299 			g3_transfer_vertex( &pts[i], &vecs[i] );
1300 	}
1301 	ptlist[0]->texture_position.u = 0.0f;
1302 	ptlist[0]->texture_position.v = 0.0f;
1303 	ptlist[0]->r = gr_screen.current_color.red;
1304 	ptlist[0]->g = gr_screen.current_color.green;
1305 	ptlist[0]->b = gr_screen.current_color.blue;
1306 	ptlist[0]->a = gr_screen.current_color.alpha;
1307 
1308 	ptlist[1]->texture_position.u = 1.0f;
1309 	ptlist[1]->texture_position.v = 0.0f;
1310 	ptlist[1]->r = gr_screen.current_color.red;
1311 	ptlist[1]->g = gr_screen.current_color.green;
1312 	ptlist[1]->b = gr_screen.current_color.blue;
1313 	ptlist[1]->a = gr_screen.current_color.alpha;
1314 
1315 	ptlist[2]->texture_position.u = 1.0f;
1316 	ptlist[2]->texture_position.v = 1.0f;
1317 	ptlist[2]->r = gr_screen.current_color.red;
1318 	ptlist[2]->g = gr_screen.current_color.green;
1319 	ptlist[2]->b = gr_screen.current_color.blue;
1320 	ptlist[2]->a = gr_screen.current_color.alpha;
1321 
1322 	ptlist[3]->texture_position.u = 0.0f;
1323 	ptlist[3]->texture_position.v = 1.0f;
1324 	ptlist[3]->r = gr_screen.current_color.red;
1325 	ptlist[3]->g = gr_screen.current_color.green;
1326 	ptlist[3]->b = gr_screen.current_color.blue;
1327 	ptlist[3]->a = gr_screen.current_color.alpha;
1328 
1329 	return g3_draw_poly(4,ptlist,tmap_flags);
1330 }
1331 
1332 #define MAX_ROD_VECS	100
g3_draw_rod(int num_points,vec3d * pvecs,float width,uint tmap_flags)1333 int g3_draw_rod(int num_points, vec3d *pvecs, float width, uint tmap_flags)
1334 {
1335 	vec3d uvec, fvec, rvec;
1336 	vec3d vecs[2];
1337 	vertex pts[MAX_ROD_VECS];
1338 	vertex *ptlist[MAX_ROD_VECS];
1339 	int i, nv = 0;
1340 
1341 	Assert( num_points >= 2 );
1342 	Assert( (num_points * 2) <= MAX_ROD_VECS );
1343 
1344 	for (i = 0; i < num_points; i++) {
1345 		vm_vec_sub(&fvec, &View_position, &pvecs[i]);
1346 		vm_vec_normalize_safe(&fvec);
1347 
1348 		int first = i+1;
1349 		int second = i-1;
1350 
1351 		if (i == 0) {
1352 			first = 1;
1353 			second = 0;
1354 		} else if (i == num_points-1) {
1355 			first = i;
1356 		}
1357 
1358 		vm_vec_sub(&rvec, &pvecs[first], &pvecs[second]);
1359 		vm_vec_normalize_safe(&rvec);
1360 
1361 		vm_vec_crossprod(&uvec, &rvec, &fvec);
1362 
1363 		vm_vec_scale_add(&vecs[0], &pvecs[i], &uvec, width * 0.5f);
1364 		vm_vec_scale_add(&vecs[1], &pvecs[i], &uvec, -width * 0.5f);
1365 
1366 		if (nv > MAX_ROD_VECS-2) {
1367 			Warning(LOCATION, "Hit high-water mark (%i) in g3_draw_rod()!!\n", MAX_ROD_VECS);
1368 			break;
1369 		}
1370 
1371 		ptlist[nv] = &pts[nv];
1372 		ptlist[nv+1] = &pts[nv+1];
1373 
1374 		if (Cmdline_nohtl) {
1375 			g3_rotate_vertex( &pts[nv], &vecs[0] );
1376 			g3_rotate_vertex( &pts[nv+1], &vecs[1] );
1377 		} else {
1378 			g3_transfer_vertex( &pts[nv], &vecs[0] );
1379 			g3_transfer_vertex( &pts[nv+1], &vecs[1] );
1380 		}
1381 
1382 		ptlist[nv]->texture_position.u = 1.0f;
1383 		ptlist[nv]->texture_position.v = i2fl(i);
1384 		ptlist[nv]->r = gr_screen.current_color.red;
1385 		ptlist[nv]->g = gr_screen.current_color.green;
1386 		ptlist[nv]->b = gr_screen.current_color.blue;
1387 		ptlist[nv]->a = gr_screen.current_color.alpha;
1388 
1389 		ptlist[nv+1]->texture_position.u = 0.0f;
1390 		ptlist[nv+1]->texture_position.v = i2fl(i);
1391 		ptlist[nv+1]->r = gr_screen.current_color.red;
1392 		ptlist[nv+1]->g = gr_screen.current_color.green;
1393 		ptlist[nv+1]->b = gr_screen.current_color.blue;
1394 		ptlist[nv+1]->a = gr_screen.current_color.alpha;
1395 
1396 		nv += 2;
1397 	}
1398 
1399 	// we should always have at least 4 verts, and there should always be an even number
1400 	Assert( (nv >= 4) && !(nv % 2) );
1401 
1402 	int rc = g3_draw_poly(nv, ptlist, tmap_flags);
1403 
1404 	return rc;
1405 }
1406 
1407 // draw a perspective bitmap based on angles and radius
1408 vec3d g3_square[4] = {
1409 	{ { { -1.0f, -1.0f, 20.0f } } },
1410 	{ { { -1.0f, 1.0f, 20.0f } } },
1411 	{ { { 1.0f, 1.0f, 20.0f } } },
1412 	{ { { 1.0f, -1.0f, 20.0f } } }
1413 };
1414 
1415 #define MAX_PERSPECTIVE_DIVISIONS			5				// should never even come close to this limit
1416 
stars_project_2d_onto_sphere(vec3d * pnt,float rho,float phi,float theta)1417 void stars_project_2d_onto_sphere( vec3d *pnt, float rho, float phi, float theta )
1418 {
1419 	float a = PI * phi;
1420 	float b = PI2 * theta;
1421 	float sin_a = (float)sin(a);
1422 
1423 	// coords
1424 	pnt->xyz.z = rho * sin_a * (float)cos(b);
1425 	pnt->xyz.y = rho * sin_a * (float)sin(b);
1426 	pnt->xyz.x = rho * (float)cos(a);
1427 }
1428 
1429 // draw a perspective bitmap based on angles and radius
1430 float p_phi = 10.0f;
1431 float p_theta = 10.0f;
g3_draw_perspective_bitmap(angles * a,float scale_x,float scale_y,int div_x,int div_y,uint tmap_flags)1432 int g3_draw_perspective_bitmap(angles *a, float scale_x, float scale_y, int div_x, int div_y, uint tmap_flags)
1433 {
1434 	vec3d s_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1435 	vec3d t_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1436 	vertex v[4];
1437 	vertex *verts[4];
1438 	matrix m, m_bank;
1439 	int idx, s_idx;
1440 	int saved_zbuffer_mode;
1441 	float ui, vi;
1442 	angles bank_first;
1443 
1444 	// cap division values
1445 	// div_x = div_x > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_x;
1446 	div_x = 1;
1447 	div_y = div_y > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_y;
1448 
1449 	// texture increment values
1450 	ui = 1.0f / (float)div_x;
1451 	vi = 1.0f / (float)div_y;
1452 
1453 	// adjust for aspect ratio
1454 	scale_x *= ((float)gr_screen.max_w / (float)gr_screen.max_h) + 0.55f;		// fudge factor
1455 
1456 	float s_phi = 0.5f + (((p_phi * scale_x) / 360.0f) / 2.0f);
1457 	float s_theta = (((p_theta * scale_y) / 360.0f) / 2.0f);
1458 	float d_phi = -(((p_phi * scale_x) / 360.0f) / (float)(div_x));
1459 	float d_theta = -(((p_theta * scale_y) / 360.0f) / (float)(div_y));
1460 
1461 	// bank matrix
1462 	bank_first.p = 0.0f;
1463 	bank_first.b = a->b;
1464 	bank_first.h = 0.0f;
1465 	vm_angles_2_matrix(&m_bank, &bank_first);
1466 
1467 	// convert angles to matrix
1468 	float b_save = a->b;
1469 	a->b = 0.0f;
1470 	vm_angles_2_matrix(&m, a);
1471 	a->b = b_save;
1472 
1473 	// generate the bitmap points
1474 	for(idx=0; idx<=div_x; idx++){
1475 		for(s_idx=0; s_idx<=div_y; s_idx++){
1476 			// get world spherical coords
1477 			stars_project_2d_onto_sphere(&s_points[idx][s_idx], 1000.0f, s_phi + ((float)idx*d_phi), s_theta + ((float)s_idx*d_theta));
1478 
1479 			// bank the bitmap first
1480 			vm_vec_rotate(&t_points[idx][s_idx], &s_points[idx][s_idx], &m_bank);
1481 
1482 			// rotate on the sphere
1483 			vm_vec_rotate(&s_points[idx][s_idx], &t_points[idx][s_idx], &m);
1484 		}
1485 	}
1486 
1487 	// turn off zbuffering
1488 	saved_zbuffer_mode = gr_zbuffer_get();
1489 	gr_zbuffer_set(GR_ZBUFF_NONE);
1490 
1491 	// turn off culling
1492 	int cull = gr_set_cull(0);
1493 
1494 	// render all polys
1495 	for(idx=0; idx<div_x; idx++){
1496 		for(s_idx=0; s_idx<div_y; s_idx++){
1497 			// stuff texture coords
1498 			v[0].texture_position.u = ui * float(idx);
1499 			v[0].texture_position.v = vi * float(s_idx);
1500 			v[0].spec_r=v[0].spec_g=v[0].spec_b=0;
1501 
1502 			v[1].texture_position.u = ui * float(idx+1);
1503 			v[1].texture_position.v = vi * float(s_idx);
1504 			v[1].spec_r=v[1].spec_g=v[1].spec_b=0;
1505 
1506 			v[2].texture_position.u = ui * float(idx+1);
1507 			v[2].texture_position.v = vi * float(s_idx+1);
1508 			v[2].spec_r=v[2].spec_g=v[2].spec_b=0;
1509 
1510 			v[3].texture_position.u = ui * float(idx);
1511 			v[3].texture_position.v = vi * float(s_idx+1);
1512 			v[3].spec_r=v[3].spec_g=v[3].spec_b=0;
1513 
1514 			// poly 1
1515 			v[0].flags = 0;
1516 			v[1].flags = 0;
1517 			v[2].flags = 0;
1518 			verts[0] = &v[0];
1519 			verts[1] = &v[1];
1520 			verts[2] = &v[2];
1521 			g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);
1522 			g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx]);
1523 			g3_rotate_faraway_vertex(verts[2], &s_points[idx+1][s_idx+1]);
1524 			g3_draw_poly(3, verts, tmap_flags);
1525 
1526 			// poly 2
1527 			v[0].flags = 0;
1528 			v[2].flags = 0;
1529 			v[3].flags = 0;
1530 			verts[0] = &v[0];
1531 			verts[1] = &v[2];
1532 			verts[2] = &v[3];
1533 			g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);
1534 			g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx+1]);
1535 			g3_rotate_faraway_vertex(verts[2], &s_points[idx][s_idx+1]);
1536 			g3_draw_poly(3, verts, tmap_flags);
1537 		}
1538 	}
1539 
1540 	// turn on culling
1541 	gr_set_cull(cull);
1542 
1543 	// restore zbuffer
1544 	gr_zbuffer_set(saved_zbuffer_mode);
1545 
1546 	// return
1547 	return 1;
1548 }
1549 
g3_draw_2d_shield_icon(const coord2d coords[6],const int r,const int g,const int b,const int a)1550 void g3_draw_2d_shield_icon(const coord2d coords[6], const int r, const int g, const int b, const int a)
1551 {
1552 	int saved_zbuf;
1553 	vertex v[6];
1554 	vertex *verts[6] = {&v[0], &v[1], &v[2], &v[3], &v[4], &v[5]};
1555 
1556 	memset(v,0,sizeof(vertex)*6);
1557 	saved_zbuf = gr_zbuffer_get();
1558 
1559 	// start the frame, no zbuffering, no culling
1560 	if (!Fred_running)
1561 		g3_start_frame(1);
1562 
1563 	gr_zbuffer_set(GR_ZBUFF_NONE);
1564 	int cull = gr_set_cull(0);
1565 
1566 	// stuff coords
1567 	v[0].screen.xyw.x = i2fl(coords[0].x);
1568 	v[0].screen.xyw.y = i2fl(coords[0].y);
1569 	v[0].screen.xyw.w = 0.0f;
1570 	v[0].texture_position.u = 0.0f;
1571 	v[0].texture_position.v = 0.0f;
1572 	v[0].flags = PF_PROJECTED;
1573 	v[0].codes = 0;
1574 	v[0].r = (ubyte)r;
1575 	v[0].g = (ubyte)g;
1576 	v[0].b = (ubyte)b;
1577 	v[0].a = 0;
1578 
1579 	v[1].screen.xyw.x = i2fl(coords[1].x);
1580 	v[1].screen.xyw.y = i2fl(coords[1].y);
1581 	v[1].screen.xyw.w = 0.0f;
1582 	v[1].texture_position.u = 0.0f;
1583 	v[1].texture_position.v = 0.0f;
1584 	v[1].flags = PF_PROJECTED;
1585 	v[1].codes = 0;
1586 	v[1].r = (ubyte)r;
1587 	v[1].g = (ubyte)g;
1588 	v[1].b = (ubyte)b;
1589 	v[1].a = (ubyte)a;
1590 
1591 	v[2].screen.xyw.x = i2fl(coords[2].x);
1592 	v[2].screen.xyw.y = i2fl(coords[2].y);
1593 	v[2].screen.xyw.w = 0.0f;
1594 	v[2].texture_position.u = 0.0f;
1595 	v[2].texture_position.v = 0.0f;
1596 	v[2].flags = PF_PROJECTED;
1597 	v[2].codes = 0;
1598 	v[2].r = (ubyte)r;
1599 	v[2].g = (ubyte)g;
1600 	v[2].b = (ubyte)b;
1601 	v[2].a = 0;
1602 
1603 	v[3].screen.xyw.x = i2fl(coords[3].x);
1604 	v[3].screen.xyw.y = i2fl(coords[3].y);
1605 	v[3].screen.xyw.w = 0.0f;
1606 	v[3].texture_position.u = 0.0f;
1607 	v[3].texture_position.v = 0.0f;
1608 	v[3].flags = PF_PROJECTED;
1609 	v[3].codes = 0;
1610 	v[3].r = (ubyte)r;
1611 	v[3].g = (ubyte)g;
1612 	v[3].b = (ubyte)b;
1613 	v[3].a = (ubyte)a;
1614 
1615 	v[4].screen.xyw.x = i2fl(coords[4].x);
1616 	v[4].screen.xyw.y = i2fl(coords[4].y);
1617 	v[4].screen.xyw.w = 0.0f;
1618 	v[4].texture_position.u = 0.0f;
1619 	v[4].texture_position.v = 0.0f;
1620 	v[4].flags = PF_PROJECTED;
1621 	v[4].codes = 0;
1622 	v[4].r = (ubyte)r;
1623 	v[4].g = (ubyte)g;
1624 	v[4].b = (ubyte)b;
1625 	v[4].a = 0;
1626 
1627 	v[5].screen.xyw.x = i2fl(coords[5].x);
1628 	v[5].screen.xyw.y = i2fl(coords[5].y);
1629 	v[5].screen.xyw.w = 0.0f;
1630 	v[5].texture_position.u = 0.0f;
1631 	v[5].texture_position.v = 0.0f;
1632 	v[5].flags = PF_PROJECTED;
1633 	v[5].codes = 0;
1634 	v[5].r = (ubyte)r;
1635 	v[5].g = (ubyte)g;
1636 	v[5].b = (ubyte)b;
1637 	v[5].a = 0;
1638 
1639 	// draw the polys
1640 	g3_draw_poly_constant_sw(6, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA | TMAP_FLAG_TRISTRIP, 0.1f);
1641 
1642 	if (!Fred_running)
1643 		g3_end_frame();
1644 
1645 	// restore zbuffer and culling
1646 	gr_zbuffer_set(saved_zbuf);
1647 	gr_set_cull(cull);
1648 }
1649 
g3_draw_2d_rect(int x,int y,int w,int h,int r,int g,int b,int a)1650 void g3_draw_2d_rect(int x, int y, int w, int h, int r, int g, int b, int a)
1651 {
1652 	int saved_zbuf;
1653 	vertex v[4];
1654 	vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
1655 
1656 	memset(v,0,sizeof(vertex)*4);
1657 	saved_zbuf = gr_zbuffer_get();
1658 
1659 	// start the frame, no zbuffering, no culling
1660 	if (!Fred_running)
1661 		g3_start_frame(1);
1662 
1663 	gr_zbuffer_set(GR_ZBUFF_NONE);
1664 	int cull = gr_set_cull(0);
1665 
1666 	// stuff coords
1667 	v[0].screen.xyw.x = i2fl(x);
1668 	v[0].screen.xyw.y = i2fl(y);
1669 	v[0].screen.xyw.w = 0.0f;
1670 	v[0].texture_position.u = 0.0f;
1671 	v[0].texture_position.v = 0.0f;
1672 	v[0].flags = PF_PROJECTED;
1673 	v[0].codes = 0;
1674 	v[0].r = (ubyte)r;
1675 	v[0].g = (ubyte)g;
1676 	v[0].b = (ubyte)b;
1677 	v[0].a = (ubyte)a;
1678 
1679 	v[1].screen.xyw.x = i2fl(x + w);
1680 	v[1].screen.xyw.y = i2fl(y);
1681 	v[1].screen.xyw.w = 0.0f;
1682 	v[1].texture_position.u = 0.0f;
1683 	v[1].texture_position.v = 0.0f;
1684 	v[1].flags = PF_PROJECTED;
1685 	v[1].codes = 0;
1686 	v[1].r = (ubyte)r;
1687 	v[1].g = (ubyte)g;
1688 	v[1].b = (ubyte)b;
1689 	v[1].a = (ubyte)a;
1690 
1691 	v[2].screen.xyw.x = i2fl(x + w);
1692 	v[2].screen.xyw.y = i2fl(y + h);
1693 	v[2].screen.xyw.w = 0.0f;
1694 	v[2].texture_position.u = 0.0f;
1695 	v[2].texture_position.v = 0.0f;
1696 	v[2].flags = PF_PROJECTED;
1697 	v[2].codes = 0;
1698 	v[2].r = (ubyte)r;
1699 	v[2].g = (ubyte)g;
1700 	v[2].b = (ubyte)b;
1701 	v[2].a = (ubyte)a;
1702 
1703 	v[3].screen.xyw.x = i2fl(x);
1704 	v[3].screen.xyw.y = i2fl(y + h);
1705 	v[3].screen.xyw.w = 0.0f;
1706 	v[3].texture_position.u = 0.0f;
1707 	v[3].texture_position.v = 0.0f;
1708 	v[3].flags = PF_PROJECTED;
1709 	v[3].codes = 0;
1710 	v[3].r = (ubyte)r;
1711 	v[3].g = (ubyte)g;
1712 	v[3].b = (ubyte)b;
1713 	v[3].a = (ubyte)a;
1714 
1715 	// draw the polys
1716 	g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA, 0.1f);
1717 
1718 	if (!Fred_running)
1719 		g3_end_frame();
1720 
1721 	// restore zbuffer and culling
1722 	gr_zbuffer_set(saved_zbuf);
1723 	gr_set_cull(cull);
1724 }
1725 
1726 // draw a 2d bitmap on a poly
g3_draw_2d_poly_bitmap(float x,float y,float w,float h,uint additional_tmap_flags)1727 int g3_draw_2d_poly_bitmap(float x, float y, float w, float h, uint additional_tmap_flags)
1728 {
1729 	int ret;
1730 	int saved_zbuffer_mode;
1731 	vertex v[4];
1732 	vertex *vertlist[4] = { &v[0], &v[1], &v[2], &v[3] };
1733 	memset(v,0,sizeof(vertex)*4);
1734 
1735 	g3_start_frame(1);
1736 
1737 	// turn off zbuffering
1738 	saved_zbuffer_mode = gr_zbuffer_get();
1739 	gr_zbuffer_set(GR_ZBUFF_NONE);
1740 
1741 	// stuff coords
1742 	v[0].screen.xyw.x = x;
1743 	v[0].screen.xyw.y = y;
1744 	v[0].screen.xyw.w = 0.0f;
1745 	v[0].texture_position.u = 0.0f;
1746 	v[0].texture_position.v = 0.0f;
1747 	v[0].flags = PF_PROJECTED;
1748 	v[0].codes = 0;
1749 
1750 	v[1].screen.xyw.x = (x + w);
1751 	v[1].screen.xyw.y = y;
1752 	v[1].screen.xyw.w = 0.0f;
1753 	v[1].texture_position.u = 1.0f;
1754 	v[1].texture_position.v = 0.0f;
1755 	v[1].flags = PF_PROJECTED;
1756 	v[1].codes = 0;
1757 
1758 	v[2].screen.xyw.x = (x + w);
1759 	v[2].screen.xyw.y = (y + h);
1760 	v[2].screen.xyw.w = 0.0f;
1761 	v[2].texture_position.u = 1.0f;
1762 	v[2].texture_position.v = 1.0f;
1763 	v[2].flags = PF_PROJECTED;
1764 	v[2].codes = 0;
1765 
1766 	v[3].screen.xyw.x = x;
1767 	v[3].screen.xyw.y = (y + h);
1768 	v[3].screen.xyw.w = 0.0f;
1769 	v[3].texture_position.u = 0.0f;
1770 	v[3].texture_position.v = 1.0f;
1771 	v[3].flags = PF_PROJECTED;
1772 	v[3].codes = 0;
1773 
1774 	// set debrief
1775 	ret = g3_draw_poly_constant_sw(4, vertlist, TMAP_FLAG_TEXTURED | additional_tmap_flags, 0.1f);
1776 
1777 	g3_end_frame();
1778 
1779 	gr_zbuffer_set(saved_zbuffer_mode);
1780 
1781 	return ret;
1782 }
1783 
1784 vertex *bitmap_2d_poly_list=NULL;
1785 vertex **bitmap_2d_poly_vertlist=NULL;
1786 int bitmap_2d_poly_list_size=0;
1787 
bm_list_shutdown()1788 void bm_list_shutdown(){
1789 	if(bitmap_2d_poly_list)delete[]bitmap_2d_poly_list;
1790 	if(bitmap_2d_poly_vertlist)delete[]bitmap_2d_poly_vertlist;
1791 }
1792 
g3_draw_2d_poly_bitmap_list(bitmap_2d_list * b_list,int n_bm,uint additional_tmap_flags)1793 int g3_draw_2d_poly_bitmap_list(bitmap_2d_list* b_list, int n_bm, uint additional_tmap_flags)
1794 {
1795 	int ret;
1796 	int saved_zbuffer_mode;
1797 	if(n_bm>bitmap_2d_poly_list_size){
1798 		if(bitmap_2d_poly_list)delete[]bitmap_2d_poly_list;
1799 		if(bitmap_2d_poly_vertlist)delete[]bitmap_2d_poly_vertlist;
1800 		bitmap_2d_poly_list = new vertex[6* n_bm];
1801 		bitmap_2d_poly_vertlist = new vertex*[6*n_bm];
1802 		for(int i = 0; i<6*n_bm; i++)bitmap_2d_poly_vertlist[i] = &bitmap_2d_poly_list[i];
1803 		memset(bitmap_2d_poly_list,0,sizeof(vertex)*6*n_bm);
1804 	}
1805 
1806 	g3_start_frame(1);
1807 
1808 	// turn off zbuffering
1809 	saved_zbuffer_mode = gr_zbuffer_get();
1810 	gr_zbuffer_set(GR_ZBUFF_NONE);
1811 
1812 	for(int i = 0; i<n_bm;i++){
1813 		// stuff coords
1814 
1815 		//tri one
1816 		vertex *V = &bitmap_2d_poly_list[i*6];
1817 		V->screen.xyw.x = (float)b_list[i].x;
1818 		V->screen.xyw.y = (float)b_list[i].y;
1819 		V->screen.xyw.w = 0.0f;
1820 		V->texture_position.u = 0.0f;
1821 		V->texture_position.v = 0.0f;
1822 		V->flags = PF_PROJECTED;
1823 		V->codes = 0;
1824 
1825 		V++;
1826 		V->screen.xyw.x = (float)(b_list[i].x + b_list[i].w);
1827 		V->screen.xyw.y = (float)b_list[i].y;
1828 		V->screen.xyw.w = 0.0f;
1829 		V->texture_position.u = 1.0f;
1830 		V->texture_position.v = 0.0f;
1831 		V->flags = PF_PROJECTED;
1832 		V->codes = 0;
1833 
1834 		V++;
1835 		V->screen.xyw.x = (float)(b_list[i].x + b_list[i].w);
1836 		V->screen.xyw.y = (float)(b_list[i].y + b_list[i].h);
1837 		V->screen.xyw.w = 0.0f;
1838 		V->texture_position.u = 1.0f;
1839 		V->texture_position.v = 1.0f;
1840 		V->flags = PF_PROJECTED;
1841 		V->codes = 0;
1842 
1843 		//tri two
1844 		V++;
1845 		V->screen.xyw.x = (float)b_list[i].x;
1846 		V->screen.xyw.y = (float)b_list[i].y;
1847 		V->screen.xyw.w = 0.0f;
1848 		V->texture_position.u = 0.0f;
1849 		V->texture_position.v = 0.0f;
1850 		V->flags = PF_PROJECTED;
1851 		V->codes = 0;
1852 
1853 		V++;
1854 		V->screen.xyw.x = (float)(b_list[i].x + b_list[i].w);
1855 		V->screen.xyw.y = (float)(b_list[i].y + b_list[i].h);
1856 		V->screen.xyw.w = 0.0f;
1857 		V->texture_position.u = 1.0f;
1858 		V->texture_position.v = 1.0f;
1859 		V->flags = PF_PROJECTED;
1860 		V->codes = 0;
1861 
1862 		V++;
1863 		V->screen.xyw.x = (float)b_list[i].x;
1864 		V->screen.xyw.y = (float)(b_list[i].y + b_list[i].h);
1865 		V->screen.xyw.w = 0.0f;
1866 		V->texture_position.u = 0.0f;
1867 		V->texture_position.v = 1.0f;
1868 		V->flags = PF_PROJECTED;
1869 		V->codes = 0;
1870 	}
1871 
1872 	// set debrief
1873 	ret = g3_draw_poly_constant_sw(6*n_bm, bitmap_2d_poly_vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_TRILIST | additional_tmap_flags, 0.1f);
1874 
1875 	g3_end_frame();
1876 
1877 	gr_zbuffer_set(saved_zbuffer_mode);
1878 
1879 	return ret;
1880 }
1881 
1882 //draws an array of bitmap_rect_list objects
1883 //see tmapper.h for explaination of structure bitmap_rect_list
g3_draw_2d_poly_bitmap_rect_list(bitmap_rect_list * b_list,int n_bm,uint additional_tmap_flags)1884 int g3_draw_2d_poly_bitmap_rect_list(bitmap_rect_list* b_list, int n_bm, uint additional_tmap_flags)
1885 {
1886 	int ret;
1887 	int saved_zbuffer_mode;
1888 	if(n_bm>bitmap_2d_poly_list_size){
1889 		if(bitmap_2d_poly_list)delete[]bitmap_2d_poly_list;
1890 		if(bitmap_2d_poly_vertlist)delete[]bitmap_2d_poly_vertlist;
1891 		bitmap_2d_poly_list = new vertex[6* n_bm];
1892 		bitmap_2d_poly_vertlist = new vertex*[6*n_bm];
1893 		for(int i = 0; i<6*n_bm; i++)bitmap_2d_poly_vertlist[i] = &bitmap_2d_poly_list[i];
1894 	}
1895 
1896 	g3_start_frame(1);
1897 
1898 	// turn off zbuffering
1899 	saved_zbuffer_mode = gr_zbuffer_get();
1900 	gr_zbuffer_set(GR_ZBUFF_NONE);
1901 
1902 	for(int i = 0; i<n_bm;i++){
1903 		// stuff coords
1904 
1905 		bitmap_2d_list* b = &b_list[i].screen_rect;
1906 		texture_rect_list* t = &b_list[i].texture_rect;
1907 		//tri one
1908 		vertex *V = &bitmap_2d_poly_list[i*6];
1909 		V->screen.xyw.x = (float)b->x;
1910 		V->screen.xyw.y = (float)b->y;
1911 		V->screen.xyw.w = 0.0f;
1912 		V->texture_position.u = (float)t->x;
1913 		V->texture_position.v = (float)t->y;
1914 		V->flags = PF_PROJECTED;
1915 		V->codes = 0;
1916 
1917 		V++;
1918 		V->screen.xyw.x = (float)(b->x + b->w);
1919 		V->screen.xyw.y = (float)b->y;
1920 		V->screen.xyw.w = 0.0f;
1921 		V->texture_position.u = (float)(t->x + t->w);
1922 		V->texture_position.v = (float)t->y;
1923 		V->flags = PF_PROJECTED;
1924 		V->codes = 0;
1925 
1926 		V++;
1927 		V->screen.xyw.x = (float)(b->x + b->w);
1928 		V->screen.xyw.y = (float)(b->y + b->h);
1929 		V->screen.xyw.w = 0.0f;
1930 		V->texture_position.u = (float)(t->x + t->w);
1931 		V->texture_position.v = (float)(t->y + t->h);
1932 		V->flags = PF_PROJECTED;
1933 		V->codes = 0;
1934 
1935 		//tri two
1936 		V++;
1937 		V->screen.xyw.x = (float)b->x;
1938 		V->screen.xyw.y = (float)b->y;
1939 		V->screen.xyw.w = 0.0f;
1940 		V->texture_position.u = (float)t->x;
1941 		V->texture_position.v = (float)t->y;
1942 		V->flags = PF_PROJECTED;
1943 		V->codes = 0;
1944 
1945 		V++;
1946 		V->screen.xyw.x = (float)(b->x + b->w);
1947 		V->screen.xyw.y = (float)(b->y + b->h);
1948 		V->screen.xyw.w = 0.0f;
1949 		V->texture_position.u = (float)(t->x + t->w);
1950 		V->texture_position.v = (float)(t->y + t->h);
1951 		V->flags = PF_PROJECTED;
1952 		V->codes = 0;
1953 
1954 		V++;
1955 		V->screen.xyw.x = (float)b->x;
1956 		V->screen.xyw.y = (float)(b->y + b->h);
1957 		V->screen.xyw.w = 0.0f;
1958 		V->texture_position.u = (float)t->x;
1959 		V->texture_position.v = (float)(t->y + t->h);
1960 		V->flags = PF_PROJECTED;
1961 		V->codes = 0;
1962 	}
1963 
1964 	// set debrief
1965 	ret = g3_draw_poly_constant_sw(6*n_bm, bitmap_2d_poly_vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_TRILIST | additional_tmap_flags, 0.1f);
1966 
1967 	g3_end_frame();
1968 
1969 	gr_zbuffer_set(saved_zbuffer_mode);
1970 
1971 	return ret;
1972 }
1973 
g3_draw_htl_line(vec3d * start,vec3d * end)1974 void g3_draw_htl_line(vec3d *start, vec3d *end)
1975 {
1976 	if (Cmdline_nohtl) {
1977 		return;
1978 	}
1979 
1980 	gr_line_htl(start,end);
1981 }
1982 
g3_draw_htl_sphere(vec3d * position,float radius)1983 void g3_draw_htl_sphere(vec3d* position, float radius)
1984 {
1985 	if (Cmdline_nohtl) {
1986 		return;
1987 	}
1988 
1989 	g3_start_instance_matrix(position, &vmd_identity_matrix, true);
1990 
1991 	gr_sphere_htl(radius);
1992 
1993 	g3_done_instance(true);
1994 }
1995 
1996 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
1997 //flash ball stuff
1998 
initialize(int number,float min_ray_width,float max_ray_width,vec3d * dir,vec3d * pcenter,float outer,float inner,ubyte max_r,ubyte max_g,ubyte max_b,ubyte min_r,ubyte min_g,ubyte min_b)1999 void flash_ball::initialize(int number, float min_ray_width, float max_ray_width, vec3d* dir, vec3d*pcenter, float outer, float inner, ubyte max_r, ubyte max_g, ubyte max_b, ubyte min_r, ubyte min_g, ubyte min_b)
2000 {
2001 	if(number < 1)
2002 		return;
2003 
2004 	center = *pcenter;
2005 
2006 	if(n_rays < number){
2007 		if(ray)vm_free(ray);
2008 		ray = (flash_beam*)vm_malloc(sizeof(flash_beam)*number);
2009 		n_rays = number;
2010 	}
2011 
2012 	int i;
2013 	for(i = 0; i<n_rays; i++){
2014 	//colors
2015 		if(min_r != 255){
2016 			ray[i].start.r = (rand()%(max_r-min_r))+min_r;
2017 		}else{
2018 			ray[i].start.r = 255;
2019 		}
2020 		if(min_g != 255){
2021 			ray[i].start.g = (rand()%(max_g-min_g))+min_g;
2022 		}else{
2023 			ray[i].start.g = 255;
2024 		}
2025 		if(min_b != 255){
2026 			ray[i].start.b = (rand()%(max_b-min_b))+min_b;
2027 		}else{
2028 			ray[i].start.b = 255;
2029 		}
2030 
2031 	//rays
2032 		if(dir == &vmd_zero_vector || outer >= PI2){
2033 			//random sphere
2034 			vec3d start, end;
2035 
2036 			vm_vec_rand_vec_quick(&start);
2037 			vm_vec_rand_vec_quick(&end);
2038 
2039 			ray[i].start.world = start;
2040 			ray[i].end.world = end;
2041 		}else{
2042 			//random cones
2043 			vec3d start, end;
2044 
2045 			vm_vec_random_cone(&start, dir, outer, inner);
2046 			vm_vec_random_cone(&end, dir, outer, inner);
2047 
2048 			ray[i].start.world = start;
2049 			ray[i].end.world = end;
2050 		}
2051 		if(max_ray_width == 0.0f)ray[i].width=min_ray_width;
2052 		else ray[i].width = frand_range(min_ray_width, max_ray_width);
2053 	}
2054 
2055 
2056 }
2057 
2058 #define uw(p)	(*((uint *) (p)))
2059 #define w(p)	(*((int *) (p)))
2060 #define wp(p)	((int *) (p))
2061 #define vp(p)	((vec3d *) (p))
2062 #define fl(p)	(*((float *) (p)))
2063 
defpoint(int off,ubyte * bsp_data)2064 void flash_ball::defpoint(int off, ubyte *bsp_data)
2065 {
2066 	int n;
2067 	int nverts = w(off+bsp_data+8);
2068 	int offset = w(off+bsp_data+16);
2069 	ubyte * normcount = off+bsp_data+20;
2070 	vec3d *src = vp(off+bsp_data+offset);
2071 
2072 	if(n_rays < nverts){
2073 		if(ray)vm_free(ray);
2074 		ray = (flash_beam*)vm_malloc(sizeof(flash_beam)*nverts);
2075 		n_rays = nverts;
2076 	}
2077 
2078 	{
2079 		vec3d temp;
2080 		for (n=0; n<nverts; n++ )	{
2081 
2082 			temp = *src;
2083 			vm_vec_sub2(&temp, &center);
2084 			vm_vec_normalize(&temp);
2085 			ray[n].start.world = temp;
2086 
2087 			src++;		// move to normal
2088 
2089 			src+=normcount[n];
2090 		}
2091 	}
2092 }
2093 
2094 #define OP_EOF 			0
2095 #define OP_DEFPOINTS 	1
2096 #define OP_FLATPOLY		2
2097 #define OP_TMAPPOLY		3
2098 #define OP_SORTNORM		4
2099 #define OP_BOUNDBOX		5
2100 
2101 
parse_bsp(int offset,ubyte * bsp_data)2102 void flash_ball::parse_bsp(int offset, ubyte *bsp_data){
2103 	int ID, SIZE;
2104 
2105 	memcpy(&ID, &bsp_data[offset], sizeof(int));
2106 	memcpy(&SIZE, &bsp_data[offset+sizeof(int)], sizeof(int));
2107 
2108 	while(ID!=0){
2109 		switch(ID){
2110 		case OP_EOF:
2111 			return;
2112 			break;
2113 		case OP_DEFPOINTS:	defpoint(offset, bsp_data);
2114 			break;
2115 		case OP_SORTNORM:
2116 			break;
2117 		case OP_FLATPOLY:
2118 			break;
2119 		case OP_TMAPPOLY:
2120 			break;
2121 		case OP_BOUNDBOX:
2122 			break;
2123 		default:
2124 			return;
2125 		}
2126 			offset += SIZE;
2127 		memcpy(&ID, &bsp_data[offset], sizeof(int));
2128 		memcpy(&SIZE, &bsp_data[offset+sizeof(int)], sizeof(int));
2129 
2130 		if(SIZE < 1)ID=OP_EOF;
2131 	}
2132 }
2133 
2134 
initialize(ubyte * bsp_data,float min_ray_width,float max_ray_width,vec3d * dir,vec3d * pcenter,float outer,float inner,ubyte max_r,ubyte max_g,ubyte max_b,ubyte min_r,ubyte min_g,ubyte min_b)2135 void flash_ball::initialize(ubyte *bsp_data, float min_ray_width, float max_ray_width, vec3d* dir , vec3d*pcenter , float outer , float inner , ubyte max_r , ubyte max_g , ubyte max_b , ubyte min_r , ubyte min_g , ubyte min_b )
2136 {
2137 	center = *pcenter;
2138 	vm_vec_negate(&center);
2139 	parse_bsp(0,bsp_data);
2140 	center = vmd_zero_vector;
2141 
2142 	int i;
2143 	for(i = 0; i<n_rays; i++){
2144 	//colors
2145 		if(min_r != 255){
2146 			ray[i].start.r = (rand()%(max_r-min_r))+min_r;
2147 		}else{
2148 			ray[i].start.r = 255;
2149 		}
2150 		if(min_g != 255){
2151 			ray[i].start.g = (rand()%(max_g-min_g))+min_g;
2152 		}else{
2153 			ray[i].start.g = 255;
2154 		}
2155 		if(min_b != 255){
2156 			ray[i].start.b = (rand()%(max_b-min_b))+min_b;
2157 		}else{
2158 			ray[i].start.b = 255;
2159 		}
2160 
2161 	//rays
2162 		if(dir == &vmd_zero_vector || outer >= PI2){
2163 			//random sphere
2164 			vec3d end;
2165 
2166 			vm_vec_rand_vec_quick(&end);
2167 
2168 			ray[i].end.world = end;
2169 		}else{
2170 			//random cones
2171 			vec3d end;
2172 
2173 			vm_vec_random_cone(&end, dir, outer, inner);
2174 
2175 			ray[i].end.world = end;
2176 		}
2177 		if(max_ray_width == 0.0f)ray[i].width=min_ray_width;
2178 		else ray[i].width = frand_range(min_ray_width, max_ray_width);
2179 	}
2180 }
2181 
2182 //rad		how wide the ball should be
2183 //intinsity	how visable it should be
2184 //life		how far along from start to end should it be
render(float rad,float intinsity,float life)2185 void flash_ball::render(float rad, float intinsity, float life){
2186 	flash_ball::batcher.allocate(n_rays);
2187 	for(int i = 0; i<n_rays; i++){
2188 		vec3d end;
2189 		vm_vec_interp_constant(&end, &ray[i].start.world, &ray[i].end.world, life);
2190 		vm_vec_scale(&end, rad);
2191 		vm_vec_add2(&end, &center);
2192 		flash_ball::batcher.draw_beam(&center, &end, ray[i].width*rad, intinsity);
2193 	}
2194 	flash_ball::batcher.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT);
2195 }
2196 
2197 geometry_batcher flash_ball::batcher;
2198