2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Render/3ddraw.cpp $
15 * 3D rendering primitives
18 * Revision 1.5 2002/06/17 06:33:10 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.4 2002/06/09 04:41:25 relnev
22 * added copyright header
24 * Revision 1.3 2002/05/07 03:16:51 theoddone33
25 * The Great Newline Fix
27 * Revision 1.2 2002/05/03 13:34:33 theoddone33
30 * Revision 1.1.1.1 2002/05/03 03:28:10 root
34 * 18 9/06/99 3:23p Andsager
35 * Make fireball and weapon expl ani LOD choice look at resolution of the
38 * 17 8/27/99 9:07p Dave
39 * LOD explosions. Improved beam weapon accuracy.
41 * 16 7/29/99 12:05a Dave
42 * Nebula speed optimizations.
44 * 15 7/13/99 1:16p Dave
45 * 32 bit support. Whee!
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.
51 * 13 6/29/99 10:35a Dave
52 * Interface polygon bitmaps! Whee!
54 * 12 6/22/99 7:03p Dave
55 * New detail options screen.
57 * 11 6/16/99 4:06p Dave
58 * New pilot info popup. Added new draw-bitmap-as-poly function.
60 * 10 6/08/99 5:17p Dave
61 * Fixed up perspective bitmap drawing.
63 * 9 6/03/99 6:37p Dave
64 * More TNT fun. Made perspective bitmaps more flexible.
66 * 8 5/28/99 1:58p Dave
67 * Fixed problem with overwriting bank value drawing perspective bitmaps.
69 * 7 5/28/99 1:45p Dave
70 * Fixed up perspective bitmap drawing.
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.
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.
81 * 4 3/09/99 6:24p Dave
82 * More work on object update revamping. Identified several sources of
83 * unnecessary bandwidth.
85 * 3 2/11/99 3:08p Dave
86 * PXO refresh button. Very preliminary squad war support.
88 * 2 10/07/98 10:53a Dave
91 * 1 10/07/98 10:51a Dave
93 * 37 3/22/98 2:34p John
94 * If alpha effects is on lowest detail level, draw rotated bitmaps as
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.
101 * 35 3/04/98 9:29a John
102 * Made rotated bitmaps force all sw's to the same value after clipping.
104 * 34 3/03/98 6:59p John
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
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.
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).
119 * 30 12/30/97 6:44p John
120 * Made g3_Draw_bitmap functions account for aspect of bitmap.
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.
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.
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
135 * 26 10/20/97 4:49p John
136 * added weapon trails.
137 * added facing bitmap code to 3d lib.
139 * 25 10/03/97 9:10a John
140 * added better antialiased line drawer
142 * 24 9/09/97 3:39p Sandeep
143 * warning level 4 bugs
145 * 23 7/11/97 11:54a John
146 * added rotated 3d bitmaps.
148 * 22 5/07/97 2:59p John
149 * Initial rev of D3D texturing.
151 * 21 4/29/97 9:55a John
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.
158 * 19 3/06/97 5:36p Mike
159 * Change vec_normalize_safe() back to vec_normalize().
160 * Spruce up docking a bit.
162 * 18 3/06/97 10:56a Mike
163 * Write error checking version of vm_vec_normalize().
164 * Fix resultant problems.
166 * 17 2/26/97 5:24p John
167 * Added g3_draw_sphere_ez
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
176 #include "3dinternal.h"
180 #include "floating.h"
181 #include "physics.h" // For Physics_viewer_bank for g3_draw_rotated_bitmap
183 #include "systemvars.h"
184 #include "alphacolors.h"
188 //deal with a clipped line
189 int must_clip_line(vertex *p0,vertex *p1,ubyte codes_or, uint flags)
193 clip_line(&p0,&p1,codes_or, flags);
195 if (p0->codes & p1->codes) goto free_points;
197 codes_or = (unsigned char)(p0->codes | p1->codes);
199 if (codes_or & CC_BEHIND) goto free_points;
201 if (!(p0->flags&PF_PROJECTED))
202 g3_project_vertex(p0);
204 if (p0->flags&PF_OVERFLOW) goto free_points;
206 if (!(p1->flags&PF_PROJECTED))
207 g3_project_vertex(p1);
209 if (p1->flags&PF_OVERFLOW) goto free_points;
211 //gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
212 // gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
221 if (p0->flags & PF_TEMP_POINT)
224 if (p1->flags & PF_TEMP_POINT)
230 //draws a line. takes two points. returns true if drew
231 int g3_draw_line(vertex *p0,vertex *p1)
235 SDL_assert( G3_count == 1 );
237 if (p0->codes & p1->codes)
240 codes_or = (unsigned char)(p0->codes | p1->codes);
242 if (codes_or & CC_BEHIND)
243 return must_clip_line(p0,p1,codes_or,0);
245 if (!(p0->flags&PF_PROJECTED))
246 g3_project_vertex(p0);
248 if (p0->flags&PF_OVERFLOW)
250 return must_clip_line(p0,p1,codes_or,0);
253 if (!(p1->flags&PF_PROJECTED))
254 g3_project_vertex(p1);
256 if (p1->flags&PF_OVERFLOW)
258 return must_clip_line(p0,p1,codes_or,0);
261 // gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
262 // gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
269 //returns true if a plane is facing the viewer. takes the unrotated surface
270 //normal of the plane, and a point on it. The normal need not be normalized
271 int g3_check_normal_facing(vector *v,vector *norm)
275 SDL_assert( G3_count == 1 );
277 vm_vec_sub(&tempv,&View_position,v);
279 return (vm_vec_dot(&tempv,norm) > 0.0f);
282 int do_facing_check(vector *norm,vertex **vertlist,vector *p)
284 SDL_assert( G3_count == 1 );
286 if (norm) { //have normal
288 SDL_assert(norm->xyz.x || norm->xyz.y || norm->xyz.z);
290 return g3_check_normal_facing(p,norm);
292 else { //normal not specified, so must compute
296 //get three points (rotated) and compute normal
298 vm_vec_perp(&tempv,(vector *)&vertlist[0]->x,(vector *)&vertlist[1]->x,(vector *)&vertlist[2]->x);
300 return (vm_vec_dot(&tempv,(vector *)&vertlist[1]->x ) < 0.0);
304 //like g3_draw_poly(), but checks to see if facing. If surface normal is
305 //NULL, this routine must compute it, which will be slow. It is better to
306 //pre-compute the normal, and pass it to this function. When the normal
307 //is passed, this function works like g3_check_normal_facing() plus
309 //returns -1 if not facing, 1 if off screen, 0 if drew
310 int g3_draw_poly_if_facing(int nv,vertex **pointlist,uint tmap_flags,vector *norm,vector *pnt)
312 SDL_assert( G3_count == 1 );
314 if (do_facing_check(norm,pointlist,pnt))
315 return g3_draw_poly(nv,pointlist,tmap_flags);
321 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
322 //returns 1 if off screen, 0 if drew
323 int g3_draw_poly(int nv,vertex **pointlist,uint tmap_flags)
329 SDL_assert( G3_count == 1 );
331 cc.vor = 0; cc.vand = 0xff;
338 p = bufptr[i] = pointlist[i];
345 return 1; //all points off screen
348 SDL_assert( G3_count == 1 );
350 bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tmap_flags);
352 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
355 vertex *p = bufptr[i];
357 if (!(p->flags&PF_PROJECTED))
358 g3_project_vertex(p);
360 if (p->flags&PF_OVERFLOW) {
361 //Int3(); //should not overflow after clip
362 //printf( "overflow in must_clip_tmap_face\n" );
367 gr_tmapper( nv, bufptr, tmap_flags );
374 if (bufptr[i]->flags & PF_TEMP_POINT)
375 free_temp_point(bufptr[i]);
378 //now make list of 2d coords (& check for overflow)
381 vertex *p = bufptr[i];
383 if (!(p->flags&PF_PROJECTED))
384 g3_project_vertex(p);
386 if (p->flags&PF_OVERFLOW) {
387 //Int3(); //should not overflow after clip
388 //printf( "3d: Point overflowed, but flags say OK!\n" );
394 gr_tmapper( nv, bufptr, tmap_flags );
396 return 0; //say it drew
401 // Draw a polygon. Same as g3_draw_poly, but it bashes sw to a constant value
402 // for all vertexes. Needs to be done after clipping to get them all.
403 //Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
404 //returns 1 if off screen, 0 if drew
405 int g3_draw_poly_constant_sw(int nv,vertex **pointlist,uint tmap_flags, float constant_sw)
411 SDL_assert( G3_count == 1 );
413 cc.vor = 0; cc.vand = 0xff;
420 p = bufptr[i] = pointlist[i];
427 return 1; //all points off screen
430 SDL_assert( G3_count == 1 );
432 bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
434 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
437 vertex *p = bufptr[i];
439 if (!(p->flags&PF_PROJECTED))
440 g3_project_vertex(p);
442 if (p->flags&PF_OVERFLOW) {
443 //Int3(); //should not overflow after clip
444 //printf( "overflow in must_clip_tmap_face\n" );
451 gr_tmapper( nv, bufptr, tmap_flags );
453 // draw lines connecting the faces
455 gr_set_color_fast(&Color_bright_green);
456 for(i=0; i<nv-1; i++){
457 g3_draw_line(bufptr[i], bufptr[i+1]);
459 g3_draw_line(bufptr[0], bufptr[i]);
467 if (bufptr[i]->flags & PF_TEMP_POINT){
468 free_temp_point(bufptr[i]);
472 //now make list of 2d coords (& check for overflow)
475 vertex *p = bufptr[i];
477 if (!(p->flags&PF_PROJECTED))
478 g3_project_vertex(p);
480 if (p->flags&PF_OVERFLOW) {
481 //Int3(); //should not overflow after clip
482 //printf( "3d: Point overflowed, but flags say OK!\n" );
489 gr_tmapper( nv, bufptr, tmap_flags );
491 // draw lines connecting the faces
493 gr_set_color_fast(&Color_bright_green);
494 for(i=0; i<nv-1; i++){
495 g3_draw_line(bufptr[i], bufptr[i+1]);
497 g3_draw_line(bufptr[0], bufptr[i]);
500 return 0; //say it drew
503 //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
504 //radius, but not to the distance from the eye
505 int g3_draw_sphere(vertex *pnt,float rad)
507 SDL_assert( G3_count == 1 );
509 if (! (pnt->codes & CC_BEHIND)) {
511 if (! (pnt->flags & PF_PROJECTED))
512 g3_project_vertex(pnt);
514 if (! (pnt->codes & PF_OVERFLOW)) {
517 r2 = rad*Matrix_scale.xyz.x;
521 gr_circle(fl2i(pnt->sx),fl2i(pnt->sy),fl2i(t*2.0f));
528 int g3_draw_sphere_ez(vector *pnt,float rad)
533 SDL_assert( G3_count == 1 );
535 flags = g3_rotate_vertex(&pt,pnt);
539 g3_project_vertex(&pt);
541 if (!(pt.flags & PF_OVERFLOW)) {
543 g3_draw_sphere( &pt, rad );
551 //draws a bitmap with the specified 3d width & height
552 //returns 1 if off screen, 0 if drew
554 int g3_draw_bitmap(vertex *pnt,int orient, float rad,uint tmap_flags)
560 if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
563 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
567 height = width*i2fl(bh)/i2fl(bw);
568 } else if ( bw > bh ) {
570 width = height*i2fl(bw)/i2fl(bh);
572 width = height = rad*2.0f;
575 width = height = rad*2.0f;
578 SDL_assert( G3_count == 1 );
580 if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) )
583 if (!(pnt->flags&PF_PROJECTED))
584 g3_project_vertex(pnt);
586 if (pnt->flags & PF_OVERFLOW)
589 t = (width*Canv_w2)/pnt->z;
590 w = t*Matrix_scale.xyz.x;
592 t = (height*Canv_h2)/pnt->z;
593 h = t*Matrix_scale.xyz.y;
596 z = pnt->z - rad/2.0f;
604 va.sx = pnt->sx - w/2.0f;
605 va.sy = pnt->sy - h/2.0f;
635 // get bitmap dims onscreen as if g3_draw_bitmap() had been called
636 int g3_get_bitmap_dims(int bitmap, vertex *pnt, float rad, int *x, int *y, int *w, int *h, int *size)
643 bm_get_info( bitmap, &bw, &bh, NULL );
647 height = width*i2fl(bh)/i2fl(bw);
648 } else if ( bw > bh ) {
650 width = height*i2fl(bw)/i2fl(bh);
652 width = height = rad*2.0f;
655 SDL_assert( G3_count == 1 );
657 if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) {
661 if (!(pnt->flags&PF_PROJECTED)){
662 g3_project_vertex(pnt);
665 if (pnt->flags & PF_OVERFLOW){
669 t = (width*Canv_w2)/pnt->z;
670 *w = (int)(t*Matrix_scale.xyz.x);
672 t = (height*Canv_h2)/pnt->z;
673 *h = (int)(t*Matrix_scale.xyz.y);
675 *x = (int)(pnt->sx - *w/2.0f);
676 *y = (int)(pnt->sy - *h/2.0f);
683 //draws a bitmap with the specified 3d width & height
684 //returns 1 if off screen, 0 if drew
685 int g3_draw_rotated_bitmap(vertex *pnt,float angle, float rad,uint tmap_flags)
688 vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
693 if ( !Detail.alpha_effects ) {
695 if ( angle < PI/2 ) {
697 } else if ( angle < PI ) {
699 } else if ( angle < PI+PI/2 ) {
704 return g3_draw_bitmap( pnt, ang, rad, tmap_flags );
708 SDL_assert( G3_count == 1 );
710 angle+=Physics_viewer_bank;
713 else if ( angle > PI2 )
717 sa = (float)sin(angle);
718 ca = (float)cos(angle);
722 if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
725 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
729 height = width*i2fl(bh)/i2fl(bw);
730 } else if ( bw > bh ) {
732 width = height*i2fl(bw)/i2fl(bh);
734 width = height = rad;
737 width = height = rad;
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;
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;
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;
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;
769 ubyte codes_and=0xff;
772 z = pnt->z - rad / 4.0f;
773 if ( z < 0.0f ) z = 0.0f;
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]);
784 return 1; //1 means off screen
787 g3_draw_poly_constant_sw(4, vertlist, tmap_flags, sw );
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)
796 float total_area = 0.0f;
799 for(idx=1; idx<nv-1; idx++){
800 TRIANGLE_AREA(pointlist[0], pointlist[idx], pointlist[idx+1]);
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)
818 SDL_assert( G3_count == 1 );
820 cc.vor = 0; cc.vand = 0xff;
827 p = bufptr[i] = pointlist[i];
834 return 0.0f; //all points off screen
838 SDL_assert( G3_count == 1 );
840 bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
842 if (nv && !(cc.vor&CC_BEHIND) && !cc.vand) {
845 vertex *p = bufptr[i];
847 if (!(p->flags&PF_PROJECTED))
848 g3_project_vertex(p);
850 if (p->flags&PF_OVERFLOW) {
851 //Int3(); //should not overflow after clip
852 //printf( "overflow in must_clip_tmap_face\n" );
860 p_area = g3_get_poly_area(nv, bufptr);
865 gr_tmapper( nv, bufptr, tmap_flags );
872 if (bufptr[i]->flags & PF_TEMP_POINT){
873 free_temp_point(bufptr[i]);
877 //now make list of 2d coords (& check for overflow)
880 vertex *p = bufptr[i];
882 if (!(p->flags&PF_PROJECTED))
883 g3_project_vertex(p);
885 if (p->flags&PF_OVERFLOW) {
893 p_area = g3_get_poly_area(nv, bufptr);
898 gr_tmapper( nv, bufptr, tmap_flags );
901 // how much area we drew
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)
911 vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
915 SDL_assert( G3_count == 1 );
917 angle+=Physics_viewer_bank;
920 } else if ( angle > PI2 ) {
924 sa = (float)sin(angle);
925 ca = (float)cos(angle);
929 if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
932 bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
936 height = width*i2fl(bh)/i2fl(bw);
937 } else if ( bw > bh ) {
939 width = height*i2fl(bw)/i2fl(bh);
941 width = height = rad;
944 width = height = rad;
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;
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;
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;
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;
976 ubyte codes_and=0xff;
979 z = pnt->z - rad / 4.0f;
980 if ( z < 0.0f ) z = 0.0f;
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]);
995 return g3_draw_poly_constant_sw_area(4, vertlist, tmap_flags, sw, area );
1001 typedef struct horz_pt {
1006 //draws a horizon. takes eax=sky_color, edx=ground_color
1007 void g3_draw_horizon_line()
1009 //int sky_color,int ground_color
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
1019 float up_right, down_right,down_left,up_left;
1021 // color_swap = 0; //assume no swap
1022 // sky_ground_flag = 0; //assume both
1024 // if ( View_matrix.uvec.y < 0.0f )
1026 // else if ( View_matrix.uvec.y == 0.0f ) {
1027 // if ( View_matrix.uvec.xyz.x > 0.0f )
1031 // if (color_swap) {
1032 // top_color = ground_color;
1033 // bot_color = sky_color;
1035 // top_color = sky_color;
1036 // bot_color = ground_color;
1039 SDL_assert( G3_count == 1 );
1042 //compute horizon_vector
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;
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;
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" ));
1060 if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) ) {
1061 // mprintf(( "All sky.\n" ));
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 ));
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
1073 // check intersection with left edge
1074 s1 = up_left > 0.0f;
1075 s2 = down_left > 0.0f;
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;
1083 // check intersection with top edge
1084 s1 = up_left > 0.0f;
1085 s2 = up_right > 0.0f;
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;
1094 // check intersection with right edge
1095 s1 = up_right > 0.0f;
1096 s2 = down_right > 0.0f;
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;
1104 //check intersection with bottom edge
1105 s1 = down_right > 0.0f;
1106 s2 = down_left > 0.0f;
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;
1115 mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
1119 //make sure first edge is left
1121 if ( horz_pts[0].x > horz_pts[1].x ) {
1124 horz_pts[0] = horz_pts[1];
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) );
1137 horizon_poly dw 5 dup (?,?) ;max of 5 points
1139 ;for g3_compute_horz_vecs
1146 ;for compute corner vec
1157 _TEXT segment dword public USE32 'CODE'
1159 extn gr_setcolor_,gr_clear_canvas_
1162 ;draw a polygon (one half of horizon) from the horizon line
1163 draw_horz_poly: lea ebx,horizon_poly
1165 ;copy horizon line as first points in poly
1177 ;add corners to polygon
1179 mov eax,8[esi] ;edge number of start edge
1181 mov ecx,8[edi] ;edge number of end point
1182 sub ecx,eax ;number of edges
1186 mov edx,ecx ;save count
1188 lea esi,corners[eax] ;first corner
1189 lea edi,16[ebx] ;rest of poly
1191 movsd ;copy a corner
1192 cmp esi,offset corners+8*4 ;end of list?
1195 no_wrap: loop corner_loop
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!
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
1214 pushm ebx,ecx,edx,esi,edi
1220 xchg esi,edi ;sky isn't top
1223 ;copy horizon line as first points in poly
1225 mov eax,[edi] ;copy end point
1230 mov eax,[esi] ;copy start point
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
1242 pop esi ;get back start point
1244 call compute_horz_end_vec
1246 pop edi ;get back end point
1248 add ebx,16 ;past two x,y pairs
1249 add ecx,24 ;past two vectors
1253 ;add corners to polygon
1255 mov eax,8[esi] ;edge number of start edge
1258 mov ecx,8[edi] ;edge number of end point
1259 sub ecx,eax ;number of edges
1263 push ecx ;save count
1265 lea esi,corners[eax] ;first corner
1266 mov edi,ebx ;rest of poly 2d points
1269 movsd ;copy a corner
1270 cmp esi,offset corners+8*4 ;end of list?
1277 call compute_corner_vec
1284 ;now return with count
1285 pop eax ;get corner count
1286 add eax,2 ;..plus horz line end points
1288 popm ebx,ecx,edx,esi,edi
1292 ;we drew all ground, so there was no horizon drawn
1293 was_all_ground: xor eax,eax ;no points in poly
1296 ;we drew all sky, so find 4 corners
1297 was_all_sky: pushm ebx,ecx,edx,esi,edi
1306 xor eax,eax ;start corner 0
1307 sky_loop: pushm eax,ecx,edi
1308 call compute_corner_vec
1313 mov eax,4 ;4 corners
1314 popm ebx,ecx,edx,esi,edi
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:
1321 ;compute rotated x/z & y/z ratios
1323 mov eax,[esi] ;get x coord
1328 mov eax,4[esi] ;get y coord
1331 neg eax ;y inversion
1334 ;compute fraction unrotated x/z
1339 fixmul View_matrix.m9
1340 sub eax,View_matrix.m7
1341 sub eax,View_matrix.m8
1342 mov ebx,eax ;save numerator
1345 fixmul View_matrix.m3
1347 mov eax,View_matrix.m1
1348 add eax,View_matrix.m2
1351 ;now eax/ebx = z/x. do divide in way to give result < 0
1357 cmp eax,ebx ;which is bigger?
1361 ;x is bigger, so do as z/x
1365 ;now eax = z/x ratio. Compute vector by normalizing and correcting sign
1367 push eax ;save ratio
1369 imul eax ;compute z*z
1370 inc edx ;+ x*x (x==1)
1373 mov ecx,eax ;mag in ecx
1374 pop eax ;get ratio, x part
1386 ;z is bigger, so do as x/z
1391 ;now eax = x/z ratio. Compute vector by normalizing and correcting sign
1393 push eax ;save ratio
1395 imul eax ;compute x*x
1396 inc edx ;+ z*z (z==1)
1399 mov ecx,eax ;mag in ecx
1400 pop eax ;get ratio, x part
1410 finish_end: xor eax,eax ;y = 0
1413 ;now make sure that this vector is in front of you, not behind
1423 jns vec_ok ;has positive z, ok
1425 ;z is neg, flip vector
1440 ;compute vector decribing a corner of the screen.
1441 ;takes edi=vector, eax=corner num
1450 mov ebx,View_matrix.m1
1451 mov ecx,View_matrix.m4
1452 mov edx,View_matrix.m7
1463 sub ebx,View_matrix.m3
1465 sub ecx,View_matrix.m6
1467 sub edx,View_matrix.m9
1470 mov ebx,View_matrix.m5
1471 mov ecx,View_matrix.m2
1472 mov edx,View_matrix.m8
1481 sub ebx,View_matrix.m6
1483 sub ecx,View_matrix.m3
1485 sub edx,View_matrix.m9
1490 ;compute denomonator
1498 sub eax,ebx ;eax = denominator
1500 ;now we have the denominator. If it is too small, try x/y, z/y or z/x, y/x
1502 mov ecx,eax ;save den
1510 ;now do x/z numerator
1513 fixmul m56 ;* (m5-m6)
1517 fixmul m46 ;* (m4-m6)
1520 ;now, eax/ecx = x/z ratio
1522 fixdiv ecx ;eax = x/z
1524 mov [edi].x,eax ;save x
1536 ;now eax/ecx = y/z ratio
1545 call vm_vec_normalize
1547 ;make sure this vec is pointing in right direction
1549 lea edi,View_matrix.fvec
1551 or eax,eax ;check sign
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)
1574 vector uvec, fvec, rvec, center;
1576 vm_vec_sub( &fvec, p0, p1 );
1577 vm_vec_normalize_safe( &fvec );
1579 vm_vec_avg( ¢er, p0, p1 );
1580 vm_vec_sub( &rvec, &Eye_position, ¢er );
1581 vm_vec_normalize( &rvec );
1583 vm_vec_crossprod(&uvec,&fvec,&rvec);
1585 //normalize new perpendicular vector
1586 vm_vec_normalize(&uvec);
1588 //now recompute right vector, in case it wasn't entirely perpendiclar
1589 vm_vec_crossprod(&rvec,&uvec,&fvec);
1591 // Now have uvec, which is up vector and rvec which is the normal
1597 vertex *ptlist[4] = { &pts[3], &pts[2], &pts[1], &pts[0] };
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 );
1604 for (i=0; i<4; i++ ) {
1608 g3_rotate_vertex( &pts[i], &vecs[i] );
1611 return g3_draw_poly(4,ptlist,tmap_flags);
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 } } }
1622 #define MAX_PERSPECTIVE_DIVISIONS 5 // should never even come close to this limit
1624 void stars_project_2d_onto_sphere( vector *pnt, float rho, float phi, float theta )
1626 float a = 3.14159f * phi;
1627 float b = 6.28318f * theta;
1628 float sin_a = (float)sin(a);
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);
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)
1641 vector s_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1642 vector t_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
1647 int saved_zbuffer_mode;
1651 // cap division values
1652 // div_x = div_x > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_x;
1654 div_y = div_y > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_y;
1656 // texture increment values
1657 ui = 1.0f / (float)div_x;
1658 vi = 1.0f / (float)div_y;
1660 // adjust for aspect ratio
1661 scale_x *= ((float)gr_screen.max_w / (float)gr_screen.max_h) + 0.55f; // fudge factor
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));
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);
1674 // convert angles to matrix
1675 float b_save = a->b;
1677 vm_angles_2_matrix(&m, a);
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));
1686 // bank the bitmap first
1687 vm_vec_rotate(&t_points[idx][s_idx], &s_points[idx][s_idx], &m_bank);
1689 // rotate on the sphere
1690 vm_vec_rotate(&s_points[idx][s_idx], &t_points[idx][s_idx], &m);
1694 // turn off zbuffering
1695 saved_zbuffer_mode = gr_zbuffer_get();
1696 gr_zbuffer_set(GR_ZBUFF_NONE);
1703 tmap_flags &= ~(TMAP_FLAG_CORRECT);
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);
1713 v[1].u = ui * float(idx+1);
1714 v[1].v = vi * float(s_idx);
1716 v[2].u = ui * float(idx+1);
1717 v[2].v = vi * float(s_idx+1);
1719 v[3].u = ui * float(idx);
1720 v[3].v = vi * float(s_idx+1);
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);
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);
1752 gr_zbuffer_set(saved_zbuffer_mode);
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)
1762 int saved_zbuffer_mode;
1764 vertex *vertlist[4] = { &v[0], &v[1], &v[2], &v[3] };
1770 // turn off zbuffering
1771 saved_zbuffer_mode = gr_zbuffer_get();
1772 gr_zbuffer_set(GR_ZBUFF_NONE);
1774 // bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &bw, &bh);
1782 v[0].flags = PF_PROJECTED;
1785 v[1].sx = (float)(x + w);
1790 v[1].flags = PF_PROJECTED;
1793 v[2].sx = (float)(x + w);
1794 v[2].sy = (float)(y + h);
1798 v[2].flags = PF_PROJECTED;
1802 v[3].sy = (float)(y + h);
1806 v[3].flags = PF_PROJECTED;
1813 v[0].u = 0.5f / i2fl(bw);
1814 v[0].v = 0.5f / i2fl(bh);
1815 v[0].flags = PF_PROJECTED;
1818 v[1].sx = (float)(x + w);
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;
1826 v[2].sx = (float)(x + w);
1827 v[2].sy = (float)(y + h);
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;
1835 v[3].sy = (float)(y + h);
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;
1844 ret = g3_draw_poly_constant_sw(4, vertlist, TMAP_FLAG_TEXTURED | additional_tmap_flags, 0.1f);
1848 gr_zbuffer_set(saved_zbuffer_mode);