Files
fs2open.github.com/code/render/3ddraw.cpp
T
randomtiger a4c446a059 Turned off fog in OGL for Fred.
Simulated speech doesnt say tags marked by $ now.
The following are fixes to issues that came up testing TBP in fs2_open and fred2_open:
Changed vm_vec_mag and parse_tmap to fail gracefully on bad data.
Error now given on missing briefing icon and bad ship normal data.
Solved more species divide by zero error.
Fixed neb cube crash.
2004-02-13 04:17:14 +00:00

2084 lines
46 KiB
C++

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
/*
* $Logfile: /Freespace2/code/Render/3ddraw.cpp $
* $Revision: 2.14 $
* $Date: 2004-02-13 04:17:14 $
* $Author: randomtiger $
*
* 3D rendering primitives
*
* $Log: not supported by cvs2svn $
* Revision 2.13 2004/01/24 14:31:27 randomtiger
* Added the D3D particle code, its not bugfree but works perfectly on my card and helps with the framerate.
* Its optional and off by default, use -d3d_particle to activiate.
* Also bumped up D3D ambient light setting, it was way too dark.
* Its now set to something similar to the original game.
*
* Revision 2.12 2004/01/19 00:56:10 randomtiger
* Some more small changes for Fred OGL
*
* Revision 2.11 2003/11/25 15:04:46 fryday
* Got lasers to work in HT&L OpenGL
* Messed a bit with opengl_tmapper_internal3d, draw_laser functions, and added draw_laser_htl
*
* Revision 2.10 2003/11/17 04:25:57 bobboau
* made the poly list dynamicly alocated,
* started work on fixing the node model not rendering,
* but most of that got commented out so I wouldn't have to deal with it
* while mucking about with the polylist
*
* Revision 2.9 2003/11/16 04:09:27 Goober5000
* language
*
* Revision 2.8 2003/11/11 03:56:12 bobboau
* lots of bug fixing, much of it in nebula and bitmap drawing
*
* Revision 2.7 2003/10/29 18:18:52 randomtiger
* D3D particle flicker fix, also fixes explosions and thruster glows
*
* Revision 2.6 2003/10/23 18:03:24 randomtiger
* Bobs changes (take 2)
*
* Revision 2.5 2003/08/30 14:49:01 phreak
* fixed some random specular lighting bugs
*
* Revision 2.4 2003/08/21 15:03:43 phreak
* zeroed out the specular fields since they caused some flickering
*
* Revision 2.3 2003/03/18 10:07:05 unknownplayer
* The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can.
*
* Revision 2.2.2.1 2002/09/24 18:56:45 randomtiger
* DX8 branch commit
*
* This is the scub of UP's previous code with the more up to date RT code.
* For full details check previous dev e-mails
*
* Revision 2.2 2002/08/06 01:49:08 penguin
* Renamed ccode members to cc_or and cc_and
*
* Revision 2.1 2002/08/01 01:41:09 penguin
* The big include file move
*
* Revision 2.0 2002/06/03 04:02:27 penguin
* Warpcore CVS sync
*
* Revision 1.2 2002/05/04 04:52:22 mharris
* 1st draft at porting
*
* Revision 1.1 2002/05/02 18:03:12 mharris
* Initial checkin - converted filenames and includes to lower case
*
*
* 18 9/06/99 3:23p Andsager
* Make fireball and weapon expl ani LOD choice look at resolution of the
* bitmap
*
* 17 8/27/99 9:07p Dave
* LOD explosions. Improved beam weapon accuracy.
*
* 16 7/29/99 12:05a Dave
* Nebula speed optimizations.
*
* 15 7/13/99 1:16p Dave
* 32 bit support. Whee!
*
* 14 7/02/99 3:05p Anoop
* Oops. Fixed g3_draw_2d_poly() so that it properly handles poly bitmap
* and LFB bitmap calls.
*
* 13 6/29/99 10:35a Dave
* Interface polygon bitmaps! Whee!
*
* 12 6/22/99 7:03p Dave
* New detail options screen.
*
* 11 6/16/99 4:06p Dave
* New pilot info popup. Added new draw-bitmap-as-poly function.
*
* 10 6/08/99 5:17p Dave
* Fixed up perspective bitmap drawing.
*
* 9 6/03/99 6:37p Dave
* More TNT fun. Made perspective bitmaps more flexible.
*
* 8 5/28/99 1:58p Dave
* Fixed problem with overwriting bank value drawing perspective bitmaps.
*
* 7 5/28/99 1:45p Dave
* Fixed up perspective bitmap drawing.
*
* 6 5/24/99 5:45p Dave
* Added detail levels to the nebula, with a decent speedup. Split nebula
* lightning into its own section.
*
* 5 4/07/99 6:22p Dave
* Fred and Freespace support for multiple background bitmaps and suns.
* Fixed link errors on all subprojects. Moved encrypt_init() to
* cfile_init() and lcl_init(), since its safe to call twice.
*
* 4 3/09/99 6:24p Dave
* More work on object update revamping. Identified several sources of
* unnecessary bandwidth.
*
* 3 2/11/99 3:08p Dave
* PXO refresh button. Very preliminary squad war support.
*
* 2 10/07/98 10:53a Dave
* Initial checkin.
*
* 1 10/07/98 10:51a Dave
*
* 37 3/22/98 2:34p John
* If alpha effects is on lowest detail level, draw rotated bitmaps as
* scaled bitmaps.
*
* 36 3/16/98 4:51p John
* Added low-level code to clip all polygons against an arbritary plane.
* Took out all old model_interp_zclip and used this new method instead.
*
* 35 3/04/98 9:29a John
* Made rotated bitmaps force all sw's to the same value after clipping.
*
* 34 3/03/98 6:59p John
*
* 33 1/26/98 5:12p John
* Added in code for Pentium Pro specific optimizations. Speed up
* zbuffered correct tmapper about 35%. Speed up non-zbuffered scalers
* by about 25%.
*
* 32 1/15/98 2:16p John
* Made bitmaps zbuffer at center minus radius.
* Made fireballs sort after objects they are around.
*
* 31 1/06/98 2:11p John
* Made g3_draw_rotated bitmap draw the same orientation as g3_draw_bitmap
* (orient=0) and made it be the same size (it was 2x too big before).
*
* 30 12/30/97 6:44p John
* Made g3_Draw_bitmap functions account for aspect of bitmap.
*
* 29 12/04/97 12:09p John
* Made glows use scaler instead of tmapper so they don't rotate. Had to
* add a zbuffered scaler.
*
* 28 12/02/97 4:00p John
* Added first rev of thruster glow, along with variable levels of
* translucency, which retquired some restructing of palman.
*
* 27 11/29/97 2:05p John
* made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
* like they used to incorrectly assume. Added code to model to read in
* thruster radius's.
*
* 26 10/20/97 4:49p John
* added weapon trails.
* added facing bitmap code to 3d lib.
*
* 25 10/03/97 9:10a John
* added better antialiased line drawer
*
* 24 9/09/97 3:39p Sandeep
* warning level 4 bugs
*
* 23 7/11/97 11:54a John
* added rotated 3d bitmaps.
*
* 22 5/07/97 2:59p John
* Initial rev of D3D texturing.
*
* 21 4/29/97 9:55a John
*
* 20 3/10/97 2:25p John
* Made pofview zbuffer. Made textest work with new model code. Took
* out some unnecessary Asserts in the 3d clipper.
*
*
* 19 3/06/97 5:36p Mike
* Change vec_normalize_safe() back to vec_normalize().
* Spruce up docking a bit.
*
* 18 3/06/97 10:56a Mike
* Write error checking version of vm_vec_normalize().
* Fix resultant problems.
*
* 17 2/26/97 5:24p John
* Added g3_draw_sphere_ez
*
* 16 2/17/97 5:18p John
* Added a bunch of RCS headers to a bunch of old files that don't have
* them.
*
* $NoKeywords: $
*/
#include "render/3dinternal.h"
#include "graphics/tmapper.h"
#include "graphics/scaler.h"
#include "graphics/2d.h"
#include "math/floating.h"
#include "physics/physics.h" // For Physics_viewer_bank for g3_draw_rotated_bitmap
#include "bmpman/bmpman.h"
#include "globalincs/systemvars.h"
#include "globalincs/alphacolors.h"
#include "cmdline/cmdline.h"
#include "io/key.h"
//deal with a clipped line
int must_clip_line(vertex *p0,vertex *p1,ubyte codes_or, uint flags)
{
int ret = 0;
clip_line(&p0,&p1,codes_or, flags);
if (p0->codes & p1->codes) goto free_points;
codes_or = (unsigned char)(p0->codes | p1->codes);
if (codes_or & CC_BEHIND) goto free_points;
if (!(p0->flags&PF_PROJECTED))
g3_project_vertex(p0);
if (p0->flags&PF_OVERFLOW) goto free_points;
if (!(p1->flags&PF_PROJECTED))
g3_project_vertex(p1);
if (p1->flags&PF_OVERFLOW) goto free_points;
//gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
// gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
gr_aaline( p0, p1 );
ret = 1;
//frees temp points
free_points:
if (p0->flags & PF_TEMP_POINT)
free_temp_point(p0);
if (p1->flags & PF_TEMP_POINT)
free_temp_point(p1);
return ret;
}
//draws a line. takes two points. returns true if drew
int g3_draw_line(vertex *p0,vertex *p1)
{
#ifdef FRED_OGL_COMMENT_OUT_FOR_NOW
if(Fred_running && !Cmdline_nohtl)
{
gr_aaline( p0, p1 );
return 0;
}
#endif
ubyte codes_or;
Assert( G3_count == 1 );
if (p0->codes & p1->codes)
return 0;
codes_or = (unsigned char)(p0->codes | p1->codes);
if (codes_or & CC_BEHIND)
return must_clip_line(p0,p1,codes_or,0);
if (!(p0->flags&PF_PROJECTED))
g3_project_vertex(p0);
if (p0->flags&PF_OVERFLOW)
// return 1;
return must_clip_line(p0,p1,codes_or,0);
if (!(p1->flags&PF_PROJECTED))
g3_project_vertex(p1);
if (p1->flags&PF_OVERFLOW)
// return 1;
return must_clip_line(p0,p1,codes_or,0);
// gr_line(fl2i(p0->sx),fl2i(p0->sy),fl2i(p1->sx),fl2i(p1->sy));
// gr_line_float(p0->sx,p0->sy,p1->sx,p1->sy);
gr_aaline( p0, p1 );
return 0;
}
//returns true if a plane is facing the viewer. takes the unrotated surface
//normal of the plane, and a point on it. The normal need not be normalized
int g3_check_normal_facing(vector *v,vector *norm)
{
vector tempv;
Assert( G3_count == 1 );
vm_vec_sub(&tempv,&View_position,v);
return (vm_vec_dot(&tempv,norm) > 0.0f);
}
int do_facing_check(vector *norm,vertex **vertlist,vector *p)
{
Assert( G3_count == 1 );
if (norm) { //have normal
Assert(norm->xyz.x || norm->xyz.y || norm->xyz.z);
return g3_check_normal_facing(p,norm);
}
else { //normal not specified, so must compute
vector tempv;
//get three points (rotated) and compute normal
vm_vec_perp(&tempv,(vector *)&vertlist[0]->x,(vector *)&vertlist[1]->x,(vector *)&vertlist[2]->x);
return (vm_vec_dot(&tempv,(vector *)&vertlist[1]->x ) < 0.0);
}
}
//like g3_draw_poly(), but checks to see if facing. If surface normal is
//NULL, this routine must compute it, which will be slow. It is better to
//pre-compute the normal, and pass it to this function. When the normal
//is passed, this function works like g3_check_normal_facing() plus
//g3_draw_poly().
//returns -1 if not facing, 1 if off screen, 0 if drew
int g3_draw_poly_if_facing(int nv,vertex **pointlist,uint tmap_flags,vector *norm,vector *pnt)
{
Assert( G3_count == 1 );
if (do_facing_check(norm,pointlist,pnt))
return g3_draw_poly(nv,pointlist,tmap_flags);
else
return 255;
}
//draw a polygon.
//Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
//returns 1 if off screen, 0 if drew
int g3_draw_poly(int nv,vertex **pointlist,uint tmap_flags)
{
int i;
vertex **bufptr;
ccodes cc;
Assert( G3_count == 1 );
if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
gr_tmapper( nv, pointlist, tmap_flags );
return 0;
}
if(Cmdline_nohtl && (tmap_flags & TMAP_FLAG_TRISTRIP)){
bool starting = true;
int offset = 0;
for (i=0;i<nv;i++){
if (!(pointlist[i]->flags&PF_PROJECTED))g3_project_vertex(pointlist[i]);
if (pointlist[i]->flags&PF_OVERFLOW){
if(starting)
offset++;
nv--;
}else
starting = false;
if(nv<3)return 1;
}
if(nv<3)return 1;
pointlist += offset;
gr_tmapper( nv, pointlist, tmap_flags );
return 0;
}
cc.cc_or = 0;
cc.cc_and = 0xff;
bufptr = Vbuf0;
/* if(tmap_flags & TMAP_HTL_3D_UNLIT && !Cmdline_nohtl) {
gr_tmapper( nv, pointlist, tmap_flags );
return 0;
}
*/
for (i=0;i<nv;i++) {
vertex *p;
p = bufptr[i] = pointlist[i];
cc.cc_and &= p->codes;
cc.cc_or |= p->codes;
}
if (cc.cc_and)
return 1; //all points off screen
if (cc.cc_or) {
Assert( G3_count == 1 );
bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tmap_flags);
if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
//Int3(); //should not overflow after clip
//printf( "overflow in must_clip_tmap_face\n" );
goto free_points;
}
}
gr_tmapper( nv, bufptr, tmap_flags );
}
free_points:
;
for (i=0;i<nv;i++)
if (bufptr[i]->flags & PF_TEMP_POINT)
free_temp_point(bufptr[i]);
} else {
//now make list of 2d coords (& check for overflow)
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
//Int3(); //should not overflow after clip
//printf( "3d: Point overflowed, but flags say OK!\n" );
return 255;
}
}
gr_tmapper( nv, bufptr, tmap_flags );
}
return 0; //say it drew
}
// Draw a polygon. Same as g3_draw_poly, but it bashes sw to a constant value
// for all vertexes. Needs to be done after clipping to get them all.
//Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
//returns 1 if off screen, 0 if drew
int g3_draw_poly_constant_sw(int nv,vertex **pointlist,uint tmap_flags, float constant_sw)
{
int i;
vertex **bufptr;
ccodes cc;
Assert( G3_count == 1 );
if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
gr_tmapper( nv, pointlist, tmap_flags );
return 0;
}
if(tmap_flags & TMAP_FLAG_TRISTRIP){
for (i=0;i<nv;i++){
if (!(pointlist[i]->flags&PF_PROJECTED))g3_project_vertex(pointlist[i]);
}
gr_tmapper( nv, pointlist, tmap_flags );
return 0;
}
cc.cc_or = 0; cc.cc_and = 0xff;
bufptr = Vbuf0;
for (i=0;i<nv;i++) {
vertex *p;
p = bufptr[i] = pointlist[i];
cc.cc_and &= p->codes;
cc.cc_or |= p->codes;
}
if (cc.cc_and)
return 1; //all points off screen
if (cc.cc_or) {
Assert( G3_count == 1 );
bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
//Int3(); //should not overflow after clip
//printf( "overflow in must_clip_tmap_face\n" );
goto free_points;
}
p->sw = constant_sw;
}
gr_tmapper( nv, bufptr, tmap_flags );
// draw lines connecting the faces
/*
gr_set_color_fast(&Color_bright_green);
for(i=0; i<nv-1; i++){
g3_draw_line(bufptr[i], bufptr[i+1]);
}
g3_draw_line(bufptr[0], bufptr[i]);
*/
}
free_points:
;
for (i=0;i<nv;i++){
if (bufptr[i]->flags & PF_TEMP_POINT){
free_temp_point(bufptr[i]);
}
}
} else {
//now make list of 2d coords (& check for overflow)
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
//Int3(); //should not overflow after clip
//printf( "3d: Point overflowed, but flags say OK!\n" );
return 255;
}
p->sw = constant_sw;
}
gr_tmapper( nv, bufptr, tmap_flags );
// draw lines connecting the faces
/*
gr_set_color_fast(&Color_bright_green);
for(i=0; i<nv-1; i++){
g3_draw_line(bufptr[i], bufptr[i+1]);
}
g3_draw_line(bufptr[0], bufptr[i]);
*/
}
return 0; //say it drew
}
//draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
//radius, but not to the distance from the eye
int g3_draw_sphere(vertex *pnt,float rad)
{
Assert( G3_count == 1 );
if (! (pnt->codes & CC_BEHIND)) {
if (! (pnt->flags & PF_PROJECTED))
g3_project_vertex(pnt);
if (! (pnt->codes & PF_OVERFLOW)) {
float r2,t;
r2 = rad*Matrix_scale.xyz.x;
t=r2*Canv_w2/pnt->z;
gr_circle(fl2i(pnt->sx),fl2i(pnt->sy),fl2i(t*2.0f));
}
}
return 0;
}
int g3_draw_sphere_ez(vector *pnt,float rad)
{
vertex pt;
ubyte flags;
Assert( G3_count == 1 );
flags = g3_rotate_vertex(&pt,pnt);
if (flags == 0) {
g3_project_vertex(&pt);
if (!(pt.flags & PF_OVERFLOW)) {
g3_draw_sphere( &pt, rad );
}
}
return 0;
}
//ID3DXSprite
// creates a quad centered around the given point, pointed at the camera
/*
0----1
|\ |
| \ |
3----2
1.41421356
*/
int g3_draw_bitmap_3d(vertex *pnt,int orient, float rad,uint tmap_flags, float depth){
//return 0;
// rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and hieght rad
vector PNT;
vm_vert2vec(pnt, &PNT);
vector p[4];
vertex P[4];
//unused variables that were there for some reason
// matrix m;
// vm_set_identity(&m);
vertex *ptlist[4] = { &P[3], &P[2], &P[1], &P[0] };
float aspect = gr_screen.aspect*(float)gr_screen.clip_width/(float)gr_screen.clip_height;//seems that we have to corect for the aspect ratio
p[0].xyz.x = rad * aspect; p[0].xyz.y = rad; p[0].xyz.z = -depth;
p[1].xyz.x = -rad * aspect; p[1].xyz.y = rad; p[1].xyz.z = -depth;
p[2].xyz.x = -rad * aspect; p[2].xyz.y = -rad; p[2].xyz.z = -depth;
p[3].xyz.x = rad * aspect; p[3].xyz.y = -rad; p[3].xyz.z = -depth;
matrix te = View_matrix;
vm_transpose_matrix(&te);
for(int i = 0; i<4; i++){
vector t = p[i];
vm_vec_rotate(&p[i],&t,&te);//point it at the eye
vm_vec_add2(&p[i],&PNT);//move it
}
//move all the data from the vecs into the verts
g3_transfer_vertex(&P[0], &p[3]);
g3_transfer_vertex(&P[1], &p[2]);
g3_transfer_vertex(&P[2], &p[1]);
g3_transfer_vertex(&P[3], &p[0]);
//set up the UV coords
P[0].u = 0.0f; P[0].v = 0.0f;
P[1].u = 1.0f; P[1].v = 0.0f;
P[2].u = 1.0f; P[2].v = 1.0f;
P[3].u = 0.0f; P[3].v = 1.0f;
gr_set_cull(0);
g3_draw_poly(4,ptlist,tmap_flags);
gr_set_cull(1);
return 0;
}
//draws a bitmap with the specified 3d width & height
//returns 1 if off screen, 0 if drew
// Orient
int g3_draw_bitmap(vertex *pnt,int orient, float rad,uint tmap_flags, float depth)
{
if(!Cmdline_nohtl)
{
bool gr_d3d_particle_set(vertex *pos, int bitmap_id, float size);
if((tmap_flags & TMAP_HTL_PARTICLE) && gr_screen.mode == GR_DIRECT3D && Cmdline_d3d_particle)
if(gr_d3d_particle_set(pnt, gr_screen.current_bitmap, rad) == true)
return 0;
if(tmap_flags & TMAP_HTL_3D_UNLIT)
return g3_draw_bitmap_3d(pnt, orient, rad, tmap_flags, depth);
}
vertex va, vb;
float t,w,h;
float width, height;
if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
int bw, bh;
bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
if ( bw < bh ) {
width = rad*2.0f;
height = width*i2fl(bh)/i2fl(bw);
} else if ( bw > bh ) {
height = rad*2.0f;
width = height*i2fl(bw)/i2fl(bh);
} else {
width = height = rad*2.0f;
}
} else {
width = height = rad*2.0f;
}
Assert( G3_count == 1 );
if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) )
return 1;
if (!(pnt->flags&PF_PROJECTED))
g3_project_vertex(pnt);
if (pnt->flags & PF_OVERFLOW)
return 1;
t = (width*Canv_w2)/pnt->z;
w = t*Matrix_scale.xyz.x;
t = (height*Canv_h2)/pnt->z;
h = t*Matrix_scale.xyz.y;
float z,sw;
z = pnt->z - rad/2.0f;
if ( z <= 0.0f ) {
z = 0.0f;
sw = 0.0f;
} else {
sw = 1.0f / z;
}
va.sx = pnt->sx - w/2.0f;
va.sy = pnt->sy - h/2.0f;
va.sw = sw;
va.z = z;
vb.sx = va.sx + w;
vb.sy = va.sy + h;
vb.sw = sw;
vb.z = z;
if ( orient & 1 ) {
va.u = 1.0f;
vb.u = 0.0f;
} else {
va.u = 0.0f;
vb.u = 1.0f;
}
if ( orient & 2 ) {
va.v = 1.0f;
vb.v = 0.0f;
} else {
va.v = 0.0f;
vb.v = 1.0f;
}
gr_scaler(&va, &vb);
return 0;
}
// get bitmap dims onscreen as if g3_draw_bitmap() had been called
int g3_get_bitmap_dims(int bitmap, vertex *pnt, float rad, int *x, int *y, int *w, int *h, int *size)
{
float t;
float width, height;
int bw, bh;
bm_get_info( bitmap, &bw, &bh, NULL );
if ( bw < bh ) {
width = rad*2.0f;
height = width*i2fl(bh)/i2fl(bw);
} else if ( bw > bh ) {
height = rad*2.0f;
width = height*i2fl(bw)/i2fl(bh);
} else {
width = height = rad*2.0f;
}
Assert( G3_count == 1 );
if ( pnt->codes & (CC_BEHIND|CC_OFF_USER) ) {
return 1;
}
if (!(pnt->flags&PF_PROJECTED)){
g3_project_vertex(pnt);
}
if (pnt->flags & PF_OVERFLOW){
return 1;
}
t = (width*Canv_w2)/pnt->z;
*w = (int)(t*Matrix_scale.xyz.x);
t = (height*Canv_h2)/pnt->z;
*h = (int)(t*Matrix_scale.xyz.y);
*x = (int)(pnt->sx - *w/2.0f);
*y = (int)(pnt->sy - *h/2.0f);
*size = max(bw, bh);
return 0;
}
int g3_draw_rotated_bitmap_3d(vertex *pnt,float angle, float rad,uint tmap_flags, float depth){
rad *= 1.41421356f;//1/0.707, becase these are the points of a square or width and hieght rad
angle+=Physics_viewer_bank;
if ( angle < 0.0f )
angle += PI2;
else if ( angle > PI2 )
angle -= PI2;
float sa = (float)sin(angle);
float ca = (float)cos(angle);
vector PNT;
vm_vert2vec(pnt, &PNT);
vector p[4];
vertex P[4];
matrix m;
vm_set_identity(&m);
vertex *ptlist[4] = { &P[3], &P[2], &P[1], &P[0] };
float aspect = gr_screen.aspect*(float)gr_screen.clip_width/(float)gr_screen.clip_height;//seems that we have to corect for the aspect ratio
p[0].xyz.x = (-rad*ca + rad*sa) * aspect; p[0].xyz.y = (-rad*sa - rad*ca); p[0].xyz.z = -depth;
p[1].xyz.x = (rad*ca + rad*sa) * aspect; p[1].xyz.y = (rad*sa - rad*ca); p[1].xyz.z = -depth;
p[2].xyz.x = (rad*ca - rad*sa) * aspect; p[2].xyz.y = (rad*sa + rad*ca); p[2].xyz.z = -depth;
p[3].xyz.x = (-rad*ca - rad*sa) * aspect; p[3].xyz.y = (-rad*sa + rad*ca); p[3].xyz.z = -depth;
matrix te = View_matrix;
vm_transpose_matrix(&te);
for(int i = 0; i<4; i++){
vector t = p[i];
vm_vec_rotate(&p[i],&t,&te);//point it at the eye
vm_vec_add2(&p[i],&PNT);//move it
}
//move all the data from the vecs into the verts
g3_transfer_vertex(&P[0], &p[3]);
g3_transfer_vertex(&P[1], &p[2]);
g3_transfer_vertex(&P[2], &p[1]);
g3_transfer_vertex(&P[3], &p[0]);
//set up the UV coords
P[0].u = 0.0f; P[0].v = 0.0f;
P[1].u = 1.0f; P[1].v = 0.0f;
P[2].u = 1.0f; P[2].v = 1.0f;
P[3].u = 0.0f; P[3].v = 1.0f;
/* P[0].spec_r = 0; P[0].spec_g = 0; P[0].spec_b = 0;
P[1].spec_r = 0; P[1].spec_g = 0; P[1].spec_b = 0;
P[2].spec_r = 0; P[2].spec_g = 0; P[2].spec_b = 0;
P[3].spec_r = 0; P[3].spec_g = 0; P[3].spec_b = 0;
*/
gr_set_cull(0);
g3_draw_poly(4,ptlist,tmap_flags);
gr_set_cull(1);
return 0;
}
//draws a bitmap with the specified 3d width & height
//returns 1 if off screen, 0 if drew
int g3_draw_rotated_bitmap(vertex *pnt,float angle, float rad,uint tmap_flags, float depth)
{
if(!Cmdline_nohtl && (tmap_flags & TMAP_HTL_3D_UNLIT)) {
return g3_draw_rotated_bitmap_3d(pnt, angle, rad, tmap_flags, depth);
}
vertex v[4];
vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
float sa, ca;
int i;
memset(v,0,sizeof(vertex)*4);
/*
if ( !Detail.alpha_effects ) {
int ang;
if ( angle < PI/2 ) {
ang = 0;
} else if ( angle < PI ) {
ang = 1;
} else if ( angle < PI+PI/2 ) {
ang = 2;
} else {
ang = 3;
}
return g3_draw_bitmap( pnt, ang, rad, tmap_flags );
}
*/
Assert( G3_count == 1 );
angle+=Physics_viewer_bank;
if ( angle < 0.0f )
angle += PI2;
else if ( angle > PI2 )
angle -= PI2;
// angle = 0.0f;
sa = (float)sin(angle);
ca = (float)cos(angle);
float width, height;
if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
int bw, bh;
bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
if ( bw < bh ) {
width = rad;
height = width*i2fl(bh)/i2fl(bw);
} else if ( bw > bh ) {
height = rad;
width = height*i2fl(bw)/i2fl(bh);
} else {
width = height = rad;
}
} else {
width = height = rad;
}
v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
v[0].z = pnt->z;
v[0].sw = 0.0f;
v[0].u = 0.0f;
v[0].v = 1.0f;
v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
v[1].z = pnt->z;
v[1].sw = 0.0f;
v[1].u = 1.0f;
v[1].v = 1.0f;
v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
v[2].z = pnt->z;
v[2].sw = 0.0f;
v[2].u = 1.0f;
v[2].v = 0.0f;
v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
v[3].z = pnt->z;
v[3].sw = 0.0f;
v[3].u = 0.0f;
v[3].v = 0.0f;
ubyte codes_and=0xff;
float sw,z;
z = pnt->z - rad / 4.0f;
if ( z < 0.0f ) z = 0.0f;
sw = 1.0f / z;
for (i=0; i<4; i++ ) {
//now code the four points
codes_and &= g3_code_vertex(&v[i]);
v[i].flags = 0; // mark as not yet projected
//g3_project_vertex(&v[i]);
}
if (codes_and)
return 1; //1 means off screen
// clip and draw it
g3_draw_poly_constant_sw(4, vertlist, tmap_flags, sw );
return 0;
}
#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);
float g3_get_poly_area(int nv, vertex **pointlist)
{
int idx;
float total_area = 0.0f;
// each triangle
for(idx=1; idx<nv-1; idx++){
TRIANGLE_AREA(pointlist[0], pointlist[idx], pointlist[idx+1]);
}
// done
return total_area;
}
// Draw a polygon. Same as g3_draw_poly, but it bashes sw to a constant value
// for all vertexes. Needs to be done after clipping to get them all.
//Set TMAP_FLAG_TEXTURED in the tmap_flags to texture map it with current texture.
//returns 1 if off screen, 0 if drew
float g3_draw_poly_constant_sw_area(int nv, vertex **pointlist, uint tmap_flags, float constant_sw, float area)
{
int i;
vertex **bufptr;
ccodes cc;
float p_area = 0.0f;
Assert( G3_count == 1 );
cc.cc_or = 0;
cc.cc_and = 0xff;
bufptr = Vbuf0;
for (i=0;i<nv;i++) {
vertex *p;
p = bufptr[i] = pointlist[i];
cc.cc_and &= p->codes;
cc.cc_or |= p->codes;
}
if (cc.cc_and){
return 0.0f; //all points off screen
}
if (cc.cc_or) {
Assert( G3_count == 1 );
bufptr = clip_polygon(Vbuf0, Vbuf1, &nv, &cc, tmap_flags);
if (nv && !(cc.cc_or & CC_BEHIND) && !cc.cc_and) {
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
//Int3(); //should not overflow after clip
//printf( "overflow in must_clip_tmap_face\n" );
goto free_points;
}
p->sw = constant_sw;
}
// check area
p_area = g3_get_poly_area(nv, bufptr);
if(p_area > area){
return 0.0f;
}
gr_tmapper( nv, bufptr, tmap_flags );
}
free_points:
;
for (i=0;i<nv;i++){
if (bufptr[i]->flags & PF_TEMP_POINT){
free_temp_point(bufptr[i]);
}
}
} else {
//now make list of 2d coords (& check for overflow)
for (i=0;i<nv;i++) {
vertex *p = bufptr[i];
if (!(p->flags&PF_PROJECTED))
g3_project_vertex(p);
if (p->flags&PF_OVERFLOW) {
return 0.0f;
}
p->sw = constant_sw;
}
// check area
p_area = g3_get_poly_area(nv, bufptr);
if(p_area > area){
return 0.0f;
}
gr_tmapper( nv, bufptr, tmap_flags );
}
// how much area we drew
return p_area;
}
//draws a bitmap with the specified 3d width & height
//returns 1 if off screen, 0 if drew
float g3_draw_rotated_bitmap_area(vertex *pnt,float angle, float rad,uint tmap_flags, float area)
{
vertex v[4];
vertex *vertlist[4] = { &v[3], &v[2], &v[1], &v[0] };
float sa, ca;
int i;
memset(v,0,sizeof(vertex)*4);
Assert( G3_count == 1 );
angle+=Physics_viewer_bank;
if ( angle < 0.0f ){
angle += PI2;
} else if ( angle > PI2 ) {
angle -= PI2;
}
sa = (float)sin(angle);
ca = (float)cos(angle);
float width, height;
if ( tmap_flags & TMAP_FLAG_TEXTURED ) {
int bw, bh;
bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
if ( bw < bh ) {
width = rad;
height = width*i2fl(bh)/i2fl(bw);
} else if ( bw > bh ) {
height = rad;
width = height*i2fl(bw)/i2fl(bh);
} else {
width = height = rad;
}
} else {
width = height = rad;
}
v[0].x = (-width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
v[0].y = (-width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
v[0].z = pnt->z;
v[0].sw = 0.0f;
v[0].u = 0.0f;
v[0].v = 1.0f;
v[1].x = (width*ca + height*sa)*Matrix_scale.xyz.x + pnt->x;
v[1].y = (width*sa - height*ca)*Matrix_scale.xyz.y + pnt->y;
v[1].z = pnt->z;
v[1].sw = 0.0f;
v[1].u = 1.0f;
v[1].v = 1.0f;
v[2].x = (width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
v[2].y = (width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
v[2].z = pnt->z;
v[2].sw = 0.0f;
v[2].u = 1.0f;
v[2].v = 0.0f;
v[3].x = (-width*ca - height*sa)*Matrix_scale.xyz.x + pnt->x;
v[3].y = (-width*sa + height*ca)*Matrix_scale.xyz.y + pnt->y;
v[3].z = pnt->z;
v[3].sw = 0.0f;
v[3].u = 0.0f;
v[3].v = 0.0f;
ubyte codes_and=0xff;
float sw,z;
z = pnt->z - rad / 4.0f;
if ( z < 0.0f ) z = 0.0f;
sw = 1.0f / z;
for (i=0; i<4; i++ ) {
//now code the four points
codes_and &= g3_code_vertex(&v[i]);
v[i].flags = 0; // mark as not yet projected
//g3_project_vertex(&v[i]);
}
if (codes_and){
return 0.0f;
}
// clip and draw it
return g3_draw_poly_constant_sw_area(4, vertlist, tmap_flags, sw, area );
}
#include "graphics/2d.h"
typedef struct horz_pt {
float x, y;
int edge;
} horz_pt;
//draws a horizon. takes eax=sky_color, edx=ground_color
void g3_draw_horizon_line()
{
//int sky_color,int ground_color
int s1, s2;
int cpnt;
horz_pt horz_pts[4]; // 0 = left, 1 = right
// int top_color, bot_color;
// int color_swap; //flag for if we swapped
// int sky_ground_flag; //0=both, 1=all sky, -1=all gnd
vector horizon_vec;
float up_right, down_right,down_left,up_left;
// color_swap = 0; //assume no swap
// sky_ground_flag = 0; //assume both
// if ( View_matrix.uvec.xyz.y < 0.0f )
// color_swap = 1;
// else if ( View_matrix.uvec.xyz.y == 0.0f ) {
// if ( View_matrix.uvec.xyz.x > 0.0f )
// color_swap = 1;
// }
// if (color_swap) {
// top_color = ground_color;
// bot_color = sky_color;
// } else {
// top_color = sky_color;
// bot_color = ground_color;
// }
Assert( G3_count == 1 );
//compute horizon_vector
horizon_vec.xyz.x = Unscaled_matrix.vec.rvec.xyz.y*Matrix_scale.xyz.y*Matrix_scale.xyz.z;
horizon_vec.xyz.y = Unscaled_matrix.vec.uvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.z;
horizon_vec.xyz.z = Unscaled_matrix.vec.fvec.xyz.y*Matrix_scale.xyz.x*Matrix_scale.xyz.y;
// now compute values & flag for 4 corners.
up_right = horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
down_right = horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
down_left = -horizon_vec.xyz.x - horizon_vec.xyz.y + horizon_vec.xyz.z;
up_left = -horizon_vec.xyz.x + horizon_vec.xyz.y + horizon_vec.xyz.z;
//check flags for all sky or all ground.
if ( (up_right<0.0f)&&(down_right<0.0f)&&(down_left<0.0f)&&(up_left<0.0f) ) {
// mprintf(( "All ground.\n" ));
return;
}
if ( (up_right>0.0f)&&(down_right>0.0f)&&(down_left>0.0f)&&(up_left>0.0f) ) {
// mprintf(( "All sky.\n" ));
return;
}
//mprintf(( "Horizon vec = %.4f, %.4f, %.4f\n", horizon_vec.xyz.x, horizon_vec.xyz.y, horizon_vec.xyz.z ));
//mprintf(( "%.4f, %.4f, %.4f, %.4f\n", up_right, down_right, down_left, up_left ));
// mprintf(( "u: %.4f %.4f %.4f c: %.4f %.4f %.4f %.4f\n",Unscaled_matrix.vec.uvec.xyz.y,Unscaled_matrix.vec.uvec.xyz.z,Unscaled_matrix.vec.uvec.xyz.x,up_left,up_right,down_right,down_left ));
// check for intesection with each of four edges & compute horizon line
cpnt = 0;
// check intersection with left edge
s1 = up_left > 0.0f;
s2 = down_left > 0.0f;
if ( s1 != s2 ) {
horz_pts[cpnt].x = 0.0f;
horz_pts[cpnt].y = fl_abs(up_left * Canv_h2 / horizon_vec.xyz.y);
horz_pts[cpnt].edge = 0;
cpnt++;
}
// check intersection with top edge
s1 = up_left > 0.0f;
s2 = up_right > 0.0f;
if ( s1 != s2 ) {
horz_pts[cpnt].x = fl_abs(up_left * Canv_w2 / horizon_vec.xyz.x);
horz_pts[cpnt].y = 0.0f;
horz_pts[cpnt].edge = 1;
cpnt++;
}
// check intersection with right edge
s1 = up_right > 0.0f;
s2 = down_right > 0.0f;
if ( s1 != s2 ) {
horz_pts[cpnt].x = i2fl(Canvas_width)-1;
horz_pts[cpnt].y = fl_abs(up_right * Canv_h2 / horizon_vec.xyz.y);
horz_pts[cpnt].edge = 2;
cpnt++;
}
//check intersection with bottom edge
s1 = down_right > 0.0f;
s2 = down_left > 0.0f;
if ( s1 != s2 ) {
horz_pts[cpnt].x = fl_abs(down_left * Canv_w2 / horizon_vec.xyz.x);
horz_pts[cpnt].y = i2fl(Canvas_height)-1;
horz_pts[cpnt].edge = 3;
cpnt++;
}
if ( cpnt != 2 ) {
mprintf(( "HORZ: Wrong number of points (%d)\n", cpnt ));
return;
}
//make sure first edge is left
if ( horz_pts[0].x > horz_pts[1].x ) {
horz_pt tmp;
tmp = horz_pts[0];
horz_pts[0] = horz_pts[1];
horz_pts[1] = tmp;
}
// draw from left to right.
gr_line( fl2i(horz_pts[0].x),fl2i(horz_pts[0].y),fl2i(horz_pts[1].x),fl2i(horz_pts[1].y) );
}
/*
horizon_poly dw 5 dup (?,?) ;max of 5 points
;for g3_compute_horz_vecs
xfrac fix ?
yfrac fix ?
vec_ptr dd ?
corner_num dd ?
;for compute corner vec
m13 fix ? ;m1-m3
m46 fix ?
m79 fix ?
m56 fix ?
m23 fix ?
m89 fix ?
_DATA ends
_TEXT segment dword public USE32 'CODE'
extn gr_setcolor_,gr_clear_canvas_
extn gr_upoly_tmap_
;draw a polygon (one half of horizon) from the horizon line
draw_horz_poly: lea ebx,horizon_poly
;copy horizon line as first points in poly
mov eax,[edi]
mov [ebx],eax
mov eax,4[edi]
mov 4[ebx],eax
mov eax,[esi]
mov 8[ebx],eax
mov eax,4[esi]
mov 12[ebx],eax
;add corners to polygon
mov eax,8[esi] ;edge number of start edge
mov ecx,8[edi] ;edge number of end point
sub ecx,eax ;number of edges
jns edgenum_ok
add ecx,4
edgenum_ok:
mov edx,ecx ;save count
sal eax,3 ;edge * 8
lea esi,corners[eax] ;first corner
lea edi,16[ebx] ;rest of poly
corner_loop: movsd
movsd ;copy a corner
cmp esi,offset corners+8*4 ;end of list?
jne no_wrap
lea esi,corners
no_wrap: loop corner_loop
;now draw the polygon
mov eax,edx ;get corner count
add eax,2 ;..plus horz line end points
lea edx,horizon_poly ;get the points
;; call gr_poly_ ;draw it!
call gr_upoly_tmap_
ret
;return information on the polygon that is the sky.
;takes ebx=ptr to x,y pairs, ecx=ptr to vecs for each point
;returns eax=number of points
;IMPORTANT: g3_draw_horizon() must be called before this routine.
g3_compute_sky_polygon:
test sky_ground_flag,-1 ;what was drawn
js was_all_ground
jg was_all_sky
pushm ebx,ecx,edx,esi,edi
lea esi,left_point
lea edi,right_point
test color_swap,-1
jz no_swap_ends
xchg esi,edi ;sky isn't top
no_swap_ends:
;copy horizon line as first points in poly
mov eax,[edi] ;copy end point
mov [ebx],eax
mov eax,4[edi]
mov 4[ebx],eax
mov eax,[esi] ;copy start point
mov 8[ebx],eax
mov eax,4[esi]
mov 12[ebx],eax
pushm ebx,ecx
push edi ;save end point
push esi ;save start point
mov esi,edi ;end point is first point
mov edi,ecx ;dest buffer
call compute_horz_end_vec
pop esi ;get back start point
add edi,12 ;2nd vec
call compute_horz_end_vec
pop edi ;get back end point
popm ebx,ecx
add ebx,16 ;past two x,y pairs
add ecx,24 ;past two vectors
mov vec_ptr,ecx
;add corners to polygon
mov eax,8[esi] ;edge number of start edge
mov corner_num,eax
mov ecx,8[edi] ;edge number of end point
sub ecx,eax ;number of edges
jns edgenum_ok2
add ecx,4
edgenum_ok2:
push ecx ;save count
sal eax,3 ;edge * 8
lea esi,corners[eax] ;first corner
mov edi,ebx ;rest of poly 2d points
corner_loop2:
movsd
movsd ;copy a corner
cmp esi,offset corners+8*4 ;end of list?
jne no_wrap2
lea esi,corners
no_wrap2:
pushm ecx,esi,edi
mov edi,vec_ptr
mov eax,corner_num
call compute_corner_vec
add vec_ptr,12
inc corner_num
popm ecx,esi,edi
loop corner_loop2
;now return with count
pop eax ;get corner count
add eax,2 ;..plus horz line end points
popm ebx,ecx,edx,esi,edi
ret
;we drew all ground, so there was no horizon drawn
was_all_ground: xor eax,eax ;no points in poly
ret
;we drew all sky, so find 4 corners
was_all_sky: pushm ebx,ecx,edx,esi,edi
push ecx
lea esi,corners
mov edi,ebx
mov ecx,8
rep movsd
pop edi
mov ecx,4
xor eax,eax ;start corner 0
sky_loop: pushm eax,ecx,edi
call compute_corner_vec
popm eax,ecx,edi
add edi,12
inc eax
loop sky_loop
mov eax,4 ;4 corners
popm ebx,ecx,edx,esi,edi
ret
;compute vector describing horizon intersection with a point.
;takes esi=2d point, edi=vec. trashes eax,ebx,ecx,edx
compute_horz_end_vec:
;compute rotated x/z & y/z ratios
mov eax,[esi] ;get x coord
sub eax,Canv_w2
fixdiv Canv_w2
mov xfrac,eax ;save
mov eax,4[esi] ;get y coord
sub eax,Canv_h2
fixdiv Canv_h2
neg eax ;y inversion
mov yfrac,eax ;save
;compute fraction unrotated x/z
mov eax,xfrac
add eax,yfrac
mov ecx,eax ;save
fixmul View_matrix.m9
sub eax,View_matrix.m7
sub eax,View_matrix.m8
mov ebx,eax ;save numerator
mov eax,ecx
fixmul View_matrix.m3
mov ecx,eax
mov eax,View_matrix.m1
add eax,View_matrix.m2
sub eax,ecx
;now eax/ebx = z/x. do divide in way to give result < 0
pushm eax,ebx
abs_eax
xchg eax,ebx
abs_eax
cmp eax,ebx ;which is bigger?
popm eax,ebx
jl do_xz
;x is bigger, so do as z/x
fixdiv ebx
;now eax = z/x ratio. Compute vector by normalizing and correcting sign
push eax ;save ratio
imul eax ;compute z*z
inc edx ;+ x*x (x==1)
call quad_sqrt
mov ecx,eax ;mag in ecx
pop eax ;get ratio, x part
fixdiv ecx
mov [edi].xyz.z,eax
mov eax,f1_0
fixdiv ecx
mov [edi].xyz.x,eax
jmp finish_end
;z is bigger, so do as x/z
do_xz:
xchg eax,ebx
fixdiv ebx
;now eax = x/z ratio. Compute vector by normalizing and correcting sign
push eax ;save ratio
imul eax ;compute x*x
inc edx ;+ z*z (z==1)
call quad_sqrt
mov ecx,eax ;mag in ecx
pop eax ;get ratio, x part
fixdiv ecx
mov [edi].xyz.x,eax
mov eax,f1_0
fixdiv ecx
mov [edi].xyz.z,eax
finish_end: xor eax,eax ;y = 0
mov [edi].xyz.y,eax
;now make sure that this vector is in front of you, not behind
mov eax,[edi].xyz.x
imul View_matrix.m3
mov ebx,eax
mov ecx,edx
mov eax,[edi].xyz.z
imul View_matrix.m9
add eax,ebx
adc edx,ecx
jns vec_ok ;has positive z, ok
;z is neg, flip vector
neg [edi].xyz.x
neg [edi].xyz.z
vec_ok:
ret
MIN_DEN equ 7fffh
sub2 macro dest,src
mov eax,src
sal eax,1
sub dest,eax
endm
;compute vector decribing a corner of the screen.
;takes edi=vector, eax=corner num
compute_corner_vec:
cmp eax,4
jl num_ok
sub eax,4
num_ok:
;compute all deltas
mov ebx,View_matrix.m1
mov ecx,View_matrix.m4
mov edx,View_matrix.m7
or eax,eax
jz neg_x
cmp eax,3
jne no_neg_x
neg_x:
neg ebx
neg ecx
neg edx
no_neg_x:
sub ebx,View_matrix.m3
mov m13,ebx ;m1-m3
sub ecx,View_matrix.m6
mov m46,ecx ;m4-m6
sub edx,View_matrix.m9
mov m79,edx ;m7-m9
mov ebx,View_matrix.m5
mov ecx,View_matrix.m2
mov edx,View_matrix.m8
cmp eax,2
jl no_neg_y
neg_y:
neg ebx
neg ecx
neg edx
no_neg_y:
sub ebx,View_matrix.m6
mov m56,ebx ;m5-m6
sub ecx,View_matrix.m3
mov m23,ecx ;m2-m3
sub edx,View_matrix.m9
mov m89,edx ;m8-m9
;compute x/z ratio
;compute denomonator
mov eax,m46
fixmul m23
mov ebx,eax ;save
mov eax,m56
fixmul m13
sub eax,ebx ;eax = denominator
;now we have the denominator. If it is too small, try x/y, z/y or z/x, y/x
mov ecx,eax ;save den
abs_eax
cmp eax,MIN_DEN
jl z_too_small
z_too_small:
;now do x/z numerator
mov eax,m79
fixmul m56 ;* (m5-m6)
mov ebx,eax
mov eax,m89
fixmul m46 ;* (m4-m6)
sub eax,ebx
;now, eax/ecx = x/z ratio
fixdiv ecx ;eax = x/z
mov [edi].xyz.x,eax ;save x
;now do y/z
mov eax,m89
fixmul m13
mov ebx,eax
mov eax,m79
fixmul m23
sub eax,ebx
;now eax/ecx = y/z ratio
fixdiv ecx
mov [edi].xyz.y,eax
mov [edi].xyz.z,f1_0
mov esi,edi
call vm_vec_normalize
;make sure this vec is pointing in right direction
lea edi,View_matrix.vec.fvec
call vm_vec_dotprod
or eax,eax ;check sign
jg vec_sign_ok
neg [esi].xyz.x
neg [esi].xyz.y
neg [esi].xyz.z
vec_sign_ok:
ret
_TEXT ends
end
*/
// Draws a polygon always facing the viewer.
// compute the corners of a rod. fills in vertbuf.
// Verts has any needs uv's or l's or can be NULL if none needed.
int g3_draw_rod(vector *p0,float width1,vector *p1,float width2, vertex * verts, uint tmap_flags)
{
vector uvec, fvec, rvec, center;
vm_vec_sub( &fvec, p0, p1 );
vm_vec_normalize_safe( &fvec );
vm_vec_avg( &center, p0, p1 );
vm_vec_sub( &rvec, &Eye_position, &center );
vm_vec_normalize( &rvec );
vm_vec_crossprod(&uvec,&fvec,&rvec);
//normalize new perpendicular vector
vm_vec_normalize(&uvec);
//now recompute right vector, in case it wasn't entirely perpendiclar
vm_vec_crossprod(&rvec,&uvec,&fvec);
// Now have uvec, which is up vector and rvec which is the normal
// of the face.
int i;
vector vecs[4];
vertex pts[4];
vertex *ptlist[4] = { &pts[3], &pts[2], &pts[1], &pts[0] };
vm_vec_scale_add( &vecs[0], p0, &uvec, width1/2.0f );
vm_vec_scale_add( &vecs[1], p1, &uvec, width2/2.0f );
vm_vec_scale_add( &vecs[2], p1, &uvec, -width2/2.0f );
vm_vec_scale_add( &vecs[3], p0, &uvec, -width1/2.0f );
for (i=0; i<4; i++ ) {
if ( verts ) {
pts[i] = verts[i];
}
if(Cmdline_nohtl)g3_rotate_vertex( &pts[i], &vecs[i] );
else g3_rotate_vertex( &pts[i], &vecs[i] );
}
ptlist[0]->u = 0.0f;
ptlist[0]->v = 0.0f;
ptlist[1]->u = 1.0f;
ptlist[1]->v = 0.0f;
ptlist[2]->u = 1.0f;
ptlist[2]->v = 1.0f;
ptlist[3]->u = 0.0f;
ptlist[3]->v = 1.0f;
return g3_draw_poly(4,ptlist,tmap_flags);
}
// draw a perspective bitmap based on angles and radius
vector g3_square[4] = {
{-1.0f, -1.0f, 20.0f},
{-1.0f, 1.0f, 20.0f},
{1.0f, 1.0f, 20.0f},
{1.0f, -1.0f, 20.0f}
};
#define MAX_PERSPECTIVE_DIVISIONS 5 // should never even come close to this limit
void stars_project_2d_onto_sphere( vector *pnt, float rho, float phi, float theta )
{
float a = 3.14159f * phi;
float b = 6.28318f * theta;
float sin_a = (float)sin(a);
// coords
pnt->xyz.z = rho * sin_a * (float)cos(b);
pnt->xyz.y = rho * sin_a * (float)sin(b);
pnt->xyz.x = rho * (float)cos(a);
}
// draw a perspective bitmap based on angles and radius
float p_phi = 10.0f;
float p_theta = 10.0f;
int g3_draw_perspective_bitmap(angles *a, float scale_x, float scale_y, int div_x, int div_y, uint tmap_flags)
{
vector s_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
vector t_points[MAX_PERSPECTIVE_DIVISIONS+1][MAX_PERSPECTIVE_DIVISIONS+1];
vertex v[4];
vertex *verts[4];
matrix m, m_bank;
int idx, s_idx;
int saved_zbuffer_mode;
float ui, vi;
angles bank_first;
// cap division values
// div_x = div_x > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_x;
div_x = 1;
div_y = div_y > MAX_PERSPECTIVE_DIVISIONS ? MAX_PERSPECTIVE_DIVISIONS : div_y;
// texture increment values
ui = 1.0f / (float)div_x;
vi = 1.0f / (float)div_y;
// adjust for aspect ratio
scale_x *= ((float)gr_screen.max_w / (float)gr_screen.max_h) + 0.55f; // fudge factor
float s_phi = 0.5f + (((p_phi * scale_x) / 360.0f) / 2.0f);
float s_theta = (((p_theta * scale_y) / 360.0f) / 2.0f);
float d_phi = -(((p_phi * scale_x) / 360.0f) / (float)(div_x));
float d_theta = -(((p_theta * scale_y) / 360.0f) / (float)(div_y));
// bank matrix
bank_first.p = 0.0f;
bank_first.b = a->b;
bank_first.h = 0.0f;
vm_angles_2_matrix(&m_bank, &bank_first);
// convert angles to matrix
float b_save = a->b;
a->b = 0.0f;
vm_angles_2_matrix(&m, a);
a->b = b_save;
// generate the bitmap points
for(idx=0; idx<=div_x; idx++){
for(s_idx=0; s_idx<=div_y; s_idx++){
// get world spherical coords
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));
// bank the bitmap first
vm_vec_rotate(&t_points[idx][s_idx], &s_points[idx][s_idx], &m_bank);
// rotate on the sphere
vm_vec_rotate(&s_points[idx][s_idx], &t_points[idx][s_idx], &m);
}
}
// turn off zbuffering
saved_zbuffer_mode = gr_zbuffer_get();
gr_zbuffer_set(GR_ZBUFF_NONE);
// turn off culling
gr_set_cull(0);
#ifndef FRED_OGL
// draw the bitmap
if(Fred_running){
tmap_flags &= ~(TMAP_FLAG_CORRECT);
}
#endif
// render all polys
for(idx=0; idx<div_x; idx++){
for(s_idx=0; s_idx<div_y; s_idx++){
// stuff texture coords
v[0].u = ui * float(idx);
v[0].v = vi * float(s_idx);
v[0].spec_r=v[2].spec_g=v[3].spec_b=0;
v[1].u = ui * float(idx+1);
v[1].v = vi * float(s_idx);
v[1].spec_r=v[2].spec_g=v[3].spec_b=0;
v[2].u = ui * float(idx+1);
v[2].v = vi * float(s_idx+1);
v[2].spec_r=v[2].spec_g=v[3].spec_b=0;
v[3].u = ui * float(idx);
v[3].v = vi * float(s_idx+1);
v[3].spec_r=v[2].spec_g=v[3].spec_b=0;
// poly 1
v[0].flags = 0;
v[1].flags = 0;
v[2].flags = 0;
verts[0] = &v[0];
verts[1] = &v[1];
verts[2] = &v[2];
g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);
g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx]);
g3_rotate_faraway_vertex(verts[2], &s_points[idx+1][s_idx+1]);
g3_draw_poly(3, verts, tmap_flags);
// poly 2
v[0].flags = 0;
v[2].flags = 0;
v[3].flags = 0;
verts[0] = &v[0];
verts[1] = &v[2];
verts[2] = &v[3];
g3_rotate_faraway_vertex(verts[0], &s_points[idx][s_idx]);
g3_rotate_faraway_vertex(verts[1], &s_points[idx+1][s_idx+1]);
g3_rotate_faraway_vertex(verts[2], &s_points[idx][s_idx+1]);
g3_draw_poly(3, verts, tmap_flags);
}
}
// turn on culling
gr_set_cull(1);
// restore zbuffer
gr_zbuffer_set(saved_zbuffer_mode);
// return
return 1;
}
// draw a 2d bitmap on a poly
int g3_draw_2d_poly_bitmap(int x, int y, int w, int h, uint additional_tmap_flags)
{
int ret;
int saved_zbuffer_mode;
vertex v[4];
vertex *vertlist[4] = { &v[0], &v[1], &v[2], &v[3] };
memset(v,0,sizeof(vertex)*4);
int bw, bh;
g3_start_frame(1);
// turn off zbuffering
saved_zbuffer_mode = gr_zbuffer_get();
gr_zbuffer_set(GR_ZBUFF_NONE);
bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &bw, &bh);
// stuff coords
v[0].sx = (float)x;
v[0].sy = (float)y;
v[0].sw = 0.0f;
v[0].u = 0.0f;
v[0].v = 0.0f;
v[0].flags = PF_PROJECTED;
v[0].codes = 0;
v[1].sx = (float)(x + w);
v[1].sy = (float)y;
v[1].sw = 0.0f;
v[1].u = 1.0f;
v[1].v = 0.0f;
v[1].flags = PF_PROJECTED;
v[1].codes = 0;
v[2].sx = (float)(x + w);
v[2].sy = (float)(y + h);
v[2].sw = 0.0f;
v[2].u = 1.0f;
v[2].v = 1.0f;
v[2].flags = PF_PROJECTED;
v[2].codes = 0;
v[3].sx = (float)x;
v[3].sy = (float)(y + h);
v[3].sw = 0.0f;
v[3].u = 0.0f;
v[3].v = 1.0f;
v[3].flags = PF_PROJECTED;
v[3].codes = 0;
/*
v[0].u = 0.5f / i2fl(bw);
v[0].v = 0.5f / i2fl(bh);
v[1].u = 1.0f + (0.5f / i2fl(bw));
v[1].v = 0.0f + (0.5f / i2fl(bh));
v[2].u = 1.0f + (0.5f / i2fl(bw));
v[2].v = 1.0f + (0.5f / i2fl(bh));
v[3].u = 0.0f + (0.5f / i2fl(bw));
v[3].v = 1.0f + (0.5f / i2fl(bh));
*/
// no filtering
gr_filter_set(0);
// set debrief
ret = g3_draw_poly_constant_sw(4, vertlist, TMAP_FLAG_TEXTURED | additional_tmap_flags, 0.1f);
g3_end_frame();
gr_zbuffer_set(saved_zbuffer_mode);
// put filtering back on
gr_filter_set(1);
return ret;
}