784 lines
30 KiB
C++
784 lines
30 KiB
C++
/*
|
|
** Command & Conquer Generals Zero Hour(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/>.
|
|
*/
|
|
|
|
/* $Header: /Commando/Code/Tools/max2w3d/vxllayer.cpp 4 10/28/97 6:08p Greg_h $ */
|
|
/***********************************************************************************************
|
|
*** Confidential - Westwood Studios ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Commando / G *
|
|
* *
|
|
* File Name : VXLLAYER.CPP *
|
|
* *
|
|
* Programmer : Greg Hjelstrom *
|
|
* *
|
|
* Start Date : 06/10/97 *
|
|
* *
|
|
* Last Update : June 10, 1997 [GH] *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* VoxelLayerClass::VoxelLayerClass -- Constructor for VoxelLayerClass *
|
|
* VoxelLayerClass::Intersect_Triangle -- Intersect a triangle with the slab *
|
|
* VoxelLayerClass::Draw_Line -- Draw a line of voxels into the slab *
|
|
* VoxelLayerClass::Scan_Triangle -- Clip and scan-convert a triangle into the slab *
|
|
* clip_tri_to_slab -- Clips a triangle against a voxel slab *
|
|
* clip_poly -- clip a polygon against a single 3D plane *
|
|
* output -- Emit a vertex into a polygons vertex list *
|
|
* inside -- Test whether a point is in the front half-space of a plane *
|
|
* intersect -- compute intersection between a line and a plane *
|
|
* clear_scan_table -- clears the static scanline table *
|
|
* fixup_scan_table -- ensure all spans are left->right in order *
|
|
* scan_edge -- Scan convert an edge *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
|
#include "vxllayer.h"
|
|
#include "plane.h"
|
|
|
|
|
|
/***************************************************************************************
|
|
** local types
|
|
***************************************************************************************/
|
|
struct vertexstruct
|
|
{
|
|
Point3 Pos;
|
|
Point3 Bary;
|
|
};
|
|
|
|
struct scanstruct
|
|
{
|
|
vertexstruct P[2];
|
|
};
|
|
|
|
|
|
/***************************************************************************************
|
|
** static data
|
|
***************************************************************************************/
|
|
static scanstruct _scantab[256];
|
|
|
|
const int LEFT = 0;
|
|
const int RIGHT = 1;
|
|
const float EMPTY_SPAN = -10000.0f;
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
** local functions
|
|
***************************************************************************************/
|
|
static void clip_tri_to_slab(
|
|
Point3 p0,
|
|
Point3 p1,
|
|
Point3 p2,
|
|
float z0,
|
|
float z1,
|
|
vertexstruct * outverts,
|
|
int * setnum);
|
|
|
|
static void clip_poly(
|
|
vertexstruct * inverts,
|
|
int innum,
|
|
vertexstruct * outverts,
|
|
int * outnum,
|
|
const PlaneClass & clipplane);
|
|
|
|
static void output(
|
|
const vertexstruct & outvert,
|
|
vertexstruct * poly,
|
|
int * numverts);
|
|
|
|
static int inside(
|
|
const vertexstruct & p,
|
|
const PlaneClass & plane);
|
|
|
|
static vertexstruct intersect(
|
|
const vertexstruct & p0,
|
|
const vertexstruct & p1,
|
|
const PlaneClass & plane);
|
|
|
|
static void clear_scan_table(void);
|
|
|
|
static void fixup_scan_table(
|
|
int y0,
|
|
int y1);
|
|
|
|
static void scan_edge(
|
|
const vertexstruct & p0,
|
|
const vertexstruct & p1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* VoxelLayerClass::VoxelLayerClass -- Constructor for VoxelLayerClass *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
VoxelLayerClass::VoxelLayerClass
|
|
(
|
|
INodeListClass & object_list,
|
|
TimeValue time,
|
|
Matrix3 parenttm,
|
|
Point3 offset,
|
|
Point3 scale,
|
|
float slicez,
|
|
float sliceh,
|
|
int bmwidth,
|
|
int bmheight
|
|
)
|
|
{
|
|
unsigned i;
|
|
|
|
SliceZ = slicez;
|
|
SliceH = sliceh;
|
|
SliceZ0 = slicez - sliceh / 2;
|
|
SliceZ1 = slicez + sliceh / 2;
|
|
|
|
bitmap_width = bmwidth;
|
|
bitmap_height = bmheight;
|
|
|
|
// Initialize everything with zero
|
|
memset ( &(Solid[0][0]), 0, sizeof(Solid));
|
|
|
|
// Go through the list of objects and intersect them with the plane.
|
|
for ( i = 0; i < object_list.Num_Nodes(); i++ )
|
|
{
|
|
// Get relavent data from MAX
|
|
INode * inode = object_list[i];
|
|
Object * obj = inode->EvalWorldState(time).obj;
|
|
TriObject * tri = (TriObject *)obj->ConvertToType(time, triObjectClassID);
|
|
Mesh * mesh = &(tri->mesh);
|
|
Matrix3 objtm = inode->GetObjectTM(time);
|
|
|
|
// Compute a delta matrix which puts vertices into the parent space
|
|
Matrix3 delta = objtm * Inverse(parenttm);
|
|
|
|
// Loop through each face, intersecting it with the slice.
|
|
unsigned faces = mesh->getNumFaces();
|
|
for ( unsigned face_index = 0; face_index < faces; ++ face_index )
|
|
{
|
|
Face & face = mesh->faces [ face_index ];
|
|
|
|
// transform the vertices into the parent space
|
|
Point3 a = mesh->verts [ face.v[0] ] * delta;
|
|
Point3 b = mesh->verts [ face.v[1] ] * delta;
|
|
Point3 c = mesh->verts [ face.v[2] ] * delta;
|
|
|
|
// shift the vertices to the origin
|
|
a.x -= offset.x;
|
|
a.y -= offset.y;
|
|
b.x -= offset.x;
|
|
b.y -= offset.y;
|
|
c.x -= offset.x;
|
|
c.y -= offset.y;
|
|
|
|
// scale the vertices into the voxel grid
|
|
a.x *= scale.x;
|
|
a.y *= scale.y;
|
|
b.x *= scale.x;
|
|
b.y *= scale.y;
|
|
c.x *= scale.x;
|
|
c.y *= scale.y;
|
|
|
|
// Intersect_Triangle ( a, b, c, SliceZ );
|
|
Scan_Triangle( a, b, c );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* VoxelLayerClass::Intersect_Triangle -- Intersect a triangle with the slab *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
void VoxelLayerClass::Intersect_Triangle
|
|
(
|
|
Point3 a,
|
|
Point3 b,
|
|
Point3 c,
|
|
float z
|
|
)
|
|
{
|
|
double start_x, start_y, end_x, end_y;
|
|
|
|
// If the triangle is wholly above or below the intersection plane,
|
|
// it does not intersect with the plane.
|
|
if ( a.z < z && b.z < z && c.z < z )
|
|
return;
|
|
|
|
if ( a.z > z && b.z > z && c.z > z )
|
|
return;
|
|
|
|
// Find the upward intersection moving counterclockwise. This will be
|
|
// the start of the edge.
|
|
if ( a.z < z && b.z >= z )
|
|
{
|
|
start_x = a.x + (b.x - a.x) * (z - a.z) / (b.z - a.z);
|
|
start_y = a.y + (b.y - a.y) * (z - a.z) / (b.z - a.z);
|
|
}
|
|
else if ( b.z < z && c.z >= z )
|
|
{
|
|
start_x = b.x + (c.x - b.x) * (z - b.z) / (c.z - b.z);
|
|
start_y = b.y + (c.y - b.y) * (z - b.z) / (c.z - b.z);
|
|
}
|
|
else if ( c.z < z && a.z >= z )
|
|
{
|
|
start_x = c.x + (a.x - c.x) * (z - c.z) / (a.z - c.z);
|
|
start_y = c.y + (a.y - c.y) * (z - c.z) / (a.z - c.z);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Find the downward intersection moving counterclockwise. This is the end
|
|
// of the edge.
|
|
if ( a.z >= z && b.z < z )
|
|
{
|
|
end_x = a.x + (b.x - a.x) * (z - a.z) / (b.z - a.z);
|
|
end_y = a.y + (b.y - a.y) * (z - a.z) / (b.z - a.z);
|
|
}
|
|
else if ( b.z >= z && c.z < z )
|
|
{
|
|
end_x = b.x + (c.x - b.x) * (z - b.z) / (c.z - b.z);
|
|
end_y = b.y + (c.y - b.y) * (z - b.z) / (c.z - b.z);
|
|
}
|
|
else if ( c.z >= z && a.z < z )
|
|
{
|
|
end_x = c.x + (a.x - c.x) * (z - c.z) / (a.z - c.z);
|
|
end_y = c.y + (a.y - c.y) * (z - c.z) / (a.z - c.z);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Draw the edge into the bitmap.
|
|
Draw_Line(start_x, start_y, end_x, end_y);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* VoxelLayerClass::Draw_Line -- Draw a line of voxels into the slab *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
void VoxelLayerClass::Draw_Line
|
|
(
|
|
double x0,
|
|
double y0,
|
|
double x1,
|
|
double y1
|
|
)
|
|
{
|
|
// Fill in the squares containing the line's endpoints.
|
|
Add_Solid((int)x0, (int)y0);
|
|
Add_Solid((int)x1, (int)y1);
|
|
|
|
// Fill in the squares between the endpoints.
|
|
double delta_x = fabs (x1 - x0);
|
|
double delta_y = fabs (y1 - y0);
|
|
|
|
if ( delta_x > delta_y )
|
|
{
|
|
// This is an X-major line.
|
|
if ( x0 > x1 )
|
|
{
|
|
double temp = x0;
|
|
x0 = x1;
|
|
x1 = temp;
|
|
|
|
temp = y0;
|
|
y0 = y1;
|
|
y1 = temp;
|
|
}
|
|
|
|
double step_y = (y1 - y0) / delta_x;
|
|
|
|
double y = y0 + step_y * (floor (x0 + 1) - x0);
|
|
|
|
for ( int x = (int) x0; x < (int) x1; ++ x )
|
|
{
|
|
if ( (int) y >= 0 && (int) y < bitmap_height )
|
|
{
|
|
Add_Solid(x, (int)y);
|
|
Add_Solid(x + 1, (int)y);
|
|
}
|
|
|
|
y += step_y;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is a Y-major line.
|
|
if ( y0 > y1 )
|
|
{
|
|
double temp = x0;
|
|
x0 = x1;
|
|
x1 = temp;
|
|
|
|
temp = y0;
|
|
y0 = y1;
|
|
y1 = temp;
|
|
}
|
|
|
|
double step_x = (x1 - x0) / delta_y;
|
|
|
|
double x = x0 + step_x * (floor (y0 + 1) - y0);
|
|
|
|
for ( int y = (int) y0; y < (int) y1; ++ y )
|
|
{
|
|
if ( (int) x >= 0 && (int) x < 256 )
|
|
{
|
|
Add_Solid((int)x, y);
|
|
Add_Solid((int)x, y+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* VoxelLayerClass::Scan_Triangle -- Clip and scan-convert a triangle into the slab *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
void VoxelLayerClass::Scan_Triangle
|
|
(
|
|
Point3 p0,
|
|
Point3 p1,
|
|
Point3 p2
|
|
)
|
|
{
|
|
int i;
|
|
|
|
// check if the entire triangle is above or below the slab:
|
|
if (p0.z < SliceZ0 && p1.z < SliceZ0 && p2.z < SliceZ1) return;
|
|
if (p0.z > SliceZ1 && p1.z > SliceZ1 && p2.z > SliceZ1) return;
|
|
|
|
// clip the triangle to the slab
|
|
vertexstruct polyvert[8];
|
|
int numverts;
|
|
|
|
clip_tri_to_slab(p0,p1,p2,SliceZ0,SliceZ1,polyvert,&numverts);
|
|
if (numverts == 0) return;
|
|
|
|
// clear the scanline table, get y-extents of polygon
|
|
clear_scan_table();
|
|
|
|
float miny = polyvert[0].Pos.y;
|
|
float maxy = polyvert[0].Pos.y;
|
|
|
|
for (i=1; i<numverts; i++) {
|
|
if (polyvert[i].Pos.y < miny) miny = polyvert[i].Pos.y;
|
|
if (polyvert[i].Pos.y > maxy) maxy = polyvert[i].Pos.y;
|
|
}
|
|
|
|
// scanconvert the triangle
|
|
int start = numverts - 1;
|
|
for (i=0; i<numverts; i++) {
|
|
scan_edge(polyvert[start],polyvert[i]);
|
|
start = i;
|
|
}
|
|
|
|
// make sure all scans go left-right.
|
|
fixup_scan_table((int)floor(miny),(int)floor(maxy));
|
|
|
|
// draw the scanlines
|
|
for (i=(int)floor(miny); i<=(int)floor(maxy); i++) {
|
|
|
|
// if (_scantab[i].P[LEFT].Pos.x != EMPTY_SPAN) {
|
|
|
|
Draw_Line(
|
|
_scantab[i].P[LEFT].Pos.x,
|
|
_scantab[i].P[LEFT].Pos.y,
|
|
_scantab[i].P[RIGHT].Pos.x,
|
|
_scantab[i].P[RIGHT].Pos.y);
|
|
// }
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* clip_tri_to_slab -- Clips a triangle against a voxel slab *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void clip_tri_to_slab
|
|
(
|
|
Point3 p0,
|
|
Point3 p1,
|
|
Point3 p2,
|
|
float z0,
|
|
float z1,
|
|
vertexstruct * outverts,
|
|
int * setnum
|
|
)
|
|
{
|
|
static vertexstruct tmpverts[8];
|
|
|
|
memset(outverts,0,sizeof(outverts));
|
|
memset(tmpverts,0,sizeof(tmpverts));
|
|
|
|
// copy the three intial points:
|
|
outverts[0].Pos = p0;
|
|
outverts[1].Pos = p1;
|
|
outverts[2].Pos = p2;
|
|
outverts[0].Bary = Point3(1.0f,0.0f,0.0f);
|
|
outverts[1].Bary = Point3(0.0f,1.0f,0.0f);
|
|
outverts[2].Bary = Point3(0.0f,0.0f,1.0f);
|
|
|
|
// clip from the out buffer to the tmp buffer against bottom of slab:
|
|
clip_poly(outverts,3,tmpverts,setnum,PlaneClass(Vector3(0.0f,0.0f,1.0f),-z0));
|
|
|
|
// clip from the tmp buffer to the out buffer against top of slab:
|
|
clip_poly(tmpverts,*setnum,outverts,setnum,PlaneClass(Vector3(0.0f,0.0f,-1.0f),z1));
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* clip_poly -- clip a polygon against a single 3D plane *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void clip_poly
|
|
(
|
|
vertexstruct * inverts,
|
|
int innum,
|
|
vertexstruct * outverts,
|
|
int * outnum,
|
|
const PlaneClass & clipplane
|
|
)
|
|
{
|
|
vertexstruct p0,p1; // start and end of current edge
|
|
vertexstruct pi; // intersection point
|
|
int i;
|
|
|
|
// start with zero vertices
|
|
*outnum = 0;
|
|
|
|
p0 = inverts[innum-1];
|
|
for (i=0; i<innum; i++) {
|
|
p1 = inverts[i];
|
|
|
|
if (inside(p1,clipplane)) {
|
|
if (inside(p0,clipplane)) {
|
|
output(p1,outverts,outnum); //both inside: output p1
|
|
} else {
|
|
pi = intersect(p0,p1,clipplane);
|
|
output(pi,outverts,outnum); //p0 out, p1 in: output intersect and p1
|
|
output(p1,outverts,outnum);
|
|
}
|
|
} else {
|
|
if (inside(p0,clipplane)) {
|
|
pi = intersect(p0,p1,clipplane); //p0 in, p1 out: output intersect
|
|
output(pi,outverts,outnum);
|
|
}
|
|
}
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* output -- Emit a vertex into a polygons vertex list *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void output
|
|
(
|
|
const vertexstruct & outvert,
|
|
vertexstruct * poly,
|
|
int * numverts
|
|
)
|
|
{
|
|
poly[*numverts] = outvert;
|
|
(*numverts)++;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* inside -- Test whether a point is in the front half-space of a plane *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static int inside
|
|
(
|
|
const vertexstruct & p,
|
|
const PlaneClass & plane
|
|
)
|
|
{
|
|
float dist = p.Pos.x * plane.N[0] + p.Pos.y * plane.N[1] + p.Pos.z * plane.N[2] + plane.D;
|
|
if (dist >= 0.0f) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* intersect -- compute intersection between a line and a plane *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static vertexstruct intersect
|
|
(
|
|
const vertexstruct & p0,
|
|
const vertexstruct & p1,
|
|
const PlaneClass & plane
|
|
)
|
|
{
|
|
float t;
|
|
|
|
Point3 delta = p1.Pos - p0.Pos;
|
|
|
|
float num = -( plane.N[0] * p0.Pos.x +
|
|
plane.N[1] * p0.Pos.y +
|
|
plane.N[2] * p0.Pos.z + plane.D );
|
|
|
|
float den = plane.N[0] * delta.x +
|
|
plane.N[1] * delta.y +
|
|
plane.N[2] * delta.z;
|
|
|
|
if (den != 0.0f) {
|
|
t = num / den;
|
|
} else {
|
|
t = 0.0f;
|
|
}
|
|
|
|
vertexstruct i;
|
|
i.Pos = (1.0f - t) * p0.Pos + t*p1.Pos;
|
|
i.Bary = (1.0f - t) * p0.Bary + t*p1.Bary;
|
|
return i;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* clear_scan_table -- clears the static scanline table *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void clear_scan_table(void)
|
|
{
|
|
memset(_scantab,0,sizeof(_scantab));
|
|
for (int i=0; i<256; i++) {
|
|
_scantab[i].P[0].Pos.x = EMPTY_SPAN;
|
|
_scantab[i].P[1].Pos.x = EMPTY_SPAN;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* fixup_scan_table -- ensure all spans are left->right in order *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void fixup_scan_table(int y0,int y1)
|
|
{
|
|
int i;
|
|
assert(y1 >= y0);
|
|
|
|
// Ensure the left -> right convention is followed.
|
|
for (i=y0; i<=y1; i++) {
|
|
if (_scantab[i].P[LEFT].Pos.x > _scantab[i].P[RIGHT].Pos.x) {
|
|
vertexstruct tmp = _scantab[i].P[LEFT];
|
|
_scantab[i].P[LEFT] = _scantab[i].P[RIGHT];
|
|
_scantab[i].P[RIGHT] = tmp;
|
|
}
|
|
}
|
|
|
|
// Ensure that we leave no gaps.
|
|
for (i=y0; i<y1; i++) {
|
|
if (_scantab[i+1].P[RIGHT].Pos.x < _scantab[i].P[LEFT].Pos.x) {
|
|
|
|
_scantab[i+1].P[RIGHT].Pos.x = _scantab[i].P[LEFT].Pos.x;
|
|
|
|
} else if (_scantab[i+1].P[LEFT].Pos.x > _scantab[i].P[RIGHT].Pos.x) {
|
|
|
|
_scantab[i+1].P[LEFT].Pos.x = _scantab[i].P[RIGHT].Pos.x;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* scan_edge -- Scan convert an edge *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/10/1997 GH : Created. *
|
|
*=============================================================================================*/
|
|
static void scan_edge
|
|
(
|
|
const vertexstruct & p0,
|
|
const vertexstruct & p1
|
|
)
|
|
{
|
|
// is this a perfectly horizontal edge:
|
|
if (floor(p0.Pos.y) == floor(p1.Pos.y)) {
|
|
|
|
int si = (int)floor(p0.Pos.y);
|
|
const vertexstruct *left, *right;
|
|
|
|
if (p0.Pos.x < p1.Pos.x) {
|
|
left = &p0;
|
|
right = &p1;
|
|
} else {
|
|
left = &p1;
|
|
right = &p0;
|
|
}
|
|
|
|
// does this scanline already have a span in it?
|
|
if (_scantab[si].P[0].Pos.x != EMPTY_SPAN) {
|
|
|
|
// yes, expand this scanline's span to include this span
|
|
if (left->Pos.x < _scantab[si].P[LEFT].Pos.x) {
|
|
_scantab[si].P[LEFT] = *left;
|
|
}
|
|
|
|
if (right->Pos.x > _scantab[si].P[RIGHT].Pos.x) {
|
|
_scantab[si].P[RIGHT] = *right;
|
|
}
|
|
|
|
} else {
|
|
|
|
// no, set this scanline with the span for this edge
|
|
_scantab[si].P[LEFT] = *left;
|
|
_scantab[si].P[RIGHT] = *right;
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
// is this a left or right edge:
|
|
int side;
|
|
const vertexstruct *top, *bot;
|
|
|
|
if (p0.Pos.y < p1.Pos.y) {
|
|
side = RIGHT;
|
|
top = &p0;
|
|
bot = &p1;
|
|
} else {
|
|
side = LEFT;
|
|
top = &p1;
|
|
bot = &p0;
|
|
}
|
|
|
|
// scan the edge into _scantab
|
|
for (double y = floor(top->Pos.y); y <= floor(bot->Pos.y); y += 1.0f) {
|
|
|
|
// parametric position on the scanline:
|
|
double t = (y - floor(top->Pos.y)) / (floor(bot->Pos.y) - floor(top->Pos.y));
|
|
|
|
// position:
|
|
_scantab[(int)y].P[side].Pos = (1.0f - (float)t)*top->Pos + (float)t*bot->Pos;
|
|
|
|
// barycentric coords:
|
|
_scantab[(int)y].P[side].Bary = (1.0f - (float)t)*top->Bary + (float)t*bot->Bary;
|
|
}
|
|
}
|