mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
475 lines
10 KiB
C++
475 lines
10 KiB
C++
#include "RendererConfig.h"
|
|
#ifdef USE_SOFTWARE_TNL
|
|
|
|
#include "3d.h"
|
|
#include "SoftwareInternal.h"
|
|
#include "renderer.h"
|
|
|
|
#define round(v) ( (int)( ((v) + 0.5f) ) )
|
|
|
|
//draws a line. takes two points. returns true if drew
|
|
void g3_DrawLine(ddgr_color color,g3Point *p0,g3Point *p1)
|
|
{
|
|
ubyte codes_or;
|
|
bool was_clipped=0;
|
|
|
|
if (p0->p3_codes & p1->p3_codes)
|
|
return;
|
|
|
|
codes_or = p0->p3_codes | p1->p3_codes;
|
|
|
|
if (codes_or)
|
|
{
|
|
ClipLine(&p0,&p1,codes_or);
|
|
was_clipped = 1;
|
|
}
|
|
|
|
if (!(p0->p3_flags & PF_PROJECTED))
|
|
{
|
|
g3_ProjectPoint(p0);
|
|
}
|
|
|
|
if (!(p1->p3_flags & PF_PROJECTED))
|
|
{
|
|
g3_ProjectPoint(p1);
|
|
}
|
|
|
|
rend_SetFlatColor (color);
|
|
rend_DrawLine( round(p0->p3_sx),round(p0->p3_sy),round(p1->p3_sx),round(p1->p3_sy));
|
|
|
|
//If was clipped, free temp points
|
|
if (was_clipped)
|
|
{
|
|
if (p0->p3_flags & PF_TEMP_POINT)
|
|
{
|
|
FreeTempPoint(p0);
|
|
}
|
|
|
|
if (p1->p3_flags & PF_TEMP_POINT)
|
|
{
|
|
FreeTempPoint(p1);
|
|
}
|
|
|
|
//Make sure all temp points have been freed
|
|
CheckTempPoints();
|
|
}
|
|
}
|
|
|
|
//draws a line based on the current setting of render states. takes two points. returns true if drew
|
|
void g3_DrawSpecialLine(g3Point *p0,g3Point *p1)
|
|
{
|
|
ubyte codes_or;
|
|
bool was_clipped=0;
|
|
|
|
if (p0->p3_codes & p1->p3_codes)
|
|
return;
|
|
|
|
codes_or = p0->p3_codes | p1->p3_codes;
|
|
|
|
if (codes_or)
|
|
{
|
|
|
|
ClipLine(&p0,&p1,codes_or);
|
|
|
|
was_clipped = 1;
|
|
}
|
|
|
|
if (!(p0->p3_flags & PF_PROJECTED))
|
|
g3_ProjectPoint(p0);
|
|
|
|
if (!(p1->p3_flags & PF_PROJECTED))
|
|
g3_ProjectPoint(p1);
|
|
|
|
rend_DrawSpecialLine (p0,p1);
|
|
|
|
//If was clipped, free temp points
|
|
if (was_clipped)
|
|
{
|
|
if (p0->p3_flags & PF_TEMP_POINT)
|
|
FreeTempPoint(p0);
|
|
|
|
if (p1->p3_flags & PF_TEMP_POINT)
|
|
FreeTempPoint(p1);
|
|
|
|
//Make sure all temp points have been freed
|
|
CheckTempPoints();
|
|
}
|
|
}
|
|
|
|
//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
|
|
bool g3_CheckNormalFacing(vector *v,vector *norm)
|
|
{
|
|
vector tempv;
|
|
|
|
tempv = View_position - *v;
|
|
|
|
return ((tempv * *norm) > 0);
|
|
}
|
|
|
|
bool DoFacingCheck(vector *norm,g3Point **vertlist,vector *p)
|
|
{
|
|
if (norm)
|
|
{
|
|
//have normal
|
|
ASSERT(norm->x || norm->y || norm->z);
|
|
return g3_CheckNormalFacing(p,norm);
|
|
}
|
|
else
|
|
{
|
|
//normal not specified, so must compute
|
|
vector tempv;
|
|
//get three points (rotated) and compute normal
|
|
vm_GetPerp(&tempv,&vertlist[0]->p3_vec,&vertlist[1]->p3_vec,&vertlist[2]->p3_vec);
|
|
return ((tempv * vertlist[1]->p3_vec) < 0);
|
|
}
|
|
}
|
|
|
|
//like g3_DrawPoly(), 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_CheckNormalFacing() plus
|
|
//g3_DrawPoly().
|
|
void g3_CheckAndDrawPoly(int nv,g3Point **pointlist,int bm,vector *norm,vector *pnt)
|
|
{
|
|
if (DoFacingCheck(norm,pointlist,pnt))
|
|
g3_DrawPoly(nv,pointlist,bm);
|
|
}
|
|
|
|
int Triangulate_test = 0;
|
|
|
|
//draw a polygon
|
|
//Parameters: nv - the number of verts in the poly
|
|
// pointlist - a pointer to a list of pointers to points
|
|
// bm - the bitmap handle if texturing. ignored if flat shading
|
|
// Returns 0 if clipped away
|
|
int g3_DrawPoly(int nv,g3Point **pointlist,int bm,int map_type,g3Codes *clip_codes)
|
|
{
|
|
int i;
|
|
g3Codes cc;
|
|
bool was_clipped=0;
|
|
|
|
if (Triangulate_test)
|
|
{
|
|
if (nv > 3)
|
|
{
|
|
g3Point *tripoints[3];
|
|
int sum=0;
|
|
|
|
for (i=0;i<nv-2;i++)
|
|
{
|
|
tripoints[0] = pointlist[0];
|
|
tripoints[1] = pointlist[i+1];
|
|
tripoints[2] = pointlist[i+2];
|
|
sum+=g3_DrawPoly(3,tripoints,bm,map_type);
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
}
|
|
|
|
//Initialize or just used the ones passed in
|
|
if (clip_codes)
|
|
{
|
|
cc=*clip_codes;
|
|
}
|
|
else
|
|
{
|
|
cc.cc_or = 0; cc.cc_and = 0xff;
|
|
|
|
//Get codes for this polygon, and copy uvls into points
|
|
for (i=0;i<nv;i++)
|
|
{
|
|
ubyte c;
|
|
|
|
c = pointlist[i]->p3_codes;
|
|
|
|
cc.cc_and &= c;
|
|
cc.cc_or |= c;
|
|
}
|
|
}
|
|
|
|
//All points off screen?
|
|
if (cc.cc_and)
|
|
return 0;
|
|
|
|
//One or more point off screen, so clip
|
|
if (cc.cc_or)
|
|
{
|
|
|
|
//Clip the polygon, getting pointer to new buffer
|
|
pointlist = g3_ClipPolygon(pointlist,&nv,&cc);
|
|
|
|
//Flag as clipped so temp points will be freed
|
|
was_clipped = 1;
|
|
|
|
//Check for polygon clipped away, or clip otherwise failed
|
|
if ((nv==0) || (cc.cc_or&CC_BEHIND) || cc.cc_and)
|
|
goto free_points;
|
|
}
|
|
|
|
//Make list of 2d coords (& check for overflow)
|
|
for (i=0;i<nv;i++)
|
|
{
|
|
g3Point *p = pointlist[i];
|
|
|
|
//Project if needed
|
|
if (!(p->p3_flags&PF_PROJECTED))
|
|
g3_ProjectPoint(p);
|
|
|
|
}
|
|
|
|
//Draw!
|
|
rend_DrawPolygon3D( bm, pointlist, nv, map_type );
|
|
|
|
free_points:;
|
|
|
|
//If was clipped, free temp points
|
|
if (was_clipped)
|
|
g3_FreeTempPoints(pointlist,nv);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
|
|
//radius, but not to the distance from the eye
|
|
void g3_DrawSphere(ddgr_color color,g3Point *pnt,float rad)
|
|
{
|
|
if (! (pnt->p3_codes & CC_BEHIND))
|
|
{
|
|
if (! (pnt->p3_flags & PF_PROJECTED))
|
|
g3_ProjectPoint(pnt);
|
|
|
|
rend_FillCircle(color, pnt->p3_sx, pnt->p3_sy,(rad * Matrix_scale.x * Window_w2 / pnt->p3_z));
|
|
}
|
|
}
|
|
|
|
//draws a bitmap with the specified 3d width & height
|
|
// If offsets are not -1, then the blitter draws not from the upper left hand
|
|
// corner of the bitmap, but from size*offsetx,size*offsety
|
|
// See Jason for explaination
|
|
void g3_DrawBitmap(vector *pos,float width,float height,int bm,int color)
|
|
{
|
|
// get the view orientation
|
|
matrix viewOrient;
|
|
g3_GetUnscaledMatrix( &viewOrient );
|
|
|
|
// break down the color into components
|
|
float r, g, b;
|
|
if( color != -1 )
|
|
{
|
|
float scale = 1.0f / 255.0f;
|
|
r = GR_COLOR_RED(color) * scale;
|
|
g = GR_COLOR_GREEN(color) * scale;
|
|
b = GR_COLOR_BLUE(color) * scale;
|
|
}
|
|
|
|
// calculate the four corners
|
|
g3Point corners[4], *pts[4];
|
|
int i;
|
|
for( i = 0; i < 4; ++i )
|
|
{
|
|
pts[i] = &corners[i];
|
|
|
|
// calculate the offset for this corner
|
|
float cornerScaleU = ((i&1) ^ ((i&2)>>1)) ? 1.0f : -1.0f;
|
|
float cornerScaleV = (i&2) ? 1.0f : -1.0f;
|
|
|
|
// find the point (parallel to the view frame)
|
|
vector cornerPos = *pos + (viewOrient.uvec * (height * -cornerScaleV)) + (viewOrient.rvec * (width * cornerScaleU));
|
|
corners[i].p3_codes = 0;
|
|
g3_RotatePoint( pts[i], &cornerPos );
|
|
|
|
// setup the flags, UVs and colors
|
|
corners[i].p3_flags |= PF_UV;
|
|
corners[i].p3_uvl.u = (cornerScaleU * 0.5f) + 0.5f;
|
|
corners[i].p3_uvl.v = (cornerScaleV * 0.5f) + 0.5f;
|
|
if( color == -1 )
|
|
{
|
|
corners[i].p3_flags |= PF_L;
|
|
corners[i].p3_uvl.l = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
corners[i].p3_flags |= PF_RGBA;
|
|
corners[i].p3_uvl.r = r;
|
|
corners[i].p3_uvl.g = g;
|
|
corners[i].p3_uvl.b = b;
|
|
}
|
|
corners[i].p3_uvl.a = 1.0f;
|
|
}
|
|
|
|
rend_SetTextureType( TT_LINEAR );
|
|
rend_DrawPolygon3D( bm, pts, 4 );
|
|
}
|
|
|
|
// Draws a bitmap that has been rotated about its center. Angle of rotation is passed as 'rot_angle'
|
|
void g3_DrawRotatedBitmap(vector *pos,angle rot_angle,float width,float height,int bm,int color)
|
|
{
|
|
g3Point pnt,rot_points[8],*pntlist[8];
|
|
vector rot_vectors[4];
|
|
matrix rot_matrix;
|
|
float w,h;
|
|
int i;
|
|
|
|
if (g3_RotatePoint(&pnt,pos) & CC_BEHIND)
|
|
return;
|
|
|
|
if (pnt.p3_codes & CC_OFF_FAR)
|
|
return;
|
|
|
|
vm_AnglesToMatrix (&rot_matrix,0,0,rot_angle);
|
|
|
|
rot_matrix.rvec*=Matrix_scale.x;
|
|
rot_matrix.uvec*=Matrix_scale.y;
|
|
|
|
|
|
w = width;
|
|
h = height;
|
|
|
|
rot_vectors[0].x=-w;
|
|
rot_vectors[0].y=h;
|
|
|
|
rot_vectors[1].x=w;
|
|
rot_vectors[1].y=h;
|
|
|
|
rot_vectors[2].x=w;
|
|
rot_vectors[2].y=-h;
|
|
|
|
rot_vectors[3].x=-w;
|
|
rot_vectors[3].y=-h;
|
|
|
|
for (i=0;i<4;i++)
|
|
{
|
|
rot_vectors[i].z=0;
|
|
vm_MatrixMulVector (&rot_points[i].p3_vec,&rot_vectors[i],&rot_matrix);
|
|
|
|
rot_points[i].p3_flags=PF_UV|PF_RGBA;
|
|
rot_points[i].p3_l=1.0;
|
|
rot_points[i].p3_vec+=pnt.p3_vec;
|
|
|
|
g3_CodePoint (&rot_points[i]);
|
|
pntlist[i]=&rot_points[i];
|
|
}
|
|
|
|
rot_points[0].p3_u=0;
|
|
rot_points[0].p3_v=0;
|
|
|
|
rot_points[1].p3_u=1;
|
|
rot_points[1].p3_v=0;
|
|
|
|
rot_points[2].p3_u=1;
|
|
rot_points[2].p3_v=1;
|
|
|
|
rot_points[3].p3_u=0;
|
|
rot_points[3].p3_v=1;
|
|
|
|
// And draw!!
|
|
rend_SetTextureType (TT_LINEAR);
|
|
|
|
if (color!=-1)
|
|
{
|
|
rend_SetLighting (LS_FLAT_GOURAUD);
|
|
rend_SetFlatColor (color);
|
|
}
|
|
|
|
g3_DrawPoly (4,pntlist,bm);
|
|
}
|
|
|
|
// Draws a bitmap on a specific plane. Also does rotation. Angle of rotation is passed as 'rot_angle'
|
|
void g3_DrawPlanarRotatedBitmap (vector *pos,vector *norm,angle rot_angle,float width,float height,int bm)
|
|
{
|
|
g3Point rot_points[8],*pntlist[8];
|
|
vector rot_vectors[4];
|
|
matrix rot_matrix;
|
|
matrix twist_matrix;
|
|
float w,h;
|
|
int i;
|
|
|
|
vm_VectorToMatrix (&rot_matrix,norm,NULL,NULL);
|
|
vm_TransposeMatrix (&rot_matrix);
|
|
|
|
vm_AnglesToMatrix (&twist_matrix,0,0,rot_angle);
|
|
|
|
w = width;
|
|
h = height;
|
|
|
|
rot_vectors[0]=(twist_matrix.rvec*-w);
|
|
rot_vectors[0]+=(twist_matrix.uvec*h);
|
|
|
|
rot_vectors[1]=(twist_matrix.rvec*w);
|
|
rot_vectors[1]+=(twist_matrix.uvec*h);
|
|
|
|
rot_vectors[2]=(twist_matrix.rvec*w);
|
|
rot_vectors[2]-=(twist_matrix.uvec*h);
|
|
|
|
rot_vectors[3]=(twist_matrix.rvec*-w);
|
|
rot_vectors[3]-=(twist_matrix.uvec*h);
|
|
|
|
for (i=0;i<4;i++)
|
|
{
|
|
vector temp_vec=rot_vectors[i];
|
|
vm_MatrixMulVector (&rot_vectors[i],&temp_vec,&rot_matrix);
|
|
}
|
|
|
|
for (i=0;i<4;i++)
|
|
{
|
|
rot_vectors[i]+=*pos;
|
|
|
|
g3_RotatePoint (&rot_points[i],&rot_vectors[i]);
|
|
|
|
rot_points[i].p3_flags|=PF_UV|PF_RGBA;
|
|
rot_points[i].p3_l=1.0;
|
|
|
|
pntlist[i]=&rot_points[i];
|
|
}
|
|
|
|
rot_points[0].p3_u=0;
|
|
rot_points[0].p3_v=0;
|
|
|
|
rot_points[1].p3_u=1;
|
|
rot_points[1].p3_v=0;
|
|
|
|
rot_points[2].p3_u=1;
|
|
rot_points[2].p3_v=1;
|
|
|
|
rot_points[3].p3_u=0;
|
|
rot_points[3].p3_v=1;
|
|
|
|
// And draw!!
|
|
rend_SetTextureType (TT_LINEAR);
|
|
g3_DrawPoly (4,pntlist,bm);
|
|
}
|
|
|
|
|
|
//Draw a wireframe box aligned with the screen. Used for the editor.
|
|
//Parameters: color - the color to draw the lines
|
|
// pnt - the center point
|
|
// rad - specifies the width/2 & height/2 of the box
|
|
void g3_DrawBox(ddgr_color color,g3Point *pnt,float rad)
|
|
{
|
|
if (! (pnt->p3_codes & CC_BEHIND))
|
|
{
|
|
if (! (pnt->p3_flags & PF_PROJECTED))
|
|
g3_ProjectPoint(pnt);
|
|
|
|
float w,h;
|
|
|
|
w = rad * Matrix_scale.x * Window_w2 / pnt->p3_z;
|
|
h = rad * Matrix_scale.y * Window_h2 / pnt->p3_z;
|
|
|
|
rend_DrawLine(round(pnt->p3_sx-w),round(pnt->p3_sy-h),round(pnt->p3_sx+w),round(pnt->p3_sy-h));
|
|
rend_DrawLine(round(pnt->p3_sx+w),round(pnt->p3_sy-h),round(pnt->p3_sx+w),round(pnt->p3_sy+h));
|
|
rend_DrawLine(round(pnt->p3_sx+w),round(pnt->p3_sy+h),round(pnt->p3_sx-w),round(pnt->p3_sy+h));
|
|
rend_DrawLine(round(pnt->p3_sx-w),round(pnt->p3_sy+h),round(pnt->p3_sx-w),round(pnt->p3_sy-h));
|
|
}
|
|
}
|
|
|
|
// Sets the triangulation test to on or off
|
|
void g3_SetTriangulationTest (int state)
|
|
{
|
|
Triangulate_test = state;
|
|
}
|
|
|
|
#endif
|