From 74c751e19780c1ea383c9d6397c4732f7df358a4 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Fri, 6 Sep 2019 21:20:16 -0500 Subject: [PATCH] Added visible poly list and painters algorithm. Something is very broken. --- j3d/build-All.sh | 2 +- j3d/j3d.c | 143 +++++++++++++++++++++++++++++++++++++++++------ j3d/j3d.h | 38 ++++++++----- j3d/main.c | 9 ++- j3d/pyramid.obj | 12 ++++ 5 files changed, 171 insertions(+), 33 deletions(-) create mode 100644 j3d/pyramid.obj diff --git a/j3d/build-All.sh b/j3d/build-All.sh index 854ac30..49aaed1 100755 --- a/j3d/build-All.sh +++ b/j3d/build-All.sh @@ -2,7 +2,7 @@ PROJECT=j3d GAME=${JOEY}/j3d/j3d -DATA=(${GAME}/cube.j3d ${GAME}/font.sta) +DATA=(${GAME}/cube.j3d ${GAME}/pyramid.j3d ${GAME}/font.sta) #SOURCE=(*.c *.h) SOURCE=() diff --git a/j3d/j3d.c b/j3d/j3d.c index f408420..1a1227d 100644 --- a/j3d/j3d.c +++ b/j3d/j3d.c @@ -55,21 +55,32 @@ segment "j3d"; #endif +typedef int (*j3qsortCastT)(const void *, const void *); + + +int _j3PolyCompare(j3PolyListT *arg1, j3PolyListT *arg2); + + // Module global data -jint16 _j3VarClipMinX = 0; -jint16 _j3VarClipMinY = 0; -jint16 _j3VarClipMinZ = 100; -jint16 _j3VarClipMaxX = 319; -jint16 _j3VarClipMaxY = 199; -jint16 _j3VarClipMaxZ = 3000; -jint16 _j3VarViewDistance = 250; -float _j3VarAmbientLight = 6; -j3Matrix4x4T _j3VarCameraMatrix; -j3VertexT _j3VarCameraLocation; -j3FacingT _j3VarCameraAngle; -bool _j3VarCameraLocationDirty = true; -bool _j3VarCameraAngleDirty = true; -j3VertexT _j3VarSunLocation; +jint16 _j3VarClipMinX = 0; +jint16 _j3VarClipMinY = 0; +jint16 _j3VarClipMinZ = 100; +jint16 _j3VarClipMaxX = 319; +jint16 _j3VarClipMaxY = 199; +jint16 _j3VarClipMaxZ = 3000; +jint16 _j3VarViewDistance = 200; +float _j3VarAmbientLight = 6; +j3Matrix4x4T _j3VarCameraMatrix; +j3VertexT _j3VarCameraLocation; +j3FacingT _j3VarCameraAngle; +bool _j3VarCameraLocationDirty = true; +bool _j3VarCameraAngleDirty = true; +j3VertexT _j3VarSunLocation; + +//***TODO*** None of this should be global - put inside world +j3PolyListT *_j3Polygons = NULL; +juint16 _j3PolygonCount = 0; // Current visible polygons +juint16 _j3TriangleCount = 0; // Current triangles in world #define ASPECT_RATIO (float)0.8 @@ -404,6 +415,65 @@ void _j3DrawWireframe(j3ObjectT *o) { } +void j3DrawWorld(j3WorldT *w) { + jint16 i; + juint16 vertex1; + juint16 vertex2; + juint16 vertex3; + float x1; + float y1; + float z1; + float x2; + float y2; + float z2; + float x3; + float y3; + float z3; + j3ObjectT *o; + j3PolyListT *p; + + //***TODO*** Fix + (void)w; + + for (i=0; i<_j3PolygonCount; i++) { + + // Dereference + p = &_j3Polygons[i]; + o = p->object; + + vertex1 = o->triangles[p->triangleNumber].index[0]; + vertex2 = o->triangles[p->triangleNumber].index[1]; + vertex3 = o->triangles[p->triangleNumber].index[2]; + z1 = o->verticies[vertex1].camera.z; + z2 = o->verticies[vertex2].camera.z; + z3 = o->verticies[vertex3].camera.z; + + // Perform z clipping + if ((z1 < _j3VarClipMinZ && z2 < _j3VarClipMinZ && z3 < _j3VarClipMinZ) || (z1 > _j3VarClipMaxZ && z2 > _j3VarClipMaxZ && z3 > _j3VarClipMaxZ)) { + continue; + } + + // Extract points of triangle + x1 = o->verticies[vertex1].camera.x; + y1 = o->verticies[vertex1].camera.y; + x2 = o->verticies[vertex2].camera.x; + y2 = o->verticies[vertex2].camera.y; + x3 = o->verticies[vertex3].camera.x; + y3 = o->verticies[vertex3].camera.y; + + // Screen position of points + x1 = HALF_SCREEN_WIDTH + x1 * _j3VarViewDistance / z1; + y1 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y1 * _j3VarViewDistance / z1; + x2 = HALF_SCREEN_WIDTH + x2 * _j3VarViewDistance / z2; + y2 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y2 * _j3VarViewDistance / z2; + x3 = HALF_SCREEN_WIDTH + x3 * _j3VarViewDistance / z3; + y3 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y3 * _j3VarViewDistance / z3; + + j3DrawTriangle2D((jint16)x1, (jint16)y1, (jint16)x2, (jint16)y2, (jint16)x3, (jint16)y3, o->triangles[p->triangleNumber].shade); + } +} + + void j3MathCrossProduct3D(j3Vector3DT *u, j3Vector3DT *v, j3Vector3DT *normal) { // Compute the cross product between two vectors normal->x = (u->y*v->z - u->z*v->y); @@ -818,7 +888,23 @@ void _j3ObjectUpdate(j3ObjectT *o) { } } - } + // Did this triangle survive culling? + if (o->triangles[i].visible) { + // Find average z depth in camera space + vertex0 = o->triangles[i].index[0]; + vertex1 = o->triangles[i].index[1]; + vertex2 = o->triangles[i].index[2]; + o->triangles[i].averageDepth = (float)0.3333333 * (o->verticies[vertex0].camera.z + o->verticies[vertex1].camera.z + o->verticies[vertex2].camera.z); + // Add to visible polygon list + _j3Polygons[_j3PolygonCount].object = o; + _j3Polygons[_j3PolygonCount].triangleNumber = (juint16)i; + _j3PolygonCount++; + } + + } // for i + + // Z Sort the visible polygon list + qsort((void *)_j3Polygons, _j3PolygonCount, sizeof(j3PolyListT), (j3qsortCastT)_j3PolyCompare); o->positionDirty = false; o->rotationDirty = false; @@ -852,6 +938,23 @@ void _j3ObjectUpdateNormalLength(j3ObjectT *object, juint16 triangle) { } +int _j3PolyCompare(j3PolyListT *arg1, j3PolyListT *arg2) { + float z1; + float z2; + + z1 = arg1->object->triangles[arg1->triangleNumber].averageDepth; + z2 = arg2->object->triangles[arg2->triangleNumber].averageDepth; + + if (z1 > z2) { + return(-1); + } else if (z1 < z2) { + return(1); + } else { + return(0); + } +} + + bool _j3UtilClipLine(jint16 *x1, jint16 *y1, jint16 *x2, jint16 *y2) { jint16 xi; jint16 yi; @@ -1042,7 +1145,10 @@ bool _j3UtilClipLine(jint16 *x1, jint16 *y1, jint16 *x2, jint16 *y2) { void j3UtilShutdown(void) { - // Nothing yet + // Free visible polygon list + if (_j3Polygons != NULL) { + jlFree(_j3Polygons); + } } @@ -1162,6 +1268,11 @@ bool _j3WorldLoad(j3WorldT **world, char *file) { (*world)->objects->triangles = (j3TriangleT *)jlMalloc(sizeof(j3TriangleT) * (*world)->objects[x].triangleCount); if ((*world)->objects->triangles) { + //***TODO*** This will have to be moved/improved + // Add to world count & increase potential polygon list + _j3TriangleCount += (*world)->objects[x].triangleCount; + _j3Polygons = (j3PolyListT *)jlRealloc(_j3Polygons, sizeof(j3PolyListT) * _j3TriangleCount); + // Iterate and read triangles for (y=0; y<(*world)->objects[x].triangleCount; y++) { // Read one at a time in case the struct gets padded diff --git a/j3d/j3d.h b/j3d/j3d.h index a356b53..4646d9f 100644 --- a/j3d/j3d.h +++ b/j3d/j3d.h @@ -54,6 +54,7 @@ typedef struct { bool visible; // Can we see this triangle? bool twoSided; // Are both sides visible? float normalLength; // Magnatude of surface normal + float averageDepth; // Average Z depth of this triangle juint16 index[3]; // We do this instead of just a typedef so it works with stretch_buffer } j3TriangleT; @@ -70,26 +71,34 @@ typedef struct { bool scaleDirty; // Did the scale change? } j3ObjectT; +typedef struct { + j3ObjectT *object; + juint16 triangleNumber; +} j3PolyListT; + typedef struct { juint16 objectCount; j3ObjectT *objects; } j3WorldT; -extern jint16 _j3VarClipMinX; -extern jint16 _j3VarClipMinY; -extern jint16 _j3VarClipMinZ; -extern jint16 _j3VarClipMaxX; -extern jint16 _j3VarClipMaxY; -extern jint16 _j3VarClipMaxZ; -extern jint16 _j3VarViewDistance; -extern float _j3VarAmbientLight; -extern j3Matrix4x4T _j3VarCameraMatrix; -extern j3VertexT _j3VarCameraLocation; -extern j3FacingT _j3VarCameraAngle; -extern bool _j3VarCameraLocationDirty; -extern bool _j3VarCameraAngleDirty; -extern j3VertexT _j3VarSunLocation; +extern jint16 _j3VarClipMinX; +extern jint16 _j3VarClipMinY; +extern jint16 _j3VarClipMinZ; +extern jint16 _j3VarClipMaxX; +extern jint16 _j3VarClipMaxY; +extern jint16 _j3VarClipMaxZ; +extern jint16 _j3VarViewDistance; +extern float _j3VarAmbientLight; +extern j3Matrix4x4T _j3VarCameraMatrix; +extern j3VertexT _j3VarCameraLocation; +extern j3FacingT _j3VarCameraAngle; +extern bool _j3VarCameraLocationDirty; +extern bool _j3VarCameraAngleDirty; +extern j3VertexT _j3VarSunLocation; +extern j3PolyListT *_j3Polygons; +extern juint16 _j3PolygonCount; +extern juint16 _j3TriangleCount; #define j3CameraMove(ob, px, py, pz) \ @@ -178,6 +187,7 @@ extern j3VertexT _j3VarSunLocation; // Prototypes void j3DrawTriangle2D(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3, jint16 color); +void j3DrawWorld(j3WorldT *w); void j3MathCrossProduct3D(j3Vector3DT *u, j3Vector3DT *v, j3Vector3DT *normal); float j3MathDotProduct3D(j3Vector3DT *u, j3Vector3DT *v); void j3MathMatrix4x4Identity(j3Matrix4x4T result); diff --git a/j3d/main.c b/j3d/main.c index fcb79e6..7789df6 100644 --- a/j3d/main.c +++ b/j3d/main.c @@ -74,7 +74,7 @@ int main(void) { printAt(font, 1, 1, "Loading object... "); jlDisplayPresent(); - r = j3WorldLoad(world, "cube"); + r = j3WorldLoad(world, "pyramid"); if (!r) { printAt(font, 1, 1, "Object loading: Failed."); jlDisplayPresent(); @@ -130,11 +130,15 @@ int main(void) { jlDrawColor(15); jlDrawBox(0, 0, 319, 199); + //***TODO*** HACK!!! + _j3PolygonCount = 0; + for (x=0; xobjectCount; x++) { j3ObjectRotate(world->objects[x], 2, 4, 6); // Matching values in code I'm studying j3ObjectUpdate(world->objects[x]); //j3DrawWireframe(world->objects[x]); - j3DrawSolid(world->objects[x]); + //j3DrawSolid(world->objects[x]); + j3DrawWorld(world); } c = 0; @@ -148,6 +152,7 @@ int main(void) { printAt(font, 1, 2, "Triangles: %d (%d visible) ", world->objects[0].triangleCount, c); jlDisplayPresent(); + jlUtilSleep(1); } jlKeyRead(); } diff --git a/j3d/pyramid.obj b/j3d/pyramid.obj new file mode 100644 index 0000000..f5a0c41 --- /dev/null +++ b/j3d/pyramid.obj @@ -0,0 +1,12 @@ +v 0 30 0 +v 30 -10 30 +v 30 -10 -30 +v -30 -10 -30 +v -30 -10 30 + +f 1 3 2 +f 1 4 3 +f 1 5 4 +f 1 2 5 +f 5 2 3 +f 3 4 5