| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 |
- /*
- ** Command & Conquer Generals(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;
- }
- }
|