]> icculus.org git repositories - taylor/freespace2.git/blob - src/render/3ddraw.cpp
use a better multi_sw_ok_to_commit() check
[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 = SDL_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 #ifdef MAKE_FS1
692         // Only seems to do anything in software mode in the retail version
693         if ( !Detail.alpha_effects ) {
694                 int ang;
695                 if ( angle < PI/2 )     {
696                         ang = 0;
697                 } else if ( angle < PI )        {
698                         ang = 1;
699                 } else if ( angle < PI+PI/2 )   {
700                         ang = 2;
701                 } else {
702                         ang = 3;
703                 }
704                 return g3_draw_bitmap( pnt, ang, rad, tmap_flags );
705         }
706 #endif
707
708         SDL_assert( G3_count == 1 );
709
710         angle+=Physics_viewer_bank;
711         if ( angle < 0.0f )
712                 angle += PI2;
713         else if ( angle > PI2 )
714                 angle -= PI2;
715 //      angle = 0.0f;
716                         
717         sa = (float)sin(angle);
718         ca = (float)cos(angle);
719
720         float width, height;
721
722         if ( tmap_flags & TMAP_FLAG_TEXTURED )  {
723                 int bw, bh;
724
725                 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
726
727                 if ( bw < bh )  {
728                         width = rad;
729                         height = width*i2fl(bh)/i2fl(bw);
730                 } else if ( bw > bh )   {
731                         height = rad;
732                         width = height*i2fl(bw)/i2fl(bh);
733                 } else {
734                         width = height = rad;
735                 }               
736         } else {
737                 width = height = rad;
738         }
739
740
741         v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
742         v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
743         v[0].z = pnt->z;
744         v[0].sw = 0.0f;
745         v[0].u = 0.0f;
746         v[0].v = 1.0f;
747
748         v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
749         v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
750         v[1].z = pnt->z;
751         v[1].sw = 0.0f;
752         v[1].u = 1.0f;
753         v[1].v = 1.0f;
754
755         v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
756         v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
757         v[2].z = pnt->z;
758         v[2].sw = 0.0f;
759         v[2].u = 1.0f;
760         v[2].v = 0.0f;
761
762         v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
763         v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
764         v[3].z = pnt->z;
765         v[3].sw = 0.0f;
766         v[3].u = 0.0f;
767         v[3].v = 0.0f;
768
769         ubyte codes_and=0xff;
770
771         float sw,z;
772         z = pnt->z - rad / 4.0f;
773         if ( z < 0.0f ) z = 0.0f;
774         sw = 1.0f / z;
775
776         for (i=0; i<4; i++ )    {
777                 //now code the four points
778                 codes_and &= g3_code_vertex(&v[i]);
779                 v[i].flags = 0;         // mark as not yet projected
780                 //g3_project_vertex(&v[i]);
781         }
782
783         if (codes_and)
784                 return 1;               //1 means off screen
785
786         // clip and draw it
787         g3_draw_poly_constant_sw(4, vertlist, tmap_flags, sw ); 
788         
789         return 0;
790 }
791
792 #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);
793 float g3_get_poly_area(int nv, vertex **pointlist)
794 {
795         int idx;
796         float total_area = 0.0f;        
797
798         // each triangle
799         for(idx=1; idx<nv-1; idx++){
800                 TRIANGLE_AREA(pointlist[0], pointlist[idx], pointlist[idx+1]);
801         }
802
803         // done
804         return total_area;
805 }
806
807 // Draw a polygon.  Same as g3_draw_poly, but it bashes sw to a constant value
808 // for all vertexes.  Needs to be done after clipping to get them all.
809 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
810 //returns 1 if off screen, 0 if drew
811 float g3_draw_poly_constant_sw_area(int nv, vertex **pointlist, uint tmap_flags, float constant_sw, float area)
812 {
813         int i;
814         vertex **bufptr;
815         ccodes cc;
816         float p_area = 0.0f;
817
818         SDL_assert( G3_count == 1 );
819
820         cc.vor = 0; cc.vand = 0xff;
821
822         bufptr = Vbuf0;
823
824         for (i=0;i<nv;i++) {
825                 vertex *p;
826
827                 p = bufptr[i] = pointlist[i];
828
829                 cc.vand &= p->codes;
830                 cc.vor  |= p->codes;
831         }
832
833         if (cc.vand){
834                 return 0.0f;    //all points off screen
835         }
836
837         if (cc.vor)     {
838                 SDL_assert( G3_count == 1 );
839
840                 bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
841
842                 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
843
844                         for (i=0;i<nv;i++) {
845                                 vertex *p = bufptr[i];
846
847                                 if (!(p->flags&PF_PROJECTED))
848                                         g3_project_vertex(p);
849                 
850                                 if (p->flags&PF_OVERFLOW) {
851                                         //Int3();               //should not overflow after clip
852                                         //printf( "overflow in must_clip_tmap_face\n" );
853                                         goto free_points;
854                                 }
855
856                                 p->sw = constant_sw;
857                         }
858
859                         // check area
860                         p_area = g3_get_poly_area(nv, bufptr);
861                         if(p_area > area){
862                                 return 0.0f;
863                         }
864
865                         gr_tmapper( nv, bufptr, tmap_flags );                   
866                 }
867
868 free_points:
869                 ;
870
871                 for (i=0;i<nv;i++){
872                         if (bufptr[i]->flags & PF_TEMP_POINT){
873                                 free_temp_point(bufptr[i]);
874                         }
875                 }
876         } else {
877                 //now make list of 2d coords (& check for overflow)
878
879                 for (i=0;i<nv;i++) {
880                         vertex *p = bufptr[i];
881
882                         if (!(p->flags&PF_PROJECTED))
883                                 g3_project_vertex(p);
884
885                         if (p->flags&PF_OVERFLOW) {                             
886                                 return 0.0f;
887                         }
888
889                         p->sw = constant_sw;
890                 }
891
892                 // check area
893                 p_area = g3_get_poly_area(nv, bufptr);
894                 if(p_area > area){
895                         return 0.0f;
896                 }               
897
898                 gr_tmapper( nv, bufptr, tmap_flags );           
899         }
900
901         // how much area we drew
902         return p_area;
903 }
904
905
906 //draws a bitmap with the specified 3d width & height 
907 //returns 1 if off screen, 0 if drew
908 float g3_draw_rotated_bitmap_area(vertex *pnt,float angle, float rad,uint tmap_flags, float area)
909 {
910         vertex v[4];
911         vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
912         float sa, ca;
913         int i;  
914
915         SDL_assert( G3_count == 1 );
916
917         angle+=Physics_viewer_bank;
918         if ( angle < 0.0f ){
919                 angle += PI2;
920         } else if ( angle > PI2 ) {
921                 angle -= PI2;
922         }
923                         
924         sa = (float)sin(angle);
925         ca = (float)cos(angle);
926
927         float width, height;
928
929         if ( tmap_flags & TMAP_FLAG_TEXTURED )  {
930                 int bw, bh;
931
932                 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
933
934                 if ( bw < bh )  {
935                         width = rad;
936                         height = width*i2fl(bh)/i2fl(bw);
937                 } else if ( bw > bh )   {
938                         height = rad;
939                         width = height*i2fl(bw)/i2fl(bh);
940                 } else {
941                         width = height = rad;
942                 }               
943         } else {
944                 width = height = rad;
945         }
946
947
948         v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
949         v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
950         v[0].z = pnt->z;
951         v[0].sw = 0.0f;
952         v[0].u = 0.0f;
953         v[0].v = 1.0f;
954
955         v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
956         v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
957         v[1].z = pnt->z;
958         v[1].sw = 0.0f;
959         v[1].u = 1.0f;
960         v[1].v = 1.0f;
961
962         v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
963         v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
964         v[2].z = pnt->z;
965         v[2].sw = 0.0f;
966         v[2].u = 1.0f;
967         v[2].v = 0.0f;
968
969         v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
970         v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
971         v[3].z = pnt->z;
972         v[3].sw = 0.0f;
973         v[3].u = 0.0f;
974         v[3].v = 0.0f;
975
976         ubyte codes_and=0xff;
977
978         float sw,z;
979         z = pnt->z - rad / 4.0f;
980         if ( z < 0.0f ) z = 0.0f;
981         sw = 1.0f / z;
982
983         for (i=0; i<4; i++ )    {
984                 //now code the four points
985                 codes_and &= g3_code_vertex(&v[i]);
986                 v[i].flags = 0;         // mark as not yet projected
987                 //g3_project_vertex(&v[i]);
988         }
989
990         if (codes_and){
991                 return 0.0f;
992         }
993
994         // clip and draw it
995         return g3_draw_poly_constant_sw_area(4, vertlist, tmap_flags, sw, area );               
996 }
997
998
999
1000 #include "2d.h"
1001 typedef struct horz_pt {
1002         float x, y;
1003         int edge;
1004 } horz_pt;
1005
1006 //draws a horizon. takes eax=sky_color, edx=ground_color
1007 void g3_draw_horizon_line()
1008 {
1009         //int sky_color,int ground_color
1010         int s1, s2;
1011         int cpnt;
1012         horz_pt horz_pts[4];            // 0 = left, 1 = right
1013 //      int top_color, bot_color;
1014 //      int color_swap;         //flag for if we swapped
1015 //      int sky_ground_flag;    //0=both, 1=all sky, -1=all gnd
1016
1017         vector horizon_vec;
1018         
1019         float up_right, down_right,down_left,up_left;
1020
1021 //      color_swap = 0;         //assume no swap
1022 //      sky_ground_flag = 0;    //assume both
1023
1024 //      if ( View_matrix.uvec.y < 0.0f )
1025 //              color_swap = 1;
1026 //      else if ( View_matrix.uvec.y == 0.0f )  {
1027 //              if ( View_matrix.uvec.xyz.x > 0.0f )
1028 //                      color_swap = 1;
1029 //      }
1030
1031 //      if (color_swap) {
1032 //              top_color  = ground_color;
1033 //              bot_color = sky_color;
1034 //      } else {
1035 //              top_color  = sky_color;
1036 //              bot_color = ground_color;
1037 //      }
1038
1039         SDL_assert( G3_count == 1 );
1040
1041
1042         //compute horizon_vector
1043         
1044         horizon_vec.xyz.x = Unscaled_matrix.v.rvec.xyz.y*Matrix_scale.xyz.y*Matrix_scale.xyz.z;
1045         horizon_vec.xyz.y = Unscaled_matrix.v.uvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.z;
1046         horizon_vec.xyz.z = Unscaled_matrix.v.fvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.y;
1047
1048         // now compute values & flag for 4 corners.
1049         up_right = horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1050         down_right = horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1051         down_left = -horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
1052     up_left = -horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
1053
1054         //check flags for all sky or all ground.
1055         if ( (up_right<0.0f)&&(down_right<0.0f)&&(down_left<0.0f)&&(up_left<0.0f) )     {
1056 //              mprintf(( "All ground.\n" ));
1057                 return;
1058         }
1059
1060         if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) )     {
1061 //              mprintf(( "All sky.\n" ));
1062                 return;
1063         }
1064
1065 //mprintf(( "Horizon vec = %.4f, %.4f, %.4f\n", horizon_vec.x, horizon_vec.y, horizon_vec.z ));
1066 //mprintf(( "%.4f, %.4f, %.4f, %.4f\n", up_right, down_right, down_left, up_left ));
1067
1068         
1069 //      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 ));
1070         // check for intesection with each of four edges & compute horizon line
1071         cpnt = 0;
1072         
1073         // check intersection with left edge
1074         s1 = up_left > 0.0f;
1075         s2 = down_left > 0.0f;
1076         if ( s1 != s2 ) {
1077                 horz_pts[cpnt].x = 0.0f;
1078                 horz_pts[cpnt].y = fl_abs(up_left * Canv_h2 / horizon_vec.xyz.y);
1079                 horz_pts[cpnt].edge = 0;
1080                 cpnt++;
1081         }
1082
1083         // check intersection with top edge
1084         s1 = up_left > 0.0f;
1085         s2 = up_right > 0.0f;
1086         if ( s1 != s2 ) {
1087                 horz_pts[cpnt].x = fl_abs(up_left * Canv_w2 / horizon_vec.xyz.x);
1088                 horz_pts[cpnt].y = 0.0f;
1089                 horz_pts[cpnt].edge = 1;
1090                 cpnt++;
1091         }
1092
1093         
1094         // check intersection with right edge
1095         s1 = up_right > 0.0f;
1096         s2 = down_right > 0.0f;
1097         if ( s1 != s2 ) {
1098                 horz_pts[cpnt].x = i2fl(Canvas_width)-1;
1099                 horz_pts[cpnt].y = fl_abs(up_right * Canv_h2 / horizon_vec.xyz.y);
1100                 horz_pts[cpnt].edge = 2;
1101                 cpnt++;
1102         }
1103         
1104         //check intersection with bottom edge
1105         s1 = down_right > 0.0f;
1106         s2 = down_left > 0.0f;
1107         if ( s1 != s2 ) {
1108                 horz_pts[cpnt].x = fl_abs(down_left * Canv_w2 / horizon_vec.xyz.x);
1109                 horz_pts[cpnt].y = i2fl(Canvas_height)-1;
1110                 horz_pts[cpnt].edge = 3;
1111                 cpnt++;
1112         }
1113
1114         if ( cpnt != 2 )        {
1115                 mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
1116                 return;
1117         }
1118
1119         //make sure first edge is left
1120
1121         if ( horz_pts[0].x > horz_pts[1].x )    {
1122                 horz_pt tmp;
1123                 tmp = horz_pts[0];
1124                 horz_pts[0] = horz_pts[1];
1125                 horz_pts[1] = tmp;
1126         }
1127
1128
1129         // draw from left to right.
1130         gr_line( fl2i(horz_pts[0].x),fl2i(horz_pts[0].y),fl2i(horz_pts[1].x),fl2i(horz_pts[1].y) );
1131         
1132 }
1133
1134
1135 /*
1136
1137 horizon_poly    dw      5 dup (?,?)     ;max of 5 points
1138
1139 ;for g3_compute_horz_vecs
1140 xfrac   fix     ?
1141 yfrac   fix     ?
1142
1143 vec_ptr dd      ?
1144 corner_num      dd      ?
1145
1146 ;for compute corner vec
1147 m13     fix     ?       ;m1-m3
1148 m46     fix     ?
1149 m79     fix     ?
1150 m56     fix     ?
1151 m23     fix     ?
1152 m89     fix     ?
1153
1154 _DATA   ends
1155
1156
1157 _TEXT   segment dword public USE32 'CODE'
1158
1159         extn    gr_setcolor_,gr_clear_canvas_
1160         extn    gr_upoly_tmap_
1161
1162 ;draw a polygon (one half of horizon) from the horizon line
1163 draw_horz_poly: lea     ebx,horizon_poly
1164
1165 ;copy horizon line as first points in poly
1166
1167         mov     eax,[edi]
1168         mov     [ebx],eax
1169         mov     eax,4[edi]
1170         mov     4[ebx],eax
1171
1172         mov     eax,[esi]
1173         mov     8[ebx],eax
1174         mov     eax,4[esi]
1175         mov     12[ebx],eax
1176
1177 ;add corners to polygon
1178
1179         mov     eax,8[esi]      ;edge number of start edge
1180
1181         mov     ecx,8[edi]      ;edge number of end point
1182         sub     ecx,eax ;number of edges
1183         jns     edgenum_ok
1184         add     ecx,4
1185 edgenum_ok:
1186         mov     edx,ecx ;save count
1187         sal     eax,3   ;edge * 8
1188         lea     esi,corners[eax]        ;first corner
1189         lea     edi,16[ebx]     ;rest of poly
1190 corner_loop:    movsd
1191         movsd           ;copy a corner
1192         cmp     esi,offset corners+8*4  ;end of list?
1193         jne     no_wrap
1194         lea     esi,corners
1195 no_wrap:        loop    corner_loop
1196
1197 ;now draw the polygon
1198         mov     eax,edx ;get corner count
1199         add     eax,2   ;..plus horz line end points
1200         lea     edx,horizon_poly        ;get the points
1201 ;;      call    gr_poly_        ;draw it!
1202  call gr_upoly_tmap_
1203         ret
1204
1205 ;return information on the polygon that is the sky. 
1206 ;takes ebx=ptr to x,y pairs, ecx=ptr to vecs for each point
1207 ;returns eax=number of points
1208 ;IMPORTANT: g3_draw_horizon() must be called before this routine.
1209 g3_compute_sky_polygon:
1210         test    sky_ground_flag,-1      ;what was drawn
1211         js      was_all_ground
1212         jg      was_all_sky     
1213
1214         pushm   ebx,ecx,edx,esi,edi
1215
1216         lea     esi,left_point
1217         lea     edi,right_point
1218         test    color_swap,-1
1219         jz      no_swap_ends
1220         xchg    esi,edi ;sky isn't top
1221 no_swap_ends:
1222
1223 ;copy horizon line as first points in poly
1224
1225         mov     eax,[edi]       ;copy end point
1226         mov     [ebx],eax
1227         mov     eax,4[edi]
1228         mov     4[ebx],eax
1229
1230         mov     eax,[esi]       ;copy start point
1231         mov     8[ebx],eax
1232         mov     eax,4[esi]
1233         mov     12[ebx],eax
1234
1235         pushm   ebx,ecx
1236         push    edi     ;save end point
1237         push    esi     ;save start point
1238         mov     esi,edi ;end point is first point
1239         mov     edi,ecx ;dest buffer
1240         call    compute_horz_end_vec
1241
1242         pop     esi     ;get back start point
1243         add     edi,12  ;2nd vec
1244         call    compute_horz_end_vec
1245
1246         pop     edi     ;get back end point
1247         popm    ebx,ecx
1248         add     ebx,16  ;past two x,y pairs
1249         add     ecx,24  ;past two vectors
1250
1251         mov     vec_ptr,ecx
1252
1253 ;add corners to polygon
1254
1255         mov     eax,8[esi]      ;edge number of start edge
1256         mov     corner_num,eax
1257
1258         mov     ecx,8[edi]      ;edge number of end point
1259         sub     ecx,eax ;number of edges
1260         jns     edgenum_ok2
1261         add     ecx,4
1262 edgenum_ok2:
1263         push    ecx     ;save count
1264         sal     eax,3   ;edge * 8
1265         lea     esi,corners[eax]        ;first corner
1266         mov     edi,ebx ;rest of poly 2d points
1267 corner_loop2:
1268         movsd
1269         movsd           ;copy a corner
1270         cmp     esi,offset corners+8*4  ;end of list?
1271         jne     no_wrap2
1272         lea     esi,corners
1273 no_wrap2:
1274         pushm   ecx,esi,edi
1275         mov     edi,vec_ptr
1276         mov     eax,corner_num
1277         call    compute_corner_vec
1278         add     vec_ptr,12
1279         inc     corner_num
1280         popm    ecx,esi,edi
1281
1282         loop    corner_loop2
1283
1284 ;now return with count
1285         pop     eax     ;get corner count
1286         add     eax,2   ;..plus horz line end points
1287
1288         popm    ebx,ecx,edx,esi,edi
1289
1290         ret
1291
1292 ;we drew all ground, so there was no horizon drawn
1293 was_all_ground: xor     eax,eax ;no points in poly
1294         ret
1295
1296 ;we drew all sky, so find 4 corners
1297 was_all_sky:    pushm   ebx,ecx,edx,esi,edi
1298         push    ecx
1299         lea     esi,corners
1300         mov     edi,ebx
1301         mov     ecx,8
1302         rep     movsd
1303         pop     edi
1304
1305         mov     ecx,4
1306         xor     eax,eax ;start corner 0
1307 sky_loop:       pushm   eax,ecx,edi
1308         call    compute_corner_vec
1309         popm    eax,ecx,edi
1310         add     edi,12
1311         inc     eax
1312         loop    sky_loop
1313         mov     eax,4   ;4 corners
1314         popm    ebx,ecx,edx,esi,edi
1315         ret
1316
1317 ;compute vector describing horizon intersection with a point.
1318 ;takes esi=2d point, edi=vec. trashes eax,ebx,ecx,edx
1319 compute_horz_end_vec:
1320
1321 ;compute rotated x/z & y/z ratios
1322
1323         mov     eax,[esi]       ;get x coord
1324         sub     eax,Canv_w2
1325         fixdiv  Canv_w2
1326         mov     xfrac,eax       ;save
1327
1328         mov     eax,4[esi]      ;get y coord
1329         sub     eax,Canv_h2
1330         fixdiv  Canv_h2
1331         neg     eax     ;y inversion
1332         mov     yfrac,eax       ;save
1333
1334 ;compute fraction unrotated x/z
1335
1336         mov     eax,xfrac
1337         add     eax,yfrac
1338         mov     ecx,eax ;save
1339         fixmul  View_matrix.m9
1340         sub     eax,View_matrix.m7
1341         sub     eax,View_matrix.m8
1342         mov     ebx,eax ;save numerator
1343
1344         mov     eax,ecx
1345         fixmul  View_matrix.m3
1346         mov     ecx,eax
1347         mov     eax,View_matrix.m1
1348         add     eax,View_matrix.m2
1349         sub     eax,ecx
1350
1351 ;now eax/ebx = z/x. do divide in way to give result < 0
1352
1353         pushm   eax,ebx
1354         abs_eax
1355         xchg    eax,ebx
1356         abs_eax
1357         cmp     eax,ebx ;which is bigger?
1358         popm    eax,ebx
1359         jl      do_xz
1360
1361 ;x is bigger, so do as z/x
1362
1363         fixdiv  ebx
1364         
1365 ;now eax = z/x ratio.  Compute vector by normalizing and correcting sign
1366
1367         push    eax     ;save ratio
1368
1369         imul    eax     ;compute z*z
1370         inc     edx     ;+ x*x (x==1)
1371         call    quad_sqrt
1372
1373         mov     ecx,eax ;mag in ecx
1374         pop     eax     ;get ratio, x part
1375
1376         fixdiv  ecx
1377         mov     [edi].z,eax
1378
1379         mov     eax,f1_0
1380         fixdiv  ecx
1381
1382         mov     [edi].x,eax
1383
1384         jmp     finish_end
1385
1386 ;z is bigger, so do as x/z
1387 do_xz:
1388         xchg    eax,ebx
1389         fixdiv  ebx
1390         
1391 ;now eax = x/z ratio.  Compute vector by normalizing and correcting sign
1392
1393         push    eax     ;save ratio
1394
1395         imul    eax     ;compute x*x
1396         inc     edx     ;+ z*z (z==1)
1397         call    quad_sqrt
1398
1399         mov     ecx,eax ;mag in ecx
1400         pop     eax     ;get ratio, x part
1401
1402         fixdiv  ecx
1403         mov     [edi].x,eax
1404
1405         mov     eax,f1_0
1406         fixdiv  ecx
1407
1408         mov     [edi].z,eax
1409
1410 finish_end:     xor     eax,eax ;y = 0
1411         mov     [edi].y,eax
1412
1413 ;now make sure that this vector is in front of you, not behind
1414
1415         mov     eax,[edi].x
1416         imul    View_matrix.m3
1417         mov     ebx,eax
1418         mov     ecx,edx
1419         mov     eax,[edi].z
1420         imul    View_matrix.m9
1421         add     eax,ebx
1422         adc     edx,ecx
1423         jns     vec_ok  ;has positive z, ok
1424
1425 ;z is neg, flip vector
1426
1427         neg     [edi].x
1428         neg     [edi].z
1429 vec_ok:
1430         ret
1431
1432 MIN_DEN equ 7fffh
1433
1434 sub2    macro   dest,src
1435         mov     eax,src
1436         sal     eax,1
1437         sub     dest,eax
1438         endm
1439
1440 ;compute vector decribing a corner of the screen.
1441 ;takes edi=vector, eax=corner num
1442 compute_corner_vec:
1443
1444         cmp     eax,4
1445         jl      num_ok
1446         sub     eax,4
1447 num_ok:
1448
1449 ;compute all deltas
1450         mov     ebx,View_matrix.m1
1451         mov     ecx,View_matrix.m4
1452         mov     edx,View_matrix.m7
1453
1454         or      eax,eax
1455         jz      neg_x
1456         cmp     eax,3
1457         jne     no_neg_x
1458 neg_x:
1459         neg     ebx
1460         neg     ecx
1461         neg     edx
1462 no_neg_x:       
1463         sub     ebx,View_matrix.m3
1464         mov     m13,ebx ;m1-m3
1465         sub     ecx,View_matrix.m6
1466         mov     m46,ecx ;m4-m6
1467         sub     edx,View_matrix.m9
1468         mov     m79,edx ;m7-m9
1469
1470         mov     ebx,View_matrix.m5
1471         mov     ecx,View_matrix.m2
1472         mov     edx,View_matrix.m8
1473
1474         cmp     eax,2
1475         jl      no_neg_y
1476 neg_y:
1477         neg     ebx
1478         neg     ecx
1479         neg     edx
1480 no_neg_y:       
1481         sub     ebx,View_matrix.m6
1482         mov     m56,ebx ;m5-m6
1483         sub     ecx,View_matrix.m3
1484         mov     m23,ecx ;m2-m3
1485         sub     edx,View_matrix.m9
1486         mov     m89,edx ;m8-m9
1487
1488 ;compute x/z ratio
1489
1490 ;compute denomonator
1491
1492         mov     eax,m46
1493         fixmul  m23
1494         mov     ebx,eax ;save
1495
1496         mov     eax,m56
1497         fixmul  m13
1498         sub     eax,ebx ;eax = denominator
1499
1500 ;now we have the denominator.  If it is too small, try x/y, z/y or z/x, y/x
1501
1502         mov     ecx,eax ;save den
1503
1504         abs_eax
1505         cmp     eax,MIN_DEN
1506         jl      z_too_small
1507
1508 z_too_small:
1509
1510 ;now do x/z numerator
1511
1512         mov     eax,m79
1513         fixmul  m56     ;* (m5-m6)
1514         mov     ebx,eax
1515
1516         mov     eax,m89
1517         fixmul  m46     ;* (m4-m6)
1518         sub     eax,ebx
1519
1520 ;now, eax/ecx = x/z ratio
1521
1522         fixdiv  ecx     ;eax = x/z
1523
1524         mov     [edi].x,eax     ;save x
1525
1526 ;now do y/z
1527
1528         mov     eax,m89
1529         fixmul  m13
1530         mov     ebx,eax
1531
1532         mov     eax,m79
1533         fixmul  m23
1534         sub     eax,ebx
1535
1536 ;now eax/ecx = y/z ratio
1537
1538         fixdiv  ecx
1539
1540         mov     [edi].y,eax
1541
1542         mov     [edi].z,f1_0
1543
1544         mov     esi,edi
1545         call    vm_vec_normalize
1546
1547 ;make sure this vec is pointing in right direction
1548
1549         lea     edi,View_matrix.fvec
1550         call    vm_vec_dotprod
1551         or      eax,eax ;check sign
1552         jg      vec_sign_ok
1553
1554         neg     [esi].x
1555         neg     [esi].y
1556         neg     [esi].z
1557 vec_sign_ok:
1558
1559         ret
1560
1561
1562 _TEXT   ends
1563
1564         end
1565
1566 */
1567
1568
1569 // Draws a polygon always facing the viewer.
1570 // compute the corners of a rod.  fills in vertbuf.
1571 // Verts has any needs uv's or l's or can be NULL if none needed.
1572 int g3_draw_rod(vector *p0,float width1,vector *p1,float width2, vertex * verts, uint tmap_flags)
1573 {
1574         vector uvec, fvec, rvec, center;
1575
1576         vm_vec_sub( &fvec, p0, p1 );
1577         vm_vec_normalize_safe( &fvec );
1578
1579         vm_vec_avg( &center, p0, p1 );
1580         vm_vec_sub( &rvec, &Eye_position, &center );
1581         vm_vec_normalize( &rvec );
1582
1583         vm_vec_crossprod(&uvec,&fvec,&rvec);
1584                         
1585         //normalize new perpendicular vector
1586         vm_vec_normalize(&uvec);
1587          
1588         //now recompute right vector, in case it wasn't entirely perpendiclar
1589         vm_vec_crossprod(&rvec,&uvec,&fvec);
1590
1591         // Now have uvec, which is up vector and rvec which is the normal
1592         // of the face.
1593
1594         int i;
1595         vector vecs[4];
1596         vertex pts[4];
1597         vertex *ptlist[4] = { &pts[3], &pts[2], &pts[1], &pts[0] };
1598
1599         vm_vec_scale_add( &vecs[0], p0, &uvec, width1/2.0f );
1600         vm_vec_scale_add( &vecs[1], p1, &uvec, width2/2.0f );
1601         vm_vec_scale_add( &vecs[2], p1, &uvec, -width2/2.0f );
1602         vm_vec_scale_add( &vecs[3], p0, &uvec, -width1/2.0f );
1603         
1604         for (i=0; i<4; i++ )    {
1605                 if ( verts )    {
1606                         pts[i] = verts[i];
1607                 }
1608                 g3_rotate_vertex( &pts[i], &vecs[i] );
1609         }
1610
1611         return g3_draw_poly(4,ptlist,tmap_flags);
1612 }
1613
1614 // draw a perspective bitmap based on angles and radius
1615 vector g3_square[4] = {
1616         { { { -1.0f, -1.0f, 20.0f } } },
1617         { { { -1.0f, 1.0f, 20.0f } } },
1618         { { { 1.0f, 1.0f, 20.0f } } },
1619         { { { 1.0f, -1.0f, 20.0f } } }
1620 };
1621
1622 #define MAX_PERSPECTIVE_DIVISIONS                       5                               // should never even come close to this limit
1623
1624 void stars_project_2d_onto_sphere( vector *pnt, float rho, float phi, float theta )
1625 {               
1626         float a = 3.14159f * phi;
1627         float b = 6.28318f * theta;
1628         float sin_a = (float)sin(a);    
1629
1630         // coords
1631         pnt->xyz.z = rho * sin_a * (float)cos(b);
1632         pnt->xyz.y = rho * sin_a * (float)sin(b);
1633         pnt->xyz.x = rho * (float)cos(a);
1634 }
1635
1636 // draw a perspective bitmap based on angles and radius
1637 float p_phi = 10.0f;
1638 float p_theta = 10.0f;
1639 int g3_draw_perspective_bitmap(angles *a, float scale_x, float scale_y, int div_x, int div_y, uint tmap_flags)
1640 {
1641         vector s_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1642         vector t_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1643         vertex v[4];
1644         vertex *verts[4];
1645         matrix m, m_bank;
1646         int idx, s_idx; 
1647         int saved_zbuffer_mode; 
1648         float ui, vi;   
1649         angles bank_first;              
1650
1651         // cap division values
1652         // div_x = div_x > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_x;
1653         div_x = 1;
1654         div_y = div_y > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_y;  
1655
1656         // texture increment values
1657         ui = 1.0f / (float)div_x;
1658         vi = 1.0f / (float)div_y;       
1659
1660         // adjust for aspect ratio
1661         scale_x *= ((float)gr_screen.max_w / (float)gr_screen.max_h) + 0.55f;           // fudge factor
1662
1663         float s_phi = 0.5f + (((p_phi * scale_x) / 360.0f) / 2.0f);
1664         float s_theta = (((p_theta * scale_y) / 360.0f) / 2.0f);        
1665         float d_phi = -(((p_phi * scale_x) / 360.0f) / (float)(div_x));
1666         float d_theta = -(((p_theta * scale_y) / 360.0f) / (float)(div_y));
1667
1668         // bank matrix
1669         bank_first.p = 0.0f;
1670         bank_first.b = a->b;
1671         bank_first.h = 0.0f;
1672         vm_angles_2_matrix(&m_bank, &bank_first);
1673
1674         // convert angles to matrix
1675         float b_save = a->b;
1676         a->b = 0.0f;
1677         vm_angles_2_matrix(&m, a);
1678         a->b = b_save;  
1679
1680         // generate the bitmap points   
1681         for(idx=0; idx<=div_x; idx++){
1682                 for(s_idx=0; s_idx<=div_y; s_idx++){                            
1683                         // get world spherical coords                   
1684                         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));                     
1685                         
1686                         // bank the bitmap first
1687                         vm_vec_rotate(&t_points[idx][s_idx], &s_points[idx][s_idx], &m_bank);
1688
1689                         // rotate on the sphere
1690                         vm_vec_rotate(&s_points[idx][s_idx], &t_points[idx][s_idx], &m);                                        
1691                 }
1692         }               
1693
1694         // turn off zbuffering
1695         saved_zbuffer_mode = gr_zbuffer_get();
1696         gr_zbuffer_set(GR_ZBUFF_NONE);
1697
1698         // turn off culling
1699         gr_set_cull(0);
1700
1701         // draw the bitmap
1702         if(Fred_running){
1703                 tmap_flags &= ~(TMAP_FLAG_CORRECT);
1704         }
1705
1706         // render all polys
1707         for(idx=0; idx<div_x; idx++){
1708                 for(s_idx=0; s_idx<div_y; s_idx++){                                             
1709                         // stuff texture coords
1710                         v[0].u = ui * float(idx);
1711                         v[0].v = vi * float(s_idx);
1712                         
1713                         v[1].u = ui * float(idx+1);
1714                         v[1].v = vi * float(s_idx);
1715
1716                         v[2].u = ui * float(idx+1);
1717                         v[2].v = vi * float(s_idx+1);                                           
1718
1719                         v[3].u = ui * float(idx);
1720                         v[3].v = vi * float(s_idx+1);                   
1721
1722                         // poly 1
1723                         v[0].flags = 0;
1724                         v[1].flags = 0;
1725                         v[2].flags = 0;
1726                         verts[0] = &v[0];
1727                         verts[1] = &v[1];
1728                         verts[2] = &v[2];
1729                         g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);                      
1730                         g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx]);                    
1731                         g3_rotate_faraway_vertex(verts[2], &s_points[idx+1][s_idx+1]);                                          
1732                         g3_draw_poly(3, verts, tmap_flags);
1733
1734                         // poly 2                       
1735                         v[0].flags = 0;
1736                         v[2].flags = 0;
1737                         v[3].flags = 0;
1738                         verts[0] = &v[0];
1739                         verts[1] = &v[2];
1740                         verts[2] = &v[3];
1741                         g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);                      
1742                         g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx+1]);                  
1743                         g3_rotate_faraway_vertex(verts[2], &s_points[idx][s_idx+1]);                                            
1744                         g3_draw_poly(3, verts, tmap_flags);
1745                 }
1746         }
1747
1748         // turn on culling
1749         gr_set_cull(1);
1750
1751         // restore zbuffer
1752         gr_zbuffer_set(saved_zbuffer_mode);
1753
1754         // return
1755         return 1;
1756 }
1757
1758 // draw a 2d bitmap on a poly
1759 int g3_draw_2d_poly_bitmap(int x, int y, int w, int h, uint additional_tmap_flags)
1760 {
1761         int ret;
1762         int saved_zbuffer_mode;
1763         vertex v[4];
1764         vertex *vertlist[4] = { &v[0], &v[1], &v[2], &v[3] };
1765
1766 //      int bw, bh;
1767
1768         g3_start_frame(1);
1769
1770         // turn off zbuffering  
1771         saved_zbuffer_mode = gr_zbuffer_get();
1772         gr_zbuffer_set(GR_ZBUFF_NONE);  
1773
1774 //      bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &bw, &bh);
1775
1776         // stuff coords 
1777         v[0].sx = (float)x;
1778         v[0].sy = (float)y;     
1779         v[0].sw = 0.0f;
1780         v[0].u = 0.0f;
1781         v[0].v = 0.0f;
1782         v[0].flags = PF_PROJECTED;
1783         v[0].codes = 0;
1784
1785         v[1].sx = (float)(x + w);
1786         v[1].sy = (float)y;     
1787         v[1].sw = 0.0f;
1788         v[1].u = 1.0f;
1789         v[1].v = 0.0f;
1790         v[1].flags = PF_PROJECTED;
1791         v[1].codes = 0;
1792
1793         v[2].sx = (float)(x + w);
1794         v[2].sy = (float)(y + h);       
1795         v[2].sw = 0.0f;
1796         v[2].u = 1.0f;
1797         v[2].v = 1.0f;
1798         v[2].flags = PF_PROJECTED;
1799         v[2].codes = 0;
1800
1801         v[3].sx = (float)x;
1802         v[3].sy = (float)(y + h);       
1803         v[3].sw = 0.0f;
1804         v[3].u = 0.0f;
1805         v[3].v = 1.0f;
1806         v[3].flags = PF_PROJECTED;
1807         v[3].codes = 0;         
1808
1809         /*
1810         v[0].sx = (float)x;
1811         v[0].sy = (float)y;     
1812         v[0].sw = 0.0f;
1813         v[0].u = 0.5f / i2fl(bw);
1814         v[0].v = 0.5f / i2fl(bh);
1815         v[0].flags = PF_PROJECTED;
1816         v[0].codes = 0;
1817
1818         v[1].sx = (float)(x + w);
1819         v[1].sy = (float)y;     
1820         v[1].sw = 0.0f;
1821         v[1].u = 1.0f + (0.5f / i2fl(bw));
1822         v[1].v = 0.0f + (0.5f / i2fl(bh));
1823         v[1].flags = PF_PROJECTED;
1824         v[1].codes = 0;
1825
1826         v[2].sx = (float)(x + w);
1827         v[2].sy = (float)(y + h);       
1828         v[2].sw = 0.0f;
1829         v[2].u = 1.0f + (0.5f / i2fl(bw));
1830         v[2].v = 1.0f + (0.5f / i2fl(bh));
1831         v[2].flags = PF_PROJECTED;
1832         v[2].codes = 0;
1833
1834         v[3].sx = (float)x;
1835         v[3].sy = (float)(y + h);       
1836         v[3].sw = 0.0f;
1837         v[3].u = 0.0f + (0.5f / i2fl(bw));
1838         v[3].v = 1.0f + (0.5f / i2fl(bh));
1839         v[3].flags = PF_PROJECTED;
1840         v[3].codes = 0; 
1841         */
1842
1843         // set debrief  
1844         ret = g3_draw_poly_constant_sw(4, vertlist, TMAP_FLAG_TEXTURED | additional_tmap_flags, 0.1f);
1845
1846         g3_end_frame();
1847         
1848         gr_zbuffer_set(saved_zbuffer_mode);     
1849
1850         return ret;
1851 }
1852