mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
726
Code/ww3d2/visrasterizer.cpp
Normal file
726
Code/ww3d2/visrasterizer.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : ww3d *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/visrasterizer.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 11/24/01 5:42p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "visrasterizer.h"
|
||||
#include "camera.h"
|
||||
#include "plane.h"
|
||||
#include "vp.h"
|
||||
|
||||
|
||||
/**
|
||||
** VisPolyClass - This class is used to clip polygons as they are
|
||||
** sent through the vis rasterization system
|
||||
*/
|
||||
class VisPolyClass
|
||||
{
|
||||
public:
|
||||
void Reset(void);
|
||||
void Add_Vertex(const Vector3 & point);
|
||||
void Clip(const PlaneClass & plane,VisPolyClass & dest) const;
|
||||
|
||||
SimpleDynVecClass<Vector3> Verts;
|
||||
};
|
||||
|
||||
|
||||
void VisPolyClass::Reset(void)
|
||||
{
|
||||
Verts.Delete_All(false);
|
||||
}
|
||||
|
||||
void VisPolyClass::Add_Vertex(const Vector3 & point)
|
||||
{
|
||||
Verts.Add(point);
|
||||
}
|
||||
|
||||
void VisPolyClass::Clip(const PlaneClass & plane,VisPolyClass & dest) const
|
||||
{
|
||||
dest.Reset();
|
||||
|
||||
// temporary variables used in clipping
|
||||
int i = 0;
|
||||
int vcount = Verts.Count();
|
||||
int iprev = vcount - 1;
|
||||
bool cur_point_in_front;
|
||||
bool prev_point_in_front;
|
||||
float alpha;
|
||||
Vector3 int_point;
|
||||
|
||||
if (vcount <= 2) return;
|
||||
|
||||
// perform clipping
|
||||
prev_point_in_front = !plane.In_Front(Verts[iprev]); // Note, plane normal is outward so we invert this test
|
||||
for (int j=0; j<vcount; j++) {
|
||||
|
||||
cur_point_in_front = !plane.In_Front(Verts[i]); // Note, plane nomral is out so we invert this test
|
||||
if (prev_point_in_front) {
|
||||
|
||||
if (cur_point_in_front) {
|
||||
|
||||
// Previous vertex was in front of plane and this vertex is in
|
||||
// front of the plane so we emit this vertex.
|
||||
dest.Add_Vertex(Verts[i]);
|
||||
|
||||
} else {
|
||||
|
||||
// Previous vert was in front, this vert is behind, compute
|
||||
// the intersection and emit the point.
|
||||
plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
|
||||
Lerp(Verts[iprev],Verts[i],alpha,&int_point);
|
||||
dest.Add_Vertex(int_point);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cur_point_in_front) {
|
||||
|
||||
// segment is going from the back halfspace to the front halfspace
|
||||
// compute the intersection and emit it, then continue
|
||||
// the edge into the front halfspace and emit the end point.
|
||||
plane.Compute_Intersection(Verts[iprev],Verts[i],&alpha);
|
||||
Lerp(Verts[iprev],Verts[i],alpha,&int_point);
|
||||
dest.Add_Vertex(int_point);
|
||||
dest.Add_Vertex(Verts[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
prev_point_in_front = cur_point_in_front;
|
||||
iprev = i;
|
||||
|
||||
//i = (i+1)%(Verts.Count());
|
||||
i++;
|
||||
if (i>=vcount) {
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VisPolyClass _VisPoly0;
|
||||
static VisPolyClass _VisPoly1;
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************************
|
||||
|
||||
VisRasterizerClass Implementation
|
||||
|
||||
*********************************************************************************************/
|
||||
|
||||
|
||||
VisRasterizerClass::VisRasterizerClass(void) :
|
||||
ModelTransform(1),
|
||||
Camera(NULL),
|
||||
MVTransform(1)
|
||||
{
|
||||
}
|
||||
|
||||
VisRasterizerClass::~VisRasterizerClass(void)
|
||||
{
|
||||
REF_PTR_RELEASE(Camera);
|
||||
}
|
||||
|
||||
void VisRasterizerClass::Set_Resolution(int width,int height)
|
||||
{
|
||||
IDBuffer.Set_Resolution(width,height);
|
||||
}
|
||||
|
||||
void VisRasterizerClass::Get_Resolution(int * set_width,int * set_height)
|
||||
{
|
||||
IDBuffer.Get_Resolution(set_width,set_height);
|
||||
}
|
||||
|
||||
void VisRasterizerClass::Set_Model_Transform(const Matrix3D & model)
|
||||
{
|
||||
ModelTransform = model;
|
||||
Update_MV_Transform();
|
||||
}
|
||||
|
||||
void VisRasterizerClass::Set_Camera(CameraClass * camera)
|
||||
{
|
||||
REF_PTR_SET(Camera,camera);
|
||||
Update_MV_Transform();
|
||||
}
|
||||
|
||||
CameraClass * VisRasterizerClass::Get_Camera(void)
|
||||
{
|
||||
if (Camera != NULL) {
|
||||
Camera->Add_Ref();
|
||||
}
|
||||
return Camera;
|
||||
}
|
||||
|
||||
CameraClass * VisRasterizerClass::Peek_Camera(void)
|
||||
{
|
||||
return Camera;
|
||||
}
|
||||
|
||||
void VisRasterizerClass::Update_MV_Transform(void)
|
||||
{
|
||||
Matrix3D view_tm(1);
|
||||
|
||||
if (Camera) {
|
||||
Camera->Get_View_Matrix(&view_tm);
|
||||
}
|
||||
|
||||
MVTransform = view_tm * ModelTransform;
|
||||
}
|
||||
|
||||
const Matrix3D & VisRasterizerClass::Get_MV_Transform(void)
|
||||
{
|
||||
// TODO: optimize this
|
||||
Update_MV_Transform(); // the user can and does mess with the camera directly!
|
||||
return MVTransform;
|
||||
}
|
||||
|
||||
Vector3 * VisRasterizerClass::Get_Temp_Vertex_Buffer(int count)
|
||||
{
|
||||
TempVertexBuffer.Uninitialised_Grow(count);
|
||||
return &(TempVertexBuffer[0]);
|
||||
}
|
||||
|
||||
|
||||
bool VisRasterizerClass::Render_Triangles
|
||||
(
|
||||
const Vector3 * verts,
|
||||
int vcount,
|
||||
const TriIndex * tris,
|
||||
int tcount,const
|
||||
AABoxClass & bounds
|
||||
)
|
||||
{
|
||||
WWASSERT(verts != NULL);
|
||||
WWASSERT(tris != NULL);
|
||||
WWASSERT(vcount > 0);
|
||||
WWASSERT(tcount > 0);
|
||||
|
||||
/*
|
||||
** if the user supplied bounds, check if we need to clip
|
||||
*/
|
||||
if (CollisionMath::Overlap_Test(Camera->Get_Frustum(),bounds) == CollisionMath::INSIDE) {
|
||||
return Render_Triangles_No_Clip(verts,vcount,tris,tcount);
|
||||
} else {
|
||||
return Render_Triangles_Clip(verts,vcount,tris,tcount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool VisRasterizerClass::Render_Triangles_No_Clip
|
||||
(
|
||||
const Vector3 * verts,
|
||||
int vcount,
|
||||
const TriIndex * tris,
|
||||
int tcount
|
||||
)
|
||||
{
|
||||
bool pixel_passed = false;
|
||||
|
||||
/*
|
||||
** 1. transform verts into homogeneous view space and project
|
||||
*/
|
||||
const Matrix3D & tm = Get_MV_Transform();
|
||||
Vector3 * tverts = Get_Temp_Vertex_Buffer(vcount);
|
||||
|
||||
VectorProcessorClass::Transform(tverts,verts,tm,vcount);
|
||||
|
||||
for (int i=0; i<vcount; i++) {
|
||||
Camera->Project_Camera_Space_Point(tverts[i],tverts[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
** 2. Pass triangles on to the ID buffer for scan conversion
|
||||
*/
|
||||
for (int tri_index=0; tri_index<tcount; tri_index++) {
|
||||
|
||||
const TriIndex & tri = tris[tri_index];
|
||||
pixel_passed |= IDBuffer.Render_Triangle(tverts[tri.I],tverts[tri.J],tverts[tri.K]);
|
||||
if (pixel_passed && (IDBuffer.Get_Render_Mode() == IDBufferClass::NON_OCCLUDER_MODE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return pixel_passed;
|
||||
}
|
||||
|
||||
|
||||
bool VisRasterizerClass::Render_Triangles_Clip
|
||||
(
|
||||
const Vector3 * verts,
|
||||
int vcount,
|
||||
const TriIndex * tris,
|
||||
int tcount
|
||||
)
|
||||
{
|
||||
bool pixel_passed = false;
|
||||
|
||||
/*
|
||||
** 1. transform triangles into homogeneous view space
|
||||
*/
|
||||
const Matrix3D & tm = Get_MV_Transform();
|
||||
Vector3 * tverts = Get_Temp_Vertex_Buffer(vcount);
|
||||
|
||||
VectorProcessorClass::Transform(tverts,verts,tm,vcount);
|
||||
|
||||
/*
|
||||
** 2. get the frustum clipping planes
|
||||
*/
|
||||
const PlaneClass *planes = Camera->Get_View_Space_Frustum_Planes();
|
||||
|
||||
/*
|
||||
** 3. Clip triangles to the view volume and pass on to the ID buffer for scan conversion
|
||||
*/
|
||||
for (int tri_index=0; tri_index<tcount; tri_index++) {
|
||||
|
||||
/*
|
||||
** Copy triangle data into the vis clipping structure
|
||||
*/
|
||||
_VisPoly0.Reset();
|
||||
_VisPoly0.Add_Vertex(tverts[tris[tri_index].I]);
|
||||
_VisPoly0.Add_Vertex(tverts[tris[tri_index].J]);
|
||||
_VisPoly0.Add_Vertex(tverts[tris[tri_index].K]);
|
||||
|
||||
/*
|
||||
** Clip against the view frustum
|
||||
*/
|
||||
_VisPoly0.Clip(planes[0],_VisPoly1);
|
||||
_VisPoly1.Clip(planes[1],_VisPoly0);
|
||||
_VisPoly0.Clip(planes[2],_VisPoly1);
|
||||
_VisPoly1.Clip(planes[3],_VisPoly0);
|
||||
_VisPoly0.Clip(planes[4],_VisPoly1);
|
||||
_VisPoly1.Clip(planes[5],_VisPoly0);
|
||||
|
||||
/*
|
||||
** Project the vertices
|
||||
*/
|
||||
int final_vcount = _VisPoly0.Verts.Count();
|
||||
|
||||
if (final_vcount >= 3) {
|
||||
|
||||
Vector3 * final_verts = &(_VisPoly0.Verts[0]);
|
||||
|
||||
int i;
|
||||
for (i=0; i<final_vcount; i++) {
|
||||
Camera->Project_Camera_Space_Point(final_verts[i],final_verts[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Pass the resulting triangle fan to the IDBuffer
|
||||
*/
|
||||
for (i=1; i<final_vcount - 1; i++) {
|
||||
|
||||
pixel_passed |= IDBuffer.Render_Triangle(final_verts[0],final_verts[i],final_verts[i+1]);
|
||||
if (pixel_passed && (IDBuffer.Get_Render_Mode() == IDBufferClass::NON_OCCLUDER_MODE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pixel_passed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************************
|
||||
|
||||
IDBufferClass Implementation
|
||||
|
||||
*********************************************************************************************/
|
||||
|
||||
IDBufferClass::IDBufferClass(void) :
|
||||
BackfaceID(0),
|
||||
FrontfaceID(0),
|
||||
CurID(0),
|
||||
RenderMode(OCCLUDER_MODE),
|
||||
TwoSidedRenderingEnabled(false),
|
||||
PixelCounter(0),
|
||||
ResWidth(0),
|
||||
ResHeight(0),
|
||||
IDBuffer(NULL),
|
||||
ZBuffer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IDBufferClass::~IDBufferClass(void)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void IDBufferClass::Set_Resolution(int w,int h)
|
||||
{
|
||||
if ((w == ResWidth) && (h == ResHeight)) {
|
||||
return;
|
||||
} else {
|
||||
ResWidth = w;
|
||||
ResHeight = h;
|
||||
Allocate_Buffers();
|
||||
}
|
||||
}
|
||||
|
||||
void IDBufferClass::Get_Resolution(int * get_w,int * get_h)
|
||||
{
|
||||
if (get_w != NULL) { *get_w = ResWidth; }
|
||||
if (get_h != NULL) { *get_h = ResHeight; }
|
||||
}
|
||||
|
||||
void IDBufferClass::Reset(void)
|
||||
{
|
||||
if (IDBuffer!=NULL) {
|
||||
delete[] IDBuffer;
|
||||
IDBuffer = NULL;
|
||||
}
|
||||
if (ZBuffer != NULL) {
|
||||
delete[] ZBuffer;
|
||||
ZBuffer = NULL;
|
||||
}
|
||||
PixelCounter = 0;
|
||||
}
|
||||
|
||||
void IDBufferClass::Allocate_Buffers(void)
|
||||
{
|
||||
Reset();
|
||||
|
||||
int bufsize = ResWidth * ResHeight;
|
||||
|
||||
if (bufsize > 0) {
|
||||
IDBuffer = new uint32 [bufsize];
|
||||
ZBuffer = new float [bufsize];
|
||||
}
|
||||
}
|
||||
|
||||
void IDBufferClass::Clear(void)
|
||||
{
|
||||
if ((ResWidth > 0) && (ResHeight > 0)) {
|
||||
int byte_count = ResWidth * ResWidth * sizeof(uint32);
|
||||
|
||||
WWASSERT(IDBuffer != NULL);
|
||||
WWASSERT(ZBuffer != NULL);
|
||||
memset(IDBuffer,0,byte_count);
|
||||
memset(ZBuffer,0,byte_count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** GradientsStruct
|
||||
** Computes the gradients for a triangle.
|
||||
*/
|
||||
struct GradientsStruct
|
||||
{
|
||||
GradientsStruct(const Vector3 * verts)
|
||||
{
|
||||
float oodx = 1 / ( ((verts[1].X - verts[2].X) * (verts[0].Y - verts[2].Y)) -
|
||||
((verts[0].X - verts[2].X) * (verts[1].Y - verts[2].Y)));
|
||||
float oody = -oodx;
|
||||
|
||||
for(int i=0; i<3; i++) {
|
||||
OOZ[i] = 1/verts[i].Z;
|
||||
}
|
||||
|
||||
DOOZ_DX = oodx * ( ((OOZ[1] - OOZ[2]) * (verts[0].Y - verts[2].Y)) -
|
||||
((OOZ[0] - OOZ[2]) * (verts[1].Y - verts[2].Y)));
|
||||
|
||||
DOOZ_DY = oody * ( ((OOZ[1] - OOZ[2]) * (verts[0].X - verts[2].X)) -
|
||||
((OOZ[0] - OOZ[2]) * (verts[1].X - verts[2].X)));
|
||||
}
|
||||
|
||||
float OOZ[3]; // 1/z for each vertex
|
||||
float DOOZ_DX; // change in 1/z per change in x
|
||||
float DOOZ_DY; // change in 1/z per change in y
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** EdgeStruct
|
||||
** Can accurately scan convert an edge of a triangle.
|
||||
*/
|
||||
struct EdgeStruct
|
||||
{
|
||||
EdgeStruct(const GradientsStruct & grad,const Vector3 * verts,int top,int bottom)
|
||||
{
|
||||
Y = WWMath::Ceil(verts[top].Y);
|
||||
Height = WWMath::Ceil(verts[bottom].Y) - Y;
|
||||
|
||||
float y_prestep = Y - verts[top].Y;
|
||||
float real_height = verts[bottom].Y - verts[top].Y;
|
||||
float real_width = verts[bottom].X - verts[top].X;
|
||||
|
||||
X = ((real_width * y_prestep)/real_height) + verts[top].X;
|
||||
XStep = real_width / real_height;
|
||||
float x_prestep = X - verts[top].X;
|
||||
|
||||
OOZ = grad.OOZ[top] + y_prestep * grad.DOOZ_DY + x_prestep * grad.DOOZ_DX;
|
||||
OOZStep = XStep * grad.DOOZ_DX + grad.DOOZ_DY;
|
||||
}
|
||||
|
||||
inline int Step(void)
|
||||
{
|
||||
X+=XStep;
|
||||
Y++;
|
||||
Height--;
|
||||
OOZ+=OOZStep;
|
||||
return Height;
|
||||
}
|
||||
|
||||
float X; // fractional x coord
|
||||
float XStep; // change in x per scanline
|
||||
int Y; // current y coord
|
||||
int Height; // number of scanlines left
|
||||
float OOZ; // current 1/z
|
||||
float OOZStep; // change in 1/z per scanline
|
||||
};
|
||||
|
||||
|
||||
bool IDBufferClass::Render_Triangle(const Vector3 & p0,const Vector3 & p1,const Vector3 & p2)
|
||||
{
|
||||
if ((ZBuffer == NULL) || (IDBuffer == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int pixels_passed = 0;
|
||||
bool is_backfacing = Is_Backfacing(p0,p1,p2);
|
||||
|
||||
if ((is_backfacing) && (TwoSidedRenderingEnabled == false)) {
|
||||
if (RenderMode == NON_OCCLUDER_MODE) {
|
||||
return false;
|
||||
}
|
||||
CurID = BackfaceID;
|
||||
} else {
|
||||
CurID = FrontfaceID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Transform the coordinates to device coords
|
||||
** All coordinates come in with the range -1 -> +1
|
||||
*/
|
||||
Vector3 points[3];
|
||||
points[0].X = 0.5f * (p0.X + 1.0f) * ResWidth;
|
||||
points[1].X = 0.5f * (p1.X + 1.0f) * ResWidth;
|
||||
points[2].X = 0.5f * (p2.X + 1.0f) * ResWidth;
|
||||
|
||||
points[0].Y = 0.5f * (1.0f - p0.Y) * ResHeight;
|
||||
points[1].Y = 0.5f * (1.0f - p1.Y) * ResHeight;
|
||||
points[2].Y = 0.5f * (1.0f - p2.Y) * ResHeight;
|
||||
|
||||
points[0].Z = 0.5f * (p0.Z + 1.001f) * 1000.0f;
|
||||
points[1].Z = 0.5f * (p1.Z + 1.001f) * 1000.0f;
|
||||
points[2].Z = 0.5f * (p2.Z + 1.001f) * 1000.0f;
|
||||
|
||||
/*
|
||||
** Sort points based on Y
|
||||
*/
|
||||
float y0 = points[0].Y;
|
||||
float y1 = points[1].Y;
|
||||
float y2 = points[2].Y;
|
||||
|
||||
int top,middle,bottom,middle_for_compare,bottom_for_compare;
|
||||
|
||||
if(y0 < y1) {
|
||||
if(y2 < y0) {
|
||||
top = 2; middle = 0; bottom = 1;
|
||||
middle_for_compare = 0; bottom_for_compare = 1;
|
||||
} else {
|
||||
top = 0;
|
||||
if(y1 < y2) {
|
||||
middle = 1; bottom = 2;
|
||||
middle_for_compare = 1; bottom_for_compare = 2;
|
||||
} else {
|
||||
middle = 2; bottom = 1;
|
||||
middle_for_compare = 2; bottom_for_compare = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(y2 < y1) {
|
||||
top = 2; middle = 1; bottom = 0;
|
||||
middle_for_compare = 1; bottom_for_compare = 0;
|
||||
} else {
|
||||
top = 1;
|
||||
if(y0 < y2) {
|
||||
middle = 0; bottom = 2;
|
||||
middle_for_compare = 3; bottom_for_compare = 2;
|
||||
} else {
|
||||
middle = 2; bottom = 0;
|
||||
middle_for_compare = 2; bottom_for_compare = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the gradients and set up the edge structures
|
||||
*/
|
||||
GradientsStruct grads(points);
|
||||
EdgeStruct top_to_bottom_edge(grads,points,top,bottom);
|
||||
EdgeStruct top_to_middle_edge(grads,points,top,middle);
|
||||
EdgeStruct middle_to_bottom_edge(grads,points,middle,bottom);
|
||||
|
||||
EdgeStruct * left_edge = NULL;
|
||||
EdgeStruct * right_edge = NULL;
|
||||
|
||||
bool middle_is_left = false;
|
||||
if (bottom_for_compare > middle_for_compare) {
|
||||
middle_is_left = 1 ^ is_backfacing;
|
||||
} else {
|
||||
middle_is_left = 0 ^ is_backfacing;
|
||||
}
|
||||
if (middle_is_left) {
|
||||
left_edge = &top_to_middle_edge;
|
||||
right_edge = &top_to_bottom_edge;
|
||||
} else {
|
||||
left_edge = &top_to_bottom_edge;
|
||||
right_edge = &top_to_middle_edge;
|
||||
}
|
||||
|
||||
/*
|
||||
** Fill scanlines
|
||||
*/
|
||||
int height = top_to_middle_edge.Height;
|
||||
|
||||
while (height--) {
|
||||
if (RenderMode == OCCLUDER_MODE) {
|
||||
pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
|
||||
} else {
|
||||
pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
|
||||
}
|
||||
left_edge->Step();
|
||||
right_edge->Step();
|
||||
}
|
||||
|
||||
if (middle_is_left) {
|
||||
left_edge = &middle_to_bottom_edge;
|
||||
right_edge = &top_to_bottom_edge;
|
||||
} else {
|
||||
left_edge = &top_to_bottom_edge;
|
||||
right_edge = &middle_to_bottom_edge;
|
||||
}
|
||||
|
||||
height = middle_to_bottom_edge.Height;
|
||||
|
||||
while (height--) {
|
||||
if (RenderMode == OCCLUDER_MODE) {
|
||||
pixels_passed += Render_Occluder_Scanline(grads,left_edge,right_edge);
|
||||
} else {
|
||||
pixels_passed += Render_Non_Occluder_Scanline(grads,left_edge,right_edge);
|
||||
}
|
||||
left_edge->Step();
|
||||
right_edge->Step();
|
||||
}
|
||||
return (pixels_passed > 0);
|
||||
}
|
||||
|
||||
|
||||
int IDBufferClass::Render_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
|
||||
{
|
||||
if ((left->Y < 1) || (left->Y >= ResHeight)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1.0f));
|
||||
int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
|
||||
if (xstart + width > ResWidth) {
|
||||
width = ResWidth - xstart;
|
||||
}
|
||||
|
||||
float xprestep = (float)xstart - left->X;
|
||||
int address = Pixel_Coords_To_Address(xstart,left->Y);
|
||||
float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
|
||||
int pixel_counter = 0;
|
||||
|
||||
/*
|
||||
** Two separate loops, backfaces only render when LESS THAN
|
||||
*/
|
||||
if (CurID == BackfaceID) {
|
||||
while (width-- > 0) {
|
||||
if (ooz > ZBuffer[address]) {
|
||||
IDBuffer[address] = CurID;
|
||||
ZBuffer[address] = ooz;
|
||||
pixel_counter++;
|
||||
}
|
||||
ooz += grads.DOOZ_DX;
|
||||
address++;
|
||||
}
|
||||
/*
|
||||
** Front faces render when LESS THAN OR EQUAL TO
|
||||
*/
|
||||
} else {
|
||||
while (width-- > 0) {
|
||||
if (ooz >= ZBuffer[address]) {
|
||||
IDBuffer[address] = CurID;
|
||||
ZBuffer[address] = ooz;
|
||||
pixel_counter++;
|
||||
}
|
||||
ooz += grads.DOOZ_DX;
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
PixelCounter += pixel_counter;
|
||||
return pixel_counter;
|
||||
}
|
||||
|
||||
|
||||
int IDBufferClass::Render_Non_Occluder_Scanline(GradientsStruct & grads,EdgeStruct * left,EdgeStruct * right)
|
||||
{
|
||||
if ((left->Y < 1) || (left->Y >= ResHeight)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xstart = WWMath::Float_To_Long(WWMath::Max(WWMath::Ceil(left->X),1));
|
||||
int width = WWMath::Float_To_Long(WWMath::Ceil(right->X)) - xstart;
|
||||
if (xstart + width > ResWidth) {
|
||||
width = ResWidth - xstart;
|
||||
}
|
||||
|
||||
float xprestep = (float)xstart - left->X;
|
||||
int address = Pixel_Coords_To_Address(xstart,left->Y);
|
||||
float ooz = left->OOZ + xprestep * grads.DOOZ_DX;
|
||||
|
||||
while (width-- > 0) {
|
||||
if (ooz >= ZBuffer[address]) {
|
||||
PixelCounter++;
|
||||
return 1;
|
||||
}
|
||||
ooz += grads.DOOZ_DX;
|
||||
address++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user