]> icculus.org git repositories - taylor/freespace2.git/blob - src/render/3ddraw.cpp
warnings (clang): unused-but-set-variable
[taylor/freespace2.git] / src / render / 3ddraw.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Render/3ddraw.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * 3D rendering primitives
16  *
17  * $Log$
18  * Revision 1.5  2002/06/17 06:33:10  relnev
19  * ryan's struct patch for gcc 2.95
20  *
21  * Revision 1.4  2002/06/09 04:41:25  relnev
22  * added copyright header
23  *
24  * Revision 1.3  2002/05/07 03:16:51  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.2  2002/05/03 13:34:33  theoddone33
28  * More stuff compiles
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:10  root
31  * Initial import.
32  *
33  * 
34  * 18    9/06/99 3:23p Andsager
35  * Make fireball and weapon expl ani LOD choice look at resolution of the
36  * bitmap
37  * 
38  * 17    8/27/99 9:07p Dave
39  * LOD explosions. Improved beam weapon accuracy.
40  * 
41  * 16    7/29/99 12:05a Dave
42  * Nebula speed optimizations.
43  * 
44  * 15    7/13/99 1:16p Dave
45  * 32 bit support. Whee!
46  * 
47  * 14    7/02/99 3:05p Anoop
48  * Oops. Fixed g3_draw_2d_poly() so that it properly handles poly bitmap
49  * and LFB bitmap calls.
50  * 
51  * 13    6/29/99 10:35a Dave
52  * Interface polygon bitmaps! Whee!
53  * 
54  * 12    6/22/99 7:03p Dave
55  * New detail options screen.
56  * 
57  * 11    6/16/99 4:06p Dave
58  * New pilot info popup. Added new draw-bitmap-as-poly function.
59  * 
60  * 10    6/08/99 5:17p Dave
61  * Fixed up perspective bitmap drawing.
62  * 
63  * 9     6/03/99 6:37p Dave
64  * More TNT fun. Made perspective bitmaps more flexible.
65  * 
66  * 8     5/28/99 1:58p Dave
67  * Fixed problem with overwriting bank value drawing perspective bitmaps.
68  * 
69  * 7     5/28/99 1:45p Dave
70  * Fixed up perspective bitmap drawing.
71  * 
72  * 6     5/24/99 5:45p Dave
73  * Added detail levels to the nebula, with a decent speedup. Split nebula
74  * lightning into its own section.
75  * 
76  * 5     4/07/99 6:22p Dave
77  * Fred and Freespace support for multiple background bitmaps and suns.
78  * Fixed link errors on all subprojects. Moved encrypt_init() to
79  * cfile_init() and lcl_init(), since its safe to call twice.
80  * 
81  * 4     3/09/99 6:24p Dave
82  * More work on object update revamping. Identified several sources of
83  * unnecessary bandwidth.
84  * 
85  * 3     2/11/99 3:08p Dave
86  * PXO refresh button. Very preliminary squad war support.
87  * 
88  * 2     10/07/98 10:53a Dave
89  * Initial checkin.
90  * 
91  * 1     10/07/98 10:51a Dave
92  * 
93  * 37    3/22/98 2:34p John
94  * If alpha effects is on lowest detail level, draw rotated bitmaps as
95  * scaled bitmaps.
96  * 
97  * 36    3/16/98 4:51p John
98  * Added low-level code to clip all polygons against an arbritary plane.
99  * Took out all old model_interp_zclip and used this new method instead.  
100  * 
101  * 35    3/04/98 9:29a John
102  * Made rotated bitmaps force all sw's to the same value after clipping.
103  * 
104  * 34    3/03/98 6:59p John
105  * 
106  * 33    1/26/98 5:12p John
107  * Added in code for Pentium Pro specific optimizations. Speed up
108  * zbuffered correct tmapper about 35%.   Speed up non-zbuffered scalers
109  * by about 25%.
110  * 
111  * 32    1/15/98 2:16p John
112  * Made bitmaps zbuffer at center minus radius.
113  * Made fireballs sort after objects they are around.
114  * 
115  * 31    1/06/98 2:11p John
116  * Made g3_draw_rotated bitmap draw the same orientation as g3_draw_bitmap
117  * (orient=0) and made it be the same size (it was 2x too big before).
118  * 
119  * 30    12/30/97 6:44p John
120  * Made g3_Draw_bitmap functions account for aspect of bitmap.
121  * 
122  * 29    12/04/97 12:09p John
123  * Made glows use scaler instead of tmapper so they don't rotate.  Had to
124  * add a zbuffered scaler.
125  * 
126  * 28    12/02/97 4:00p John
127  * Added first rev of thruster glow, along with variable levels of
128  * translucency, which retquired some restructing of palman.
129  * 
130  * 27    11/29/97 2:05p John
131  * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
132  * like they used to incorrectly assume.   Added code to model to read in
133  * thruster radius's.
134  * 
135  * 26    10/20/97 4:49p John
136  * added weapon trails.
137  * added facing bitmap code to 3d lib.
138  * 
139  * 25    10/03/97 9:10a John
140  * added better antialiased line drawer
141  * 
142  * 24    9/09/97 3:39p Sandeep
143  * warning level 4 bugs
144  * 
145  * 23    7/11/97 11:54a John
146  * added rotated 3d bitmaps.
147  * 
148  * 22    5/07/97 2:59p John
149  * Initial rev of D3D texturing.
150  * 
151  * 21    4/29/97 9:55a John
152  * 
153  * 20    3/10/97 2:25p John
154  * Made pofview zbuffer.   Made textest work with new model code.  Took
155  * out some unnecessary Asserts in the 3d clipper.
156  * 
157  * 
158  * 19    3/06/97 5:36p Mike
159  * Change vec_normalize_safe() back to vec_normalize().
160  * Spruce up docking a bit.
161  * 
162  * 18    3/06/97 10:56a Mike
163  * Write error checking version of vm_vec_normalize().
164  * Fix resultant problems.
165  * 
166  * 17    2/26/97 5:24p John
167  * Added g3_draw_sphere_ez
168  * 
169  * 16    2/17/97 5:18p John
170  * Added a bunch of RCS headers to a bunch of old files that don't have
171  * them.
172  *
173  * $NoKeywords: $
174  */
175
176 #include "3dinternal.h"
177 #include "tmapper.h"
178 #include "2d.h"
179 #include "floating.h"
180 #include "physics.h"            // For Physics_viewer_bank for g3_draw_rotated_bitmap
181 #include "bmpman.h"
182 #include "systemvars.h"
183 #include "alphacolors.h"
184
185 #include "key.h"
186
187 //deal with a clipped line
188 int must_clip_line(vertex *p0,vertex *p1,ubyte codes_or, uint flags)
189 {
190         int ret = 0;
191         
192         clip_line(&p0,&p1,codes_or, flags);
193         
194         if (p0->codes & p1->codes) goto free_points;
195
196         codes_or = (unsigned char)(p0->codes | p1->codes);
197
198         if (codes_or & CC_BEHIND) goto free_points;
199
200         if (!(p0->flags&PF_PROJECTED))
201                 g3_project_vertex(p0);
202
203         if (p0->flags&PF_OVERFLOW) goto free_points;
204
205         if (!(p1->flags&PF_PROJECTED))
206                 g3_project_vertex(p1);
207
208         if (p1->flags&PF_OVERFLOW) goto free_points;
209         
210         //gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
211         //      gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
212
213         gr_aaline( p0, p1 );
214
215         ret = 1;
216
217         //frees temp points
218 free_points:
219
220         if (p0->flags & PF_TEMP_POINT)
221                 free_temp_point(p0);
222
223         if (p1->flags & PF_TEMP_POINT)
224                 free_temp_point(p1);
225
226         return ret;
227 }
228
229 //draws a line. takes two points.  returns true if drew
230 int g3_draw_line(vertex *p0,vertex *p1)
231 {
232         ubyte codes_or;
233
234         SDL_assert( G3_count == 1 );
235
236         if (p0->codes & p1->codes)
237                 return 0;
238
239         codes_or = (unsigned char)(p0->codes | p1->codes);
240
241         if (codes_or & CC_BEHIND)
242                 return must_clip_line(p0,p1,codes_or,0);
243
244         if (!(p0->flags&PF_PROJECTED))
245                 g3_project_vertex(p0);
246
247         if (p0->flags&PF_OVERFLOW) 
248 //              return 1;
249                 return must_clip_line(p0,p1,codes_or,0);
250
251
252         if (!(p1->flags&PF_PROJECTED))
253                 g3_project_vertex(p1);
254
255         if (p1->flags&PF_OVERFLOW)
256 //              return 1;
257                 return must_clip_line(p0,p1,codes_or,0);
258
259         
260 //      gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
261 //      gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
262
263         gr_aaline( p0, p1 );
264
265         return 0;
266 }
267
268 //returns true if a plane is facing the viewer. takes the unrotated surface
269 //normal of the plane, and a point on it.  The normal need not be normalized
270 int g3_check_normal_facing(vector *v,vector *norm)
271 {
272         vector tempv;
273
274         SDL_assert( G3_count == 1 );
275
276         vm_vec_sub(&tempv,&View_position,v);
277
278         return (vm_vec_dot(&tempv,norm) > 0.0f);
279 }
280
281 int do_facing_check(vector *norm,vertex **vertlist,vector *p)
282 {
283         SDL_assert( G3_count == 1 );
284
285         if (norm) {             //have normal
286
287                 SDL_assert(norm->xyz.x || norm->xyz.y || norm->xyz.z);
288
289                 return g3_check_normal_facing(p,norm);
290         }
291         else {  //normal not specified, so must compute
292
293                 vector tempv;
294
295                 //get three points (rotated) and compute normal
296
297                 vm_vec_perp(&tempv,(vector *)&vertlist[0]->x,(vector *)&vertlist[1]->x,(vector *)&vertlist[2]->x);
298
299                 return (vm_vec_dot(&tempv,(vector *)&vertlist[1]->x ) < 0.0);
300         }
301 }
302
303 //like g3_draw_poly(), but checks to see if facing.  If surface normal is
304 //NULL, this routine must compute it, which will be slow.  It is better to
305 //pre-compute the normal, and pass it to this function.  When the normal
306 //is passed, this function works like g3_check_normal_facing() plus
307 //g3_draw_poly().
308 //returns -1 if not facing, 1 if off screen, 0 if drew
309 int g3_draw_poly_if_facing(int nv,vertex **pointlist,uint tmap_flags,vector *norm,vector *pnt)
310 {
311         SDL_assert( G3_count == 1 );
312
313         if (do_facing_check(norm,pointlist,pnt))
314                 return g3_draw_poly(nv,pointlist,tmap_flags);
315         else
316                 return 255;
317 }
318
319 //draw a polygon.
320 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
321 //returns 1 if off screen, 0 if drew
322 int g3_draw_poly(int nv,vertex **pointlist,uint tmap_flags)
323 {
324         int i;
325         vertex **bufptr;
326         ccodes cc;
327
328         SDL_assert( G3_count == 1 );
329
330         cc.vor = 0; cc.vand = 0xff;
331
332         bufptr = Vbuf0;
333
334         for (i=0;i<nv;i++) {
335                 vertex *p;
336
337                 p = bufptr[i] = pointlist[i];
338
339                 cc.vand &= p->codes;
340                 cc.vor  |= p->codes;
341         }
342
343         if (cc.vand)
344                 return 1;       //all points off screen
345
346         if (cc.vor)     {
347                 SDL_assert( G3_count == 1 );
348
349                 bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tmap_flags);
350
351                 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
352
353                         for (i=0;i<nv;i++) {
354                                 vertex *p = bufptr[i];
355
356                                 if (!(p->flags&PF_PROJECTED))
357                                         g3_project_vertex(p);
358                 
359                                 if (p->flags&PF_OVERFLOW) {
360                                         //Int3();               //should not overflow after clip
361                                         //printf( "overflow in must_clip_tmap_face\n" );
362                                         goto free_points;
363                                 }                               
364                         }
365
366                         gr_tmapper( nv, bufptr, tmap_flags );
367                 }
368
369 free_points:
370                 ;
371
372                 for (i=0;i<nv;i++)
373                         if (bufptr[i]->flags & PF_TEMP_POINT)
374                                 free_temp_point(bufptr[i]);
375
376         } else {
377                 //now make list of 2d coords (& check for overflow)
378
379                 for (i=0;i<nv;i++) {
380                         vertex *p = bufptr[i];
381
382                         if (!(p->flags&PF_PROJECTED))
383                                 g3_project_vertex(p);
384
385                         if (p->flags&PF_OVERFLOW) {
386                                 //Int3();               //should not overflow after clip
387                                 //printf( "3d: Point overflowed, but flags say OK!\n" );
388                                 return 255;
389                         }
390
391                 }
392
393                 gr_tmapper( nv, bufptr, tmap_flags );
394         }
395         return 0;       //say it drew
396 }
397
398
399
400 // Draw a polygon.  Same as g3_draw_poly, but it bashes sw to a constant value
401 // for all vertexes.  Needs to be done after clipping to get them all.
402 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
403 //returns 1 if off screen, 0 if drew
404 int g3_draw_poly_constant_sw(int nv,vertex **pointlist,uint tmap_flags, float constant_sw)
405 {
406         int i;
407         vertex **bufptr;
408         ccodes cc;
409
410         SDL_assert( G3_count == 1 );
411
412         cc.vor = 0; cc.vand = 0xff;
413
414         bufptr = Vbuf0;
415
416         for (i=0;i<nv;i++) {
417                 vertex *p;
418
419                 p = bufptr[i] = pointlist[i];
420
421                 cc.vand &= p->codes;
422                 cc.vor  |= p->codes;
423         }
424
425         if (cc.vand)
426                 return 1;       //all points off screen
427
428         if (cc.vor)     {
429                 SDL_assert( G3_count == 1 );
430
431                 bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
432
433                 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
434
435                         for (i=0;i<nv;i++) {
436                                 vertex *p = bufptr[i];
437
438                                 if (!(p->flags&PF_PROJECTED))
439                                         g3_project_vertex(p);
440                 
441                                 if (p->flags&PF_OVERFLOW) {
442                                         //Int3();               //should not overflow after clip
443                                         //printf( "overflow in must_clip_tmap_face\n" );
444                                         goto free_points;
445                                 }
446
447                                 p->sw = constant_sw;
448                         }
449
450                         gr_tmapper( nv, bufptr, tmap_flags );
451
452                         // draw lines connecting the faces
453                         /*
454                         gr_set_color_fast(&Color_bright_green);
455                         for(i=0; i<nv-1; i++){
456                                 g3_draw_line(bufptr[i], bufptr[i+1]);
457                         } 
458                         g3_draw_line(bufptr[0], bufptr[i]);
459                         */
460                 }
461
462 free_points:
463                 ;
464
465                 for (i=0;i<nv;i++){
466                         if (bufptr[i]->flags & PF_TEMP_POINT){
467                                 free_temp_point(bufptr[i]);
468                         }
469                 }
470         } else {
471                 //now make list of 2d coords (& check for overflow)
472
473                 for (i=0;i<nv;i++) {
474                         vertex *p = bufptr[i];
475
476                         if (!(p->flags&PF_PROJECTED))
477                                 g3_project_vertex(p);
478
479                         if (p->flags&PF_OVERFLOW) {
480                                 //Int3();               //should not overflow after clip
481                                 //printf( "3d: Point overflowed, but flags say OK!\n" );
482                                 return 255;
483                         }
484
485                         p->sw = constant_sw;
486                 }
487
488                 gr_tmapper( nv, bufptr, tmap_flags );
489
490                 // draw lines connecting the faces
491                 /*
492                 gr_set_color_fast(&Color_bright_green);
493                 for(i=0; i<nv-1; i++){
494                         g3_draw_line(bufptr[i], bufptr[i+1]);
495                 } 
496                 g3_draw_line(bufptr[0], bufptr[i]);
497                 */
498         }
499         return 0;       //say it drew
500 }
501
502 //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
503 //radius, but not to the distance from the eye
504 int g3_draw_sphere(vertex *pnt,float rad)
505 {
506         SDL_assert( G3_count == 1 );
507
508         if (! (pnt->codes & CC_BEHIND)) {
509
510                 if (! (pnt->flags & PF_PROJECTED))
511                         g3_project_vertex(pnt);
512
513                 if (! (pnt->codes & PF_OVERFLOW)) {
514                         float r2,t;
515
516                         r2 = rad*Matrix_scale.xyz.x;
517
518                         t=r2*Canv_w2/pnt->z;
519
520                         gr_circle(fl2i(pnt->sx),fl2i(pnt->sy),fl2i(t*2.0f));
521                 }
522         }
523
524         return 0;
525 }
526
527 int g3_draw_sphere_ez(vector *pnt,float rad)
528 {
529         vertex pt;
530         ubyte flags;
531
532         SDL_assert( G3_count == 1 );
533
534         flags = g3_rotate_vertex(&pt,pnt);
535
536         if (flags == 0) {
537
538                 g3_project_vertex(&pt);
539
540                 if (!(pt.flags & PF_OVERFLOW))  {
541
542                         g3_draw_sphere( &pt, rad );
543                 }
544         }
545
546         return 0;
547 }
548
549
550 //draws a bitmap with the specified 3d width & height 
551 //returns 1 if off screen, 0 if drew
552 // Orient
553 int g3_draw_bitmap(vertex *pnt,int orient, float rad,uint tmap_flags)
554 {
555         vertex va, vb;
556         float t,w,h;
557         float width, height;
558
559         if ( tmap_flags & TMAP_FLAG_TEXTURED )  {
560                 int bw, bh;
561
562                 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
563
564                 if ( bw < bh )  {
565                         width = rad*2.0f;
566                         height = width*i2fl(bh)/i2fl(bw);
567                 } else if ( bw > bh )   {
568                         height = rad*2.0f;
569                         width = height*i2fl(bw)/i2fl(bh);
570                 } else {
571                         width = height = rad*2.0f;
572                 }               
573         } else {
574                 width = height = rad*2.0f;
575         }
576
577         SDL_assert( G3_count == 1 );
578
579         if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) 
580                 return 1;
581
582         if (!(pnt->flags&PF_PROJECTED))
583                 g3_project_vertex(pnt);
584
585         if (pnt->flags & PF_OVERFLOW)
586                 return 1;
587
588         t = (width*Canv_w2)/pnt->z;
589         w = t*Matrix_scale.xyz.x;
590
591         t = (height*Canv_h2)/pnt->z;
592         h = t*Matrix_scale.xyz.y;
593
594         float z,sw;
595         z = pnt->z - rad/2.0f;
596         if ( z <= 0.0f ) {
597                 z = 0.0f;
598                 sw = 0.0f;
599         } else {
600                 sw = 1.0f / z;
601         }
602
603         va.sx = pnt->sx - w/2.0f;
604         va.sy = pnt->sy - h/2.0f;
605         va.sw = sw;
606         va.z = z;
607
608         vb.sx = va.sx + w;
609         vb.sy = va.sy + h;
610         vb.sw = sw;
611         vb.z = z;
612
613         if ( orient & 1 )       {
614                 va.u = 1.0f;
615                 vb.u = 0.0f;
616         } else {
617                 va.u = 0.0f;
618                 vb.u = 1.0f;
619         }
620
621         if ( orient & 2 )       {
622                 va.v = 1.0f;
623                 vb.v = 0.0f;
624         } else {
625                 va.v = 0.0f;
626                 vb.v = 1.0f;
627         }
628
629         gr_scaler(&va, &vb);
630
631         return 0;
632 }
633
634 // get bitmap dims onscreen as if g3_draw_bitmap() had been called
635 int g3_get_bitmap_dims(int bitmap, vertex *pnt, float rad, int *x, int *y, int *w, int *h, int *size)
636 {       
637         float t;
638         float width, height;
639         
640         int bw, bh;
641
642         bm_get_info( bitmap, &bw, &bh, NULL );
643
644         if ( bw < bh )  {
645                 width = rad*2.0f;
646                 height = width*i2fl(bh)/i2fl(bw);
647         } else if ( bw > bh )   {
648                 height = rad*2.0f;
649                 width = height*i2fl(bw)/i2fl(bh);
650         } else {
651                 width = height = rad*2.0f;
652         }                       
653
654         SDL_assert( G3_count == 1 );
655
656         if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) {
657                 return 1;
658         }
659
660         if (!(pnt->flags&PF_PROJECTED)){
661                 g3_project_vertex(pnt);
662         }
663
664         if (pnt->flags & PF_OVERFLOW){
665                 return 1;
666         }
667
668         t = (width*Canv_w2)/pnt->z;
669         *w = (int)(t*Matrix_scale.xyz.x);
670
671         t = (height*Canv_h2)/pnt->z;
672         *h = (int)(t*Matrix_scale.xyz.y);
673
674         *x = (int)(pnt->sx - *w/2.0f);
675         *y = (int)(pnt->sy - *h/2.0f);  
676
677         *size = max(bw, bh);
678
679         return 0;
680 }
681
682 //draws a bitmap with the specified 3d width & height 
683 //returns 1 if off screen, 0 if drew
684 int g3_draw_rotated_bitmap(vertex *pnt,float angle, float rad,uint tmap_flags)
685 {
686         vertex v[4];
687         vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
688         float sa, ca;
689         int i;
690
691         /*
692         if ( !Detail.alpha_effects )    {
693                 int ang;
694                 if ( angle < PI/2 )     {
695                         ang = 0;
696                 } else if ( angle < PI )        {
697                         ang = 1;
698                 } else if ( angle < PI+PI/2 )   {
699                         ang = 2;
700                 } else {
701                         ang = 3;
702                 }
703                 return g3_draw_bitmap( pnt, ang, rad, tmap_flags );
704         }
705         */
706
707         SDL_assert( G3_count == 1 );
708
709         angle+=Physics_viewer_bank;
710         if ( angle < 0.0f )
711                 angle += PI2;
712         else if ( angle > PI2 )
713                 angle -= PI2;
714 //      angle = 0.0f;
715                         
716         sa = (float)sin(angle);
717         ca = (float)cos(angle);
718
719         float width, height;
720
721         if ( tmap_flags & TMAP_FLAG_TEXTURED )  {
722                 int bw, bh;
723
724                 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
725
726                 if ( bw < bh )  {
727                         width = rad;
728                         height = width*i2fl(bh)/i2fl(bw);
729                 } else if ( bw > bh )   {
730                         height = rad;
731                         width = height*i2fl(bw)/i2fl(bh);
732                 } else {
733                         width = height = rad;
734                 }               
735         } else {
736                 width = height = rad;
737         }
738
739
740         v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
741         v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
742         v[0].z = pnt->z;
743         v[0].sw = 0.0f;
744         v[0].u = 0.0f;
745         v[0].v = 1.0f;
746
747         v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
748         v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
749         v[1].z = pnt->z;
750         v[1].sw = 0.0f;
751         v[1].u = 1.0f;
752         v[1].v = 1.0f;
753
754         v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
755         v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
756         v[2].z = pnt->z;
757         v[2].sw = 0.0f;
758         v[2].u = 1.0f;
759         v[2].v = 0.0f;
760
761         v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
762         v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
763         v[3].z = pnt->z;
764         v[3].sw = 0.0f;
765         v[3].u = 0.0f;
766         v[3].v = 0.0f;
767
768         ubyte codes_and=0xff;
769
770         float sw,z;
771         z = pnt->z - rad / 4.0f;
772         if ( z < 0.0f ) z = 0.0f;
773         sw = 1.0f / z;
774
775         for (i=0; i<4; i++ )    {
776                 //now code the four points
777                 codes_and &= g3_code_vertex(&v[i]);
778                 v[i].flags = 0;         // mark as not yet projected
779                 //g3_project_vertex(&v[i]);
780         }
781
782         if (codes_and)
783                 return 1;               //1 means off screen
784
785         // clip and draw it
786         g3_draw_poly_constant_sw(4, vertlist, tmap_flags, sw ); 
787         
788         return 0;
789 }
790
791 #define TRIANGLE_AREA(_p, _q, _r)       do { vector a, b, cross; a.xyz.x = _q->x - _p->x; a.xyz.y = _q->y - _p->y; a.xyz.z = 0.0f; b.xyz.x = _r->x - _p->x; b.xyz.y = _r->y - _p->y; b.xyz.z = 0.0f; vm_vec_crossprod(&cross, &a, &b); total_area += vm_vec_mag(&cross) * 0.5f; } while(0);
792 float g3_get_poly_area(int nv, vertex **pointlist)
793 {
794         int idx;
795         float total_area = 0.0f;        
796
797         // each triangle
798         for(idx=1; idx<nv-1; idx++){
799                 TRIANGLE_AREA(pointlist[0], pointlist[idx], pointlist[idx+1]);
800         }
801
802         // done
803         return total_area;
804 }
805
806 // Draw a polygon.  Same as g3_draw_poly, but it bashes sw to a constant value
807 // for all vertexes.  Needs to be done after clipping to get them all.
808 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
809 //returns 1 if off screen, 0 if drew
810 float g3_draw_poly_constant_sw_area(int nv, vertex **pointlist, uint tmap_flags, float constant_sw, float area)
811 {
812         int i;
813         vertex **bufptr;
814         ccodes cc;
815         float p_area = 0.0f;
816
817         SDL_assert( G3_count == 1 );
818
819         cc.vor = 0; cc.vand = 0xff;
820
821         bufptr = Vbuf0;
822
823         for (i=0;i<nv;i++) {
824                 vertex *p;
825
826                 p = bufptr[i] = pointlist[i];
827
828                 cc.vand &= p->codes;
829                 cc.vor  |= p->codes;
830         }
831
832         if (cc.vand){
833                 return 0.0f;    //all points off screen
834         }
835
836         if (cc.vor)     {
837                 SDL_assert( G3_count == 1 );
838
839                 bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
840
841                 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
842
843                         for (i=0;i<nv;i++) {
844                                 vertex *p = bufptr[i];
845
846                                 if (!(p->flags&PF_PROJECTED))
847                                         g3_project_vertex(p);
848                 
849                                 if (p->flags&PF_OVERFLOW) {
850                                         //Int3();               //should not overflow after clip
851                                         //printf( "overflow in must_clip_tmap_face\n" );
852                                         goto free_points;
853                                 }
854
855                                 p->sw = constant_sw;
856                         }
857
858                         // check area
859                         p_area = g3_get_poly_area(nv, bufptr);
860                         if(p_area > area){
861                                 return 0.0f;
862                         }
863
864                         gr_tmapper( nv, bufptr, tmap_flags );                   
865                 }
866
867 free_points:
868                 ;
869
870                 for (i=0;i<nv;i++){
871                         if (bufptr[i]->flags & PF_TEMP_POINT){
872                                 free_temp_point(bufptr[i]);
873                         }
874                 }
875         } else {
876                 //now make list of 2d coords (& check for overflow)
877
878                 for (i=0;i<nv;i++) {
879                         vertex *p = bufptr[i];
880
881                         if (!(p->flags&PF_PROJECTED))
882                                 g3_project_vertex(p);
883
884                         if (p->flags&PF_OVERFLOW) {                             
885                                 return 0.0f;
886                         }
887
888                         p->sw = constant_sw;
889                 }
890
891                 // check area
892                 p_area = g3_get_poly_area(nv, bufptr);
893                 if(p_area > area){
894                         return 0.0f;
895                 }               
896
897                 gr_tmapper( nv, bufptr, tmap_flags );           
898         }
899
900         // how much area we drew
901         return p_area;
902 }
903
904
905 //draws a bitmap with the specified 3d width & height 
906 //returns 1 if off screen, 0 if drew
907 float g3_draw_rotated_bitmap_area(vertex *pnt,float angle, float rad,uint tmap_flags, float area)
908 {
909         vertex v[4];
910         vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
911         float sa, ca;
912         int i;  
913
914         SDL_assert( G3_count == 1 );
915
916         angle+=Physics_viewer_bank;
917         if ( angle < 0.0f ){
918                 angle += PI2;
919         } else if ( angle > PI2 ) {
920                 angle -= PI2;
921         }
922                         
923         sa = (float)sin(angle);
924         ca = (float)cos(angle);
925
926         float width, height;
927
928         if ( tmap_flags & TMAP_FLAG_TEXTURED )  {
929                 int bw, bh;
930
931                 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
932
933                 if ( bw < bh )  {
934                         width = rad;
935                         height = width*i2fl(bh)/i2fl(bw);
936                 } else if ( bw > bh )   {
937                         height = rad;
938                         width = height*i2fl(bw)/i2fl(bh);
939                 } else {
940                         width = height = rad;
941                 }               
942         } else {
943                 width = height = rad;
944         }
945
946
947         v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
948         v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
949         v[0].z = pnt->z;
950         v[0].sw = 0.0f;
951         v[0].u = 0.0f;
952         v[0].v = 1.0f;
953
954         v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
955         v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
956         v[1].z = pnt->z;
957         v[1].sw = 0.0f;
958         v[1].u = 1.0f;
959         v[1].v = 1.0f;
960
961         v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
962         v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
963         v[2].z = pnt->z;
964         v[2].sw = 0.0f;
965         v[2].u = 1.0f;
966         v[2].v = 0.0f;
967
968         v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
969         v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
970         v[3].z = pnt->z;
971         v[3].sw = 0.0f;
972         v[3].u = 0.0f;
973         v[3].v = 0.0f;
974
975         ubyte codes_and=0xff;
976
977         float sw,z;
978         z = pnt->z - rad / 4.0f;
979         if ( z < 0.0f ) z = 0.0f;
980         sw = 1.0f / z;
981
982         for (i=0; i<4; i++ )    {
983                 //now code the four points
984                 codes_and &= g3_code_vertex(&v[i]);
985                 v[i].flags = 0;         // mark as not yet projected
986                 //g3_project_vertex(&v[i]);
987         }
988
989         if (codes_and){
990                 return 0.0f;
991         }
992
993         // clip and draw it
994         return g3_draw_poly_constant_sw_area(4, vertlist, tmap_flags, sw, area );               
995 }
996
997
998
999 #include "2d.h"
1000 typedef struct horz_pt {
1001         float x, y;
1002         int edge;
1003 } horz_pt;
1004
1005 //draws a horizon. takes eax=sky_color, edx=ground_color
1006 void g3_draw_horizon_line()
1007 {
1008         //int sky_color,int ground_color
1009         int s1, s2;
1010         int cpnt;
1011         horz_pt horz_pts[4];            // 0 = left, 1 = right
1012 //      int top_color, bot_color;
1013 //      int color_swap;         //flag for if we swapped
1014 //      int sky_ground_flag;    //0=both, 1=all sky, -1=all gnd
1015
1016         vector horizon_vec;
1017         
1018         float up_right, down_right,down_left,up_left;
1019
1020 //      color_swap = 0;         //assume no swap
1021 //      sky_ground_flag = 0;    //assume both
1022
1023 //      if ( View_matrix.uvec.y < 0.0f )
1024 //              color_swap = 1;
1025 //      else if ( View_matrix.uvec.y == 0.0f )  {
1026 //              if ( View_matrix.uvec.xyz.x > 0.0f )
1027 //                      color_swap = 1;
1028 //      }
1029
1030 //      if (color_swap) {
1031 //              top_color  = ground_color;
1032 //              bot_color = sky_color;
1033 //      } else {
1034 //              top_color  = sky_color;
1035 //              bot_color = ground_color;
1036 //      }
1037
1038         SDL_assert( G3_count == 1 );
1039
1040
1041         //compute horizon_vector
1042         
1043         horizon_vec.xyz.x = Unscaled_matrix.v.rvec.xyz.y*Matrix_scale.xyz.y*Matrix_scale.xyz.z;
1044         horizon_vec.xyz.y = Unscaled_matrix.v.uvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.z;
1045         horizon_vec.xyz.z = Unscaled_matrix.v.fvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.y;
1046
1047         // now compute values & flag for 4 corners.
1048         up_right = horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1049         down_right = horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1050         down_left = -horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1051     up_left = -horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1052
1053         //check flags for all sky or all ground.
1054         if ( (up_right<0.0f)&&(down_right<0.0f)&&(down_left<0.0f)&&(up_left<0.0f) )     {
1055 //              mprintf(( "All ground.\n" ));
1056                 return;
1057         }
1058
1059         if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) )     {
1060 //              mprintf(( "All sky.\n" ));
1061                 return;
1062         }
1063
1064 //mprintf(( "Horizon vec = %.4f, %.4f, %.4f\n", horizon_vec.x, horizon_vec.y, horizon_vec.z ));
1065 //mprintf(( "%.4f, %.4f, %.4f, %.4f\n", up_right, down_right, down_left, up_left ));
1066
1067         
1068 //      mprintf(( "u: %.4f %.4f %.4f  c: %.4f %.4f %.4f %.4f\n",Unscaled_matrix.uvec.y,Unscaled_matrix.uvec.z,Unscaled_matrix.uvec.x,up_left,up_right,down_right,down_left ));
1069         // check for intesection with each of four edges & compute horizon line
1070         cpnt = 0;
1071         
1072         // check intersection with left edge
1073         s1 = up_left > 0.0f;
1074         s2 = down_left > 0.0f;
1075         if ( s1 != s2 ) {
1076                 horz_pts[cpnt].x = 0.0f;
1077                 horz_pts[cpnt].y = fl_abs(up_left * Canv_h2 / horizon_vec.xyz.y);
1078                 horz_pts[cpnt].edge = 0;
1079                 cpnt++;
1080         }
1081
1082         // check intersection with top edge
1083         s1 = up_left > 0.0f;
1084         s2 = up_right > 0.0f;
1085         if ( s1 != s2 ) {
1086                 horz_pts[cpnt].x = fl_abs(up_left * Canv_w2 / horizon_vec.xyz.x);
1087                 horz_pts[cpnt].y = 0.0f;
1088                 horz_pts[cpnt].edge = 1;
1089                 cpnt++;
1090         }
1091
1092         
1093         // check intersection with right edge
1094         s1 = up_right > 0.0f;
1095         s2 = down_right > 0.0f;
1096         if ( s1 != s2 ) {
1097                 horz_pts[cpnt].x = i2fl(Canvas_width)-1;
1098                 horz_pts[cpnt].y = fl_abs(up_right * Canv_h2 / horizon_vec.xyz.y);
1099                 horz_pts[cpnt].edge = 2;
1100                 cpnt++;
1101         }
1102         
1103         //check intersection with bottom edge
1104         s1 = down_right > 0.0f;
1105         s2 = down_left > 0.0f;
1106         if ( s1 != s2 ) {
1107                 horz_pts[cpnt].x = fl_abs(down_left * Canv_w2 / horizon_vec.xyz.x);
1108                 horz_pts[cpnt].y = i2fl(Canvas_height)-1;
1109                 horz_pts[cpnt].edge = 3;
1110                 cpnt++;
1111         }
1112
1113         if ( cpnt != 2 )        {
1114                 mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
1115                 return;
1116         }
1117
1118         //make sure first edge is left
1119
1120         if ( horz_pts[0].x > horz_pts[1].x )    {
1121                 horz_pt tmp;
1122                 tmp = horz_pts[0];
1123                 horz_pts[0] = horz_pts[1];
1124                 horz_pts[1] = tmp;
1125         }
1126
1127
1128         // draw from left to right.
1129         gr_line( fl2i(horz_pts[0].x),fl2i(horz_pts[0].y),fl2i(horz_pts[1].x),fl2i(horz_pts[1].y) );
1130         
1131 }
1132
1133
1134 /*
1135
1136 horizon_poly    dw      5 dup (?,?)     ;max of 5 points
1137
1138 ;for g3_compute_horz_vecs
1139 xfrac   fix     ?
1140 yfrac   fix     ?
1141
1142 vec_ptr dd      ?
1143 corner_num      dd      ?
1144
1145 ;for compute corner vec
1146 m13     fix     ?       ;m1-m3
1147 m46     fix     ?
1148 m79     fix     ?
1149 m56     fix     ?
1150 m23     fix     ?
1151 m89     fix     ?
1152
1153 _DATA   ends
1154
1155
1156 _TEXT   segment dword public USE32 'CODE'
1157
1158         extn    gr_setcolor_,gr_clear_canvas_
1159         extn    gr_upoly_tmap_
1160
1161 ;draw a polygon (one half of horizon) from the horizon line
1162 draw_horz_poly: lea     ebx,horizon_poly
1163
1164 ;copy horizon line as first points in poly
1165
1166         mov     eax,[edi]
1167         mov     [ebx],eax
1168         mov     eax,4[edi]
1169         mov     4[ebx],eax
1170
1171         mov     eax,[esi]
1172         mov     8[ebx],eax
1173         mov     eax,4[esi]
1174         mov     12[ebx],eax
1175
1176 ;add corners to polygon
1177
1178         mov     eax,8[esi]      ;edge number of start edge
1179
1180         mov     ecx,8[edi]      ;edge number of end point
1181         sub     ecx,eax ;number of edges
1182         jns     edgenum_ok
1183         add     ecx,4
1184 edgenum_ok:
1185         mov     edx,ecx ;save count
1186         sal     eax,3   ;edge * 8
1187         lea     esi,corners[eax]        ;first corner
1188         lea     edi,16[ebx]     ;rest of poly
1189 corner_loop:    movsd
1190         movsd           ;copy a corner
1191         cmp     esi,offset corners+8*4  ;end of list?
1192         jne     no_wrap
1193         lea     esi,corners
1194 no_wrap:        loop    corner_loop
1195
1196 ;now draw the polygon
1197         mov     eax,edx ;get corner count
1198         add     eax,2   ;..plus horz line end points
1199         lea     edx,horizon_poly        ;get the points
1200 ;;      call    gr_poly_        ;draw it!
1201  call gr_upoly_tmap_
1202         ret
1203
1204 ;return information on the polygon that is the sky. 
1205 ;takes ebx=ptr to x,y pairs, ecx=ptr to vecs for each point
1206 ;returns eax=number of points
1207 ;IMPORTANT: g3_draw_horizon() must be called before this routine.
1208 g3_compute_sky_polygon:
1209         test    sky_ground_flag,-1      ;what was drawn
1210         js      was_all_ground
1211         jg      was_all_sky     
1212
1213         pushm   ebx,ecx,edx,esi,edi
1214
1215         lea     esi,left_point
1216         lea     edi,right_point
1217         test    color_swap,-1
1218         jz      no_swap_ends
1219         xchg    esi,edi ;sky isn't top
1220 no_swap_ends:
1221
1222 ;copy horizon line as first points in poly
1223
1224         mov     eax,[edi]       ;copy end point
1225         mov     [ebx],eax
1226         mov     eax,4[edi]
1227         mov     4[ebx],eax
1228
1229         mov     eax,[esi]       ;copy start point
1230         mov     8[ebx],eax
1231         mov     eax,4[esi]
1232         mov     12[ebx],eax
1233
1234         pushm   ebx,ecx
1235         push    edi     ;save end point
1236         push    esi     ;save start point
1237         mov     esi,edi ;end point is first point
1238         mov     edi,ecx ;dest buffer
1239         call    compute_horz_end_vec
1240
1241         pop     esi     ;get back start point
1242         add     edi,12  ;2nd vec
1243         call    compute_horz_end_vec
1244
1245         pop     edi     ;get back end point
1246         popm    ebx,ecx
1247         add     ebx,16  ;past two x,y pairs
1248         add     ecx,24  ;past two vectors
1249
1250         mov     vec_ptr,ecx
1251
1252 ;add corners to polygon
1253
1254         mov     eax,8[esi]      ;edge number of start edge
1255         mov     corner_num,eax
1256
1257         mov     ecx,8[edi]      ;edge number of end point
1258         sub     ecx,eax ;number of edges
1259         jns     edgenum_ok2
1260         add     ecx,4
1261 edgenum_ok2:
1262         push    ecx     ;save count
1263         sal     eax,3   ;edge * 8
1264         lea     esi,corners[eax]        ;first corner
1265         mov     edi,ebx ;rest of poly 2d points
1266 corner_loop2:
1267         movsd
1268         movsd           ;copy a corner
1269         cmp     esi,offset corners+8*4  ;end of list?
1270         jne     no_wrap2
1271         lea     esi,corners
1272 no_wrap2:
1273         pushm   ecx,esi,edi
1274         mov     edi,vec_ptr
1275         mov     eax,corner_num
1276         call    compute_corner_vec
1277         add     vec_ptr,12
1278         inc     corner_num
1279         popm    ecx,esi,edi
1280
1281         loop    corner_loop2
1282
1283 ;now return with count
1284         pop     eax     ;get corner count
1285         add     eax,2   ;..plus horz line end points
1286
1287         popm    ebx,ecx,edx,esi,edi
1288
1289         ret
1290
1291 ;we drew all ground, so there was no horizon drawn
1292 was_all_ground: xor     eax,eax ;no points in poly
1293         ret
1294
1295 ;we drew all sky, so find 4 corners
1296 was_all_sky:    pushm   ebx,ecx,edx,esi,edi
1297         push    ecx
1298         lea     esi,corners
1299         mov     edi,ebx
1300         mov     ecx,8
1301         rep     movsd
1302         pop     edi
1303
1304         mov     ecx,4
1305         xor     eax,eax ;start corner 0
1306 sky_loop:       pushm   eax,ecx,edi
1307         call    compute_corner_vec
1308         popm    eax,ecx,edi
1309         add     edi,12
1310         inc     eax
1311         loop    sky_loop
1312         mov     eax,4   ;4 corners
1313         popm    ebx,ecx,edx,esi,edi
1314         ret
1315
1316 ;compute vector describing horizon intersection with a point.
1317 ;takes esi=2d point, edi=vec. trashes eax,ebx,ecx,edx
1318 compute_horz_end_vec:
1319
1320 ;compute rotated x/z & y/z ratios
1321
1322         mov     eax,[esi]       ;get x coord
1323         sub     eax,Canv_w2
1324         fixdiv  Canv_w2
1325         mov     xfrac,eax       ;save
1326
1327         mov     eax,4[esi]      ;get y coord
1328         sub     eax,Canv_h2
1329         fixdiv  Canv_h2
1330         neg     eax     ;y inversion
1331         mov     yfrac,eax       ;save
1332
1333 ;compute fraction unrotated x/z
1334
1335         mov     eax,xfrac
1336         add     eax,yfrac
1337         mov     ecx,eax ;save
1338         fixmul  View_matrix.m9
1339         sub     eax,View_matrix.m7
1340         sub     eax,View_matrix.m8
1341         mov     ebx,eax ;save numerator
1342
1343         mov     eax,ecx
1344         fixmul  View_matrix.m3
1345         mov     ecx,eax
1346         mov     eax,View_matrix.m1
1347         add     eax,View_matrix.m2
1348         sub     eax,ecx
1349
1350 ;now eax/ebx = z/x. do divide in way to give result < 0
1351
1352         pushm   eax,ebx
1353         abs_eax
1354         xchg    eax,ebx
1355         abs_eax
1356         cmp     eax,ebx ;which is bigger?
1357         popm    eax,ebx
1358         jl      do_xz
1359
1360 ;x is bigger, so do as z/x
1361
1362         fixdiv  ebx
1363         
1364 ;now eax = z/x ratio.  Compute vector by normalizing and correcting sign
1365
1366         push    eax     ;save ratio
1367
1368         imul    eax     ;compute z*z
1369         inc     edx     ;+ x*x (x==1)
1370         call    quad_sqrt
1371
1372         mov     ecx,eax ;mag in ecx
1373         pop     eax     ;get ratio, x part
1374
1375         fixdiv  ecx
1376         mov     [edi].z,eax
1377
1378         mov     eax,f1_0
1379         fixdiv  ecx
1380
1381         mov     [edi].x,eax
1382
1383         jmp     finish_end
1384
1385 ;z is bigger, so do as x/z
1386 do_xz:
1387         xchg    eax,ebx
1388         fixdiv  ebx
1389         
1390 ;now eax = x/z ratio.  Compute vector by normalizing and correcting sign
1391
1392         push    eax     ;save ratio
1393
1394         imul    eax     ;compute x*x
1395         inc     edx     ;+ z*z (z==1)
1396         call    quad_sqrt
1397
1398         mov     ecx,eax ;mag in ecx
1399         pop     eax     ;get ratio, x part
1400
1401         fixdiv  ecx
1402         mov     [edi].x,eax
1403
1404         mov     eax,f1_0
1405         fixdiv  ecx
1406
1407         mov     [edi].z,eax
1408
1409 finish_end:     xor     eax,eax ;y = 0
1410         mov     [edi].y,eax
1411
1412 ;now make sure that this vector is in front of you, not behind
1413
1414         mov     eax,[edi].x
1415         imul    View_matrix.m3
1416         mov     ebx,eax
1417         mov     ecx,edx
1418         mov     eax,[edi].z
1419         imul    View_matrix.m9
1420         add     eax,ebx
1421         adc     edx,ecx
1422         jns     vec_ok  ;has positive z, ok
1423
1424 ;z is neg, flip vector
1425
1426         neg     [edi].x
1427         neg     [edi].z
1428 vec_ok:
1429         ret
1430
1431 MIN_DEN equ 7fffh
1432
1433 sub2    macro   dest,src
1434         mov     eax,src
1435         sal     eax,1
1436         sub     dest,eax
1437         endm
1438
1439 ;compute vector decribing a corner of the screen.
1440 ;takes edi=vector, eax=corner num
1441 compute_corner_vec:
1442
1443         cmp     eax,4
1444         jl      num_ok
1445         sub     eax,4
1446 num_ok:
1447
1448 ;compute all deltas
1449         mov     ebx,View_matrix.m1
1450         mov     ecx,View_matrix.m4
1451         mov     edx,View_matrix.m7
1452
1453         or      eax,eax
1454         jz      neg_x
1455         cmp     eax,3
1456         jne     no_neg_x
1457 neg_x:
1458         neg     ebx
1459         neg     ecx
1460         neg     edx
1461 no_neg_x:       
1462         sub     ebx,View_matrix.m3
1463         mov     m13,ebx ;m1-m3
1464         sub     ecx,View_matrix.m6
1465         mov     m46,ecx ;m4-m6
1466         sub     edx,View_matrix.m9
1467         mov     m79,edx ;m7-m9
1468
1469         mov     ebx,View_matrix.m5
1470         mov     ecx,View_matrix.m2
1471         mov     edx,View_matrix.m8
1472
1473         cmp     eax,2
1474         jl      no_neg_y
1475 neg_y:
1476         neg     ebx
1477         neg     ecx
1478         neg     edx
1479 no_neg_y:       
1480         sub     ebx,View_matrix.m6
1481         mov     m56,ebx ;m5-m6
1482         sub     ecx,View_matrix.m3
1483         mov     m23,ecx ;m2-m3
1484         sub     edx,View_matrix.m9
1485         mov     m89,edx ;m8-m9
1486
1487 ;compute x/z ratio
1488
1489 ;compute denomonator
1490
1491         mov     eax,m46
1492         fixmul  m23
1493         mov     ebx,eax ;save
1494
1495         mov     eax,m56
1496         fixmul  m13
1497         sub     eax,ebx ;eax = denominator
1498
1499 ;now we have the denominator.  If it is too small, try x/y, z/y or z/x, y/x
1500
1501         mov     ecx,eax ;save den
1502
1503         abs_eax
1504         cmp     eax,MIN_DEN
1505         jl      z_too_small
1506
1507 z_too_small:
1508
1509 ;now do x/z numerator
1510
1511         mov     eax,m79
1512         fixmul  m56     ;* (m5-m6)
1513         mov     ebx,eax
1514
1515         mov     eax,m89
1516         fixmul  m46     ;* (m4-m6)
1517         sub     eax,ebx
1518
1519 ;now, eax/ecx = x/z ratio
1520
1521         fixdiv  ecx     ;eax = x/z
1522
1523         mov     [edi].x,eax     ;save x
1524
1525 ;now do y/z
1526
1527         mov     eax,m89
1528         fixmul  m13
1529         mov     ebx,eax
1530
1531         mov     eax,m79
1532         fixmul  m23
1533         sub     eax,ebx
1534
1535 ;now eax/ecx = y/z ratio
1536
1537         fixdiv  ecx
1538
1539         mov     [edi].y,eax
1540
1541         mov     [edi].z,f1_0
1542
1543         mov     esi,edi
1544         call    vm_vec_normalize
1545
1546 ;make sure this vec is pointing in right direction
1547
1548         lea     edi,View_matrix.fvec
1549         call    vm_vec_dotprod
1550         or      eax,eax ;check sign
1551         jg      vec_sign_ok
1552
1553         neg     [esi].x
1554         neg     [esi].y
1555         neg     [esi].z
1556 vec_sign_ok:
1557
1558         ret
1559
1560
1561 _TEXT   ends
1562
1563         end
1564
1565 */
1566
1567
1568 // Draws a polygon always facing the viewer.
1569 // compute the corners of a rod.  fills in vertbuf.
1570 // Verts has any needs uv's or l's or can be NULL if none needed.
1571 int g3_draw_rod(vector *p0,float width1,vector *p1,float width2, vertex * verts, uint tmap_flags)
1572 {
1573         vector uvec, fvec, rvec, center;
1574
1575         vm_vec_sub( &fvec, p0, p1 );
1576         vm_vec_normalize_safe( &fvec );
1577
1578         vm_vec_avg( &center, p0, p1 );
1579         vm_vec_sub( &rvec, &Eye_position, &center );
1580         vm_vec_normalize( &rvec );
1581
1582         vm_vec_crossprod(&uvec,&fvec,&rvec);
1583                         
1584         //normalize new perpendicular vector
1585         vm_vec_normalize(&uvec);
1586          
1587         //now recompute right vector, in case it wasn't entirely perpendiclar
1588         vm_vec_crossprod(&rvec,&uvec,&fvec);
1589
1590         // Now have uvec, which is up vector and rvec which is the normal
1591         // of the face.
1592
1593         int i;
1594         vector vecs[4];
1595         vertex pts[4];
1596         vertex *ptlist[4] = { &pts[3], &pts[2], &pts[1], &pts[0] };
1597
1598         vm_vec_scale_add( &vecs[0], p0, &uvec, width1/2.0f );
1599         vm_vec_scale_add( &vecs[1], p1, &uvec, width2/2.0f );
1600         vm_vec_scale_add( &vecs[2], p1, &uvec, -width2/2.0f );
1601         vm_vec_scale_add( &vecs[3], p0, &uvec, -width1/2.0f );
1602         
1603         for (i=0; i<4; i++ )    {
1604                 if ( verts )    {
1605                         pts[i] = verts[i];
1606                 }
1607                 g3_rotate_vertex( &pts[i], &vecs[i] );
1608         }
1609
1610         return g3_draw_poly(4,ptlist,tmap_flags);
1611 }
1612
1613 // draw a perspective bitmap based on angles and radius
1614 vector g3_square[4] = {
1615         { { { -1.0f, -1.0f, 20.0f } } },
1616         { { { -1.0f, 1.0f, 20.0f } } },
1617         { { { 1.0f, 1.0f, 20.0f } } },
1618         { { { 1.0f, -1.0f, 20.0f } } }
1619 };
1620
1621 #define MAX_PERSPECTIVE_DIVISIONS                       5                               // should never even come close to this limit
1622
1623 void stars_project_2d_onto_sphere( vector *pnt, float rho, float phi, float theta )
1624 {               
1625         float a = 3.14159f * phi;
1626         float b = 6.28318f * theta;
1627         float sin_a = (float)sin(a);    
1628
1629         // coords
1630         pnt->xyz.z = rho * sin_a * (float)cos(b);
1631         pnt->xyz.y = rho * sin_a * (float)sin(b);
1632         pnt->xyz.x = rho * (float)cos(a);
1633 }
1634
1635 // draw a perspective bitmap based on angles and radius
1636 float p_phi = 10.0f;
1637 float p_theta = 10.0f;
1638 int g3_draw_perspective_bitmap(angles *a, float scale_x, float scale_y, int div_x, int div_y, uint tmap_flags)
1639 {
1640         vector s_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1641         vector t_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1642         vertex v[4];
1643         vertex *verts[4];
1644         matrix m, m_bank;
1645         int idx, s_idx; 
1646         int saved_zbuffer_mode; 
1647         float ui, vi;   
1648         angles bank_first;              
1649
1650         // cap division values
1651         // div_x = div_x > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_x;
1652         div_x = 1;
1653         div_y = div_y > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_y;  
1654
1655         // texture increment values
1656         ui = 1.0f / (float)div_x;
1657         vi = 1.0f / (float)div_y;       
1658
1659         // adjust for aspect ratio
1660         scale_x *= ((float)gr_screen.max_w / (float)gr_screen.max_h) + 0.55f;           // fudge factor
1661
1662         float s_phi = 0.5f + (((p_phi * scale_x) / 360.0f) / 2.0f);
1663         float s_theta = (((p_theta * scale_y) / 360.0f) / 2.0f);        
1664         float d_phi = -(((p_phi * scale_x) / 360.0f) / (float)(div_x));
1665         float d_theta = -(((p_theta * scale_y) / 360.0f) / (float)(div_y));
1666
1667         // bank matrix
1668         bank_first.p = 0.0f;
1669         bank_first.b = a->b;
1670         bank_first.h = 0.0f;
1671         vm_angles_2_matrix(&m_bank, &bank_first);
1672
1673         // convert angles to matrix
1674         float b_save = a->b;
1675         a->b = 0.0f;
1676         vm_angles_2_matrix(&m, a);
1677         a->b = b_save;  
1678
1679         // generate the bitmap points   
1680         for(idx=0; idx<=div_x; idx++){
1681                 for(s_idx=0; s_idx<=div_y; s_idx++){                            
1682                         // get world spherical coords                   
1683                         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));                     
1684                         
1685                         // bank the bitmap first
1686                         vm_vec_rotate(&t_points[idx][s_idx], &s_points[idx][s_idx], &m_bank);
1687
1688                         // rotate on the sphere
1689                         vm_vec_rotate(&s_points[idx][s_idx], &t_points[idx][s_idx], &m);                                        
1690                 }
1691         }               
1692
1693         // turn off zbuffering
1694         saved_zbuffer_mode = gr_zbuffer_get();
1695         gr_zbuffer_set(GR_ZBUFF_NONE);
1696
1697         // turn off culling
1698         gr_set_cull(0);
1699
1700         // draw the bitmap
1701         if(Fred_running){
1702                 tmap_flags &= ~(TMAP_FLAG_CORRECT);
1703         }
1704
1705         // render all polys
1706         for(idx=0; idx<div_x; idx++){
1707                 for(s_idx=0; s_idx<div_y; s_idx++){                                             
1708                         // stuff texture coords
1709                         v[0].u = ui * float(idx);
1710                         v[0].v = vi * float(s_idx);
1711                         
1712                         v[1].u = ui * float(idx+1);
1713                         v[1].v = vi * float(s_idx);
1714
1715                         v[2].u = ui * float(idx+1);
1716                         v[2].v = vi * float(s_idx+1);                                           
1717
1718                         v[3].u = ui * float(idx);
1719                         v[3].v = vi * float(s_idx+1);                   
1720
1721                         // poly 1
1722                         v[0].flags = 0;
1723                         v[1].flags = 0;
1724                         v[2].flags = 0;
1725                         verts[0] = &v[0];
1726                         verts[1] = &v[1];
1727                         verts[2] = &v[2];
1728                         g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);                      
1729                         g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx]);                    
1730                         g3_rotate_faraway_vertex(verts[2], &s_points[idx+1][s_idx+1]);                                          
1731                         g3_draw_poly(3, verts, tmap_flags);
1732
1733                         // poly 2                       
1734                         v[0].flags = 0;
1735                         v[2].flags = 0;
1736                         v[3].flags = 0;
1737                         verts[0] = &v[0];
1738                         verts[1] = &v[2];
1739                         verts[2] = &v[3];
1740                         g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);                      
1741                         g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx+1]);                  
1742                         g3_rotate_faraway_vertex(verts[2], &s_points[idx][s_idx+1]);                                            
1743                         g3_draw_poly(3, verts, tmap_flags);
1744                 }
1745         }
1746
1747         // turn on culling
1748         gr_set_cull(1);
1749
1750         // restore zbuffer
1751         gr_zbuffer_set(saved_zbuffer_mode);
1752
1753         // return
1754         return 1;
1755 }
1756
1757 // draw a 2d bitmap on a poly
1758 int g3_draw_2d_poly_bitmap(int x, int y, int w, int h, uint additional_tmap_flags)
1759 {
1760         int ret;
1761         int saved_zbuffer_mode;
1762         vertex v[4];
1763         vertex *vertlist[4] = { &v[0], &v[1], &v[2], &v[3] };
1764
1765 //      int bw, bh;
1766
1767         g3_start_frame(1);
1768
1769         // turn off zbuffering  
1770         saved_zbuffer_mode = gr_zbuffer_get();
1771         gr_zbuffer_set(GR_ZBUFF_NONE);  
1772
1773 //      bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &bw, &bh);
1774
1775         // stuff coords 
1776         v[0].sx = (float)x;
1777         v[0].sy = (float)y;     
1778         v[0].sw = 0.0f;
1779         v[0].u = 0.0f;
1780         v[0].v = 0.0f;
1781         v[0].flags = PF_PROJECTED;
1782         v[0].codes = 0;
1783
1784         v[1].sx = (float)(x + w);
1785         v[1].sy = (float)y;     
1786         v[1].sw = 0.0f;
1787         v[1].u = 1.0f;
1788         v[1].v = 0.0f;
1789         v[1].flags = PF_PROJECTED;
1790         v[1].codes = 0;
1791
1792         v[2].sx = (float)(x + w);
1793         v[2].sy = (float)(y + h);       
1794         v[2].sw = 0.0f;
1795         v[2].u = 1.0f;
1796         v[2].v = 1.0f;
1797         v[2].flags = PF_PROJECTED;
1798         v[2].codes = 0;
1799
1800         v[3].sx = (float)x;
1801         v[3].sy = (float)(y + h);       
1802         v[3].sw = 0.0f;
1803         v[3].u = 0.0f;
1804         v[3].v = 1.0f;
1805         v[3].flags = PF_PROJECTED;
1806         v[3].codes = 0;         
1807
1808         /*
1809         v[0].sx = (float)x;
1810         v[0].sy = (float)y;     
1811         v[0].sw = 0.0f;
1812         v[0].u = 0.5f / i2fl(bw);
1813         v[0].v = 0.5f / i2fl(bh);
1814         v[0].flags = PF_PROJECTED;
1815         v[0].codes = 0;
1816
1817         v[1].sx = (float)(x + w);
1818         v[1].sy = (float)y;     
1819         v[1].sw = 0.0f;
1820         v[1].u = 1.0f + (0.5f / i2fl(bw));
1821         v[1].v = 0.0f + (0.5f / i2fl(bh));
1822         v[1].flags = PF_PROJECTED;
1823         v[1].codes = 0;
1824
1825         v[2].sx = (float)(x + w);
1826         v[2].sy = (float)(y + h);       
1827         v[2].sw = 0.0f;
1828         v[2].u = 1.0f + (0.5f / i2fl(bw));
1829         v[2].v = 1.0f + (0.5f / i2fl(bh));
1830         v[2].flags = PF_PROJECTED;
1831         v[2].codes = 0;
1832
1833         v[3].sx = (float)x;
1834         v[3].sy = (float)(y + h);       
1835         v[3].sw = 0.0f;
1836         v[3].u = 0.0f + (0.5f / i2fl(bw));
1837         v[3].v = 1.0f + (0.5f / i2fl(bh));
1838         v[3].flags = PF_PROJECTED;
1839         v[3].codes = 0; 
1840         */
1841
1842         // set debrief  
1843         ret = g3_draw_poly_constant_sw(4, vertlist, TMAP_FLAG_TEXTURED | additional_tmap_flags, 0.1f);
1844
1845         g3_end_frame();
1846         
1847         gr_zbuffer_set(saved_zbuffer_mode);     
1848
1849         return ret;
1850 }
1851