Backface removal, solid drawing, and basic lighting.
This commit is contained in:
parent
d2fd766caa
commit
99de9c6b23
3 changed files with 532 additions and 30 deletions
509
j3d/j3d.c
509
j3d/j3d.c
|
@ -49,11 +49,17 @@ segment "j3d";
|
|||
|
||||
|
||||
// Module global data
|
||||
static jint16 clipMinX = 0;
|
||||
static jint16 clipMinY = 0;
|
||||
static jint16 clipMaxX = 319;
|
||||
static jint16 clipMaxY = 199;
|
||||
static jint16 viewDistance = 250;
|
||||
static jint16 clipMinX = 0;
|
||||
static jint16 clipMinY = 0;
|
||||
static jint16 clipMinZ = 100;
|
||||
static jint16 clipMaxX = 319;
|
||||
static jint16 clipMaxY = 199;
|
||||
static jint16 clipMaxZ = 3000;
|
||||
static jint16 viewDistance = 250;
|
||||
static float ambientLight = 6;
|
||||
static j3VertexT cameraLocation;
|
||||
static j3FacingT cameraAngle;
|
||||
static j3VertexT sunLocation;
|
||||
|
||||
|
||||
#define ASPECT_RATIO (float)0.8
|
||||
|
@ -63,6 +69,280 @@ static jint16 viewDistance = 250;
|
|||
#define HALF_SCREEN_HEIGHT 100
|
||||
|
||||
|
||||
void _j3DrawSolid(j3ObjectT *o) {
|
||||
jint16 t;
|
||||
juint16 vertex1;
|
||||
juint16 vertex2;
|
||||
juint16 vertex3;
|
||||
float x1;
|
||||
float y1;
|
||||
float z1;
|
||||
float x2;
|
||||
float y2;
|
||||
float z2;
|
||||
float x3;
|
||||
float y3;
|
||||
float z3;
|
||||
|
||||
for (t=0; t<o->triangleCount; t++) {
|
||||
|
||||
// Is this triangle even visible?
|
||||
if (!o->triangles[t].visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vertex1 = o->triangles[t].index[0];
|
||||
vertex2 = o->triangles[t].index[1];
|
||||
vertex3 = o->triangles[t].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 < clipMinZ && z2 < clipMinZ && z3 < clipMinZ) || (z1 > clipMaxZ && z2 > clipMaxZ && z3 > clipMaxZ)) {
|
||||
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 * viewDistance / z1;
|
||||
y1 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y1 * viewDistance / z1;
|
||||
x2 = HALF_SCREEN_WIDTH + x2 * viewDistance / z2;
|
||||
y2 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y2 * viewDistance / z2;
|
||||
x3 = HALF_SCREEN_WIDTH + x3 * viewDistance / z3;
|
||||
y3 = HALF_SCREEN_HEIGHT - ASPECT_RATIO * y3 * viewDistance / z3;
|
||||
|
||||
j3DrawTriangle2D((jint16)x1, (jint16)y1, (jint16)x2, (jint16)y2, (jint16)x3, (jint16)y3, o->triangles[t].shade);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void j3DrawTriangle2D(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3, jint16 color) {
|
||||
jint16 tempX;
|
||||
jint16 tempY;
|
||||
jint16 newX;
|
||||
|
||||
// Horizontal or vertical lines?
|
||||
if ((x1 == x2 && x2 == x3) || (y1 == y2 && y2 == y3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort points in ascending Y order
|
||||
if (y2 < y1) {
|
||||
tempX = x2;
|
||||
tempY = y2;
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
x1 = tempX;
|
||||
y1 = tempY;
|
||||
}
|
||||
// p1 and p2 are now in order
|
||||
if (y3 < y1) {
|
||||
tempX = x3;
|
||||
tempY = y3;
|
||||
x3 = x1;
|
||||
y3 = y1;
|
||||
x1 = tempX;
|
||||
y1 = tempY;
|
||||
}
|
||||
// Finally check y3 against y2
|
||||
if (y3 < y2) {
|
||||
tempX = x3;
|
||||
tempY = y3;
|
||||
x3 = x2;
|
||||
y3 = y2;
|
||||
x2 = tempX;
|
||||
y2 = tempY;
|
||||
} // end if
|
||||
|
||||
// Trivial rejection tests
|
||||
if (y3 < clipMinY || y1 > clipMaxY || (x1 < clipMinX && x2 < clipMinX && x3 < clipMinX) || (x1 > clipMaxX && x2 > clipMaxX && x3 > clipMaxX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
jlDrawColor((byte)color);
|
||||
|
||||
// Is top of triangle flat?
|
||||
if (y1 == y2) {
|
||||
_j3DrawTriangleTop(x1, y1, x2, y2, x3, y3);
|
||||
} else if (y2 == y3) {
|
||||
_j3DrawTriangleBottom(x1, y1, x2, y2, x3, y3);
|
||||
} else {
|
||||
// General triangle that's needs to be broken up along long edge
|
||||
newX = x1 + (jint16)((float)(y2 - y1) * (float)(x3 - x1) / (float)(y3 - y1));
|
||||
// Draw each sub-triangle
|
||||
_j3DrawTriangleBottom(x1, y1, newX, y2, x2, y2);
|
||||
_j3DrawTriangleTop(x2, y2, newX, y2, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _j3DrawTriangleBottom(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3) {
|
||||
float dxRight;
|
||||
float dxLeft;
|
||||
float xs;
|
||||
float xe;
|
||||
float height;
|
||||
jint16 tempX;
|
||||
jint16 tempY;
|
||||
jint16 right;
|
||||
jint16 left;
|
||||
|
||||
(void)y2;
|
||||
|
||||
// Test order of x1 and x2
|
||||
if (x3 < x2) {
|
||||
tempX = x2;
|
||||
x2 = x3;
|
||||
x3 = tempX;
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
height = y3 - y1;
|
||||
dxLeft = (x2 - x1) / height;
|
||||
dxRight = (x3 - x1) / height;
|
||||
|
||||
// Set starting points
|
||||
xs = (float)x1;
|
||||
xe = (float)x1 + (float)0.5;
|
||||
|
||||
// Perform y clipping
|
||||
if (y1 < clipMinY) {
|
||||
// Compute new xs and ys
|
||||
xs = xs + dxLeft * (float)(-y1 + clipMinY);
|
||||
xe = xe + dxRight * (float)(-y1 + clipMinY);
|
||||
// Reset y1
|
||||
y1 = clipMinY;
|
||||
}
|
||||
if (y3 > clipMaxY) {
|
||||
y3 = clipMaxY;
|
||||
}
|
||||
|
||||
// Test if x clipping is needed
|
||||
if (x1 >= clipMinX && x1 <= clipMaxX && x2 >= clipMinX && x2 <= clipMaxX && x3 >= clipMinX && x3 <= clipMaxX) {
|
||||
// Draw the triangle
|
||||
for (tempY=y1; tempY<=y3; tempY++) {
|
||||
jlDrawLine((jint16)xs, tempY, (jint16)xe, tempY);
|
||||
// Adjust starting point and ending point
|
||||
xs += dxLeft;
|
||||
xe += dxRight;
|
||||
}
|
||||
} else {
|
||||
// Clip x axis with slower version
|
||||
for (tempY=y1; tempY<=y3; tempY++) {
|
||||
// Do x clip
|
||||
left = (jint16)xs;
|
||||
right = (jint16)xe;
|
||||
// Adjust starting point and ending point
|
||||
xs += dxLeft;
|
||||
xe += dxRight;
|
||||
// Clip line
|
||||
if (left < clipMinX) {
|
||||
left = clipMinX;
|
||||
if (right < clipMinX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (right > clipMaxX) {
|
||||
right = clipMaxX;
|
||||
if (left > clipMaxX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Draw
|
||||
jlDrawLine(left, tempY, right, tempY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _j3DrawTriangleTop(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3) {
|
||||
float dxRight;
|
||||
float dxLeft;
|
||||
float xs;
|
||||
float xe;
|
||||
float height;
|
||||
jint16 tempX;
|
||||
jint16 tempY;
|
||||
jint16 right;
|
||||
jint16 left;
|
||||
|
||||
(void)y2;
|
||||
|
||||
// Test order of x1 and x2
|
||||
if (x2 < x1) {
|
||||
tempX = x2;
|
||||
x2 = x1;
|
||||
x1 = tempX;
|
||||
}
|
||||
|
||||
// Compute deltas
|
||||
height = y3 - y1;
|
||||
dxLeft = (x3 - x1) / height;
|
||||
dxRight = (x3 - x2) / height;
|
||||
|
||||
// Set starting points
|
||||
xs = (float)x1;
|
||||
xe = (float)x2 + (float)0.5;
|
||||
|
||||
// Perform y clipping
|
||||
if (y1 < clipMinY) {
|
||||
// Compute new xs and ys
|
||||
xs = xs + dxLeft * (float)(-y1 + clipMinY);
|
||||
xe = xe + dxRight * (float)(-y1 + clipMinY);
|
||||
// Reset y1
|
||||
y1 = clipMinY;
|
||||
}
|
||||
if (y3 > clipMaxY) {
|
||||
y3=clipMaxY;
|
||||
}
|
||||
|
||||
// Test if x clipping is needed
|
||||
if (x1 >= clipMinX && x1 <= clipMaxX && x2 >= clipMinX && x2 <= clipMaxX && x3 >= clipMinX && x3 <= clipMaxX) {
|
||||
// Draw the triangle
|
||||
for (tempY=y1; tempY<=y3; tempY++) {
|
||||
jlDrawLine((jint16)xs, tempY, (jint16)xe, tempY);
|
||||
// Adjust starting point and ending point
|
||||
xs += dxLeft;
|
||||
xe += dxRight;
|
||||
}
|
||||
} else {
|
||||
// Clip x axis
|
||||
for (tempY=y1; tempY<=y3; tempY++) {
|
||||
// Do x clip
|
||||
left = (jint16)xs;
|
||||
right = (jint16)xe;
|
||||
// Adjust starting point and ending point
|
||||
xs += dxLeft;
|
||||
xe += dxRight;
|
||||
// Clip line
|
||||
if (left < clipMinX) {
|
||||
left = clipMinX;
|
||||
if (right < clipMinX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (right > clipMaxX) {
|
||||
right = clipMaxX;
|
||||
if (left > clipMaxX) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Draw
|
||||
jlDrawLine((jint16)left, tempY, (jint16)right, tempY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _j3DrawWireframePair(j3ObjectT *o, juint16 v1, juint16 v2) {
|
||||
float x1;
|
||||
float y1;
|
||||
|
@ -114,6 +394,20 @@ void _j3DrawWireframe(j3ObjectT *o) {
|
|||
}
|
||||
|
||||
|
||||
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);
|
||||
normal->y = -(u->x*v->z - u->z*v->x);
|
||||
normal->z = (u->x*v->y - u->y*v->x);
|
||||
}
|
||||
|
||||
|
||||
float j3MathDotProduct3D(j3Vector3DT *u, j3Vector3DT *v) {
|
||||
// Compute the dot product of two vectors
|
||||
return( (u->x * v->x) + (u->y * v->y) + (u->z * v->z));
|
||||
}
|
||||
|
||||
|
||||
void j3MathMatrix4x4Identity(j3Matrix4x4T result) {
|
||||
result[0][0] = 1; result[0][1] = 0; result[0][2] = 0; result[0][3] = 0;
|
||||
result[1][0] = 0; result[1][1] = 1; result[1][2] = 0; result[1][3] = 0;
|
||||
|
@ -145,6 +439,20 @@ void j3MathMatrix4x4Mult(j3Matrix4x4T a, j3Matrix4x4T b, j3Matrix4x4T result) {
|
|||
}
|
||||
|
||||
|
||||
void j3MathMakeVector3D(j3VertexT *init, j3VertexT *term, j3Vector3DT *result) {
|
||||
// Create a vector from two points in 3D space
|
||||
result->x = term->x - init->x;
|
||||
result->y = term->y - init->y;
|
||||
result->z = term->z - init->z;
|
||||
}
|
||||
|
||||
|
||||
float j3MathVectorMagnatude3D(j3Vector3DT *v) {
|
||||
// Compute the magnitude of a vector
|
||||
return((float)sqrt((double)(v->x * v->x + v->y * v->y + v->z * v->z)));
|
||||
}
|
||||
|
||||
|
||||
void _j3ObjectReset(j3ObjectT *o) {
|
||||
o->position.x = 0;
|
||||
o->position.y = 0;
|
||||
|
@ -165,7 +473,16 @@ void _j3ObjectUpdate(j3ObjectT *o) {
|
|||
jint16 y;
|
||||
jint16 z;
|
||||
jint16 i;
|
||||
byte axis = 0;
|
||||
juint16 vertex0;
|
||||
juint16 vertex1;
|
||||
juint16 vertex2;
|
||||
float dot;
|
||||
float intensity;
|
||||
j3Vector3DT u;
|
||||
j3Vector3DT v;
|
||||
j3Vector3DT normal;
|
||||
j3Vector3DT sight;
|
||||
byte axis = 0;
|
||||
j3Matrix4x4T rotateX;
|
||||
j3Matrix4x4T rotateY;
|
||||
j3Matrix4x4T rotateZ;
|
||||
|
@ -326,6 +643,103 @@ void _j3ObjectUpdate(j3ObjectT *o) {
|
|||
for (i=0; i<o->vertexCount; i++) {
|
||||
o->verticies[i].camera = o->verticies[i].world;
|
||||
}
|
||||
|
||||
// === REMOVE BACKFACES & LIGHT ===
|
||||
|
||||
for (i=0; i<o->triangleCount; i++) {
|
||||
// If it's two sided, there are no backfaces
|
||||
if (!o->triangles[i].twoSided) {
|
||||
|
||||
// Compute two vectors on polygon that have the same intial points
|
||||
vertex0 = o->triangles[i].index[0];
|
||||
vertex1 = o->triangles[i].index[1];
|
||||
vertex2 = o->triangles[i].index[2];
|
||||
// Vector u = v0->v1
|
||||
j3MathMakeVector3D((j3VertexT *)&o->verticies[vertex0].world, (j3VertexT *)&o->verticies[vertex1].world, (j3Vector3DT *)&u);
|
||||
// Vector v = v0->v2
|
||||
j3MathMakeVector3D((j3VertexT *)&o->verticies[vertex0].world, (j3VertexT *)&o->verticies[vertex2].world, (j3Vector3DT *)&v);
|
||||
// Normal v x u
|
||||
j3MathCrossProduct3D((j3Vector3DT *)&v, (j3Vector3DT *)&u, (j3Vector3DT *)&normal);
|
||||
// Compute the line of sight vector, since all coordinates are world all
|
||||
// object vertices are already relative to (0,0,0), thus
|
||||
sight.x = cameraLocation.x - o->verticies[vertex0].world.x;
|
||||
sight.y = cameraLocation.y - o->verticies[vertex0].world.y;
|
||||
sight.z = cameraLocation.z - o->verticies[vertex0].world.z;
|
||||
// Compute the dot product between line of sight vector and normal to surface
|
||||
dot = j3MathDotProduct3D((j3Vector3DT *)&normal, (j3Vector3DT *)&sight);
|
||||
|
||||
// Is the surface visible
|
||||
if (dot > 0) {
|
||||
// Set visible flag
|
||||
o->triangles[i].visible = true;
|
||||
|
||||
// Compute light intensity if needed
|
||||
if (o->triangles[i].lit) {
|
||||
// Compute the dot product between the light source vector and normal vector to surface
|
||||
dot = j3MathDotProduct3D((j3Vector3DT *)&normal, (j3Vector3DT *)&sunLocation);
|
||||
// Test if light ray is reflecting off surface
|
||||
if (dot > 0) {
|
||||
intensity = ambientLight + (dot * (o->triangles[i].normalLength));
|
||||
// Test if intensity has overflowed
|
||||
if (intensity > 15) {
|
||||
intensity = 15;
|
||||
}
|
||||
// Intensity now varies from 0-1, 0 being black or grazing and 1 being
|
||||
// totally illuminated. use the value to index into color table
|
||||
o->triangles[i].shade = o->triangles[i].color - (jint16)intensity;
|
||||
} else {
|
||||
o->triangles[i].shade = o->triangles[i].color - (jint16)ambientLight;
|
||||
}
|
||||
} else {
|
||||
// Constant shading - simply assign color to shade
|
||||
o->triangles[i].shade = o->triangles[i].color;
|
||||
}
|
||||
} else {
|
||||
o->triangles[i].visible = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Triangle is always visible i.e. two sided
|
||||
o->triangles[i].visible = true;
|
||||
|
||||
// Perform shading calculation
|
||||
if (o->triangles[i].lit) {
|
||||
|
||||
// Compute two vectors on polygon that have the same intial points
|
||||
vertex0 = o->triangles[i].index[0];
|
||||
vertex1 = o->triangles[i].index[1];
|
||||
vertex2 = o->triangles[i].index[2];
|
||||
// Vector u = v0->v1
|
||||
j3MathMakeVector3D((j3VertexT *)&o->verticies[vertex0].world, (j3VertexT *)&o->verticies[vertex1].world, (j3Vector3DT *)&u);
|
||||
// Vector v = v0->v2
|
||||
j3MathMakeVector3D((j3VertexT *)&o->verticies[vertex0].world, (j3VertexT *)&o->verticies[vertex2].world, (j3Vector3DT *)&v);
|
||||
// Normal v x u
|
||||
j3MathCrossProduct3D((j3Vector3DT *)&v, (j3Vector3DT *)&u, (j3Vector3DT *)&normal);
|
||||
// Compute the dot product between the light source vector and normal vector to surface
|
||||
dot = j3MathDotProduct3D((j3Vector3DT *)&normal, (j3Vector3DT *)&sunLocation);
|
||||
|
||||
// Is light ray is reflecting off surface
|
||||
if (dot > 0) {
|
||||
// cos 0 = (u.v)/|u||v| or
|
||||
intensity = ambientLight + (dot * (o->triangles[i].normalLength));
|
||||
// test if intensity has overflowed
|
||||
if (intensity > 15) {
|
||||
intensity = 15;
|
||||
}
|
||||
// intensity now varies from 0-1, 0 being black or grazing and 1 being
|
||||
// totally illuminated. use the value to index into color table
|
||||
o->triangles[i].shade = o->triangles[i].color - (jint16)intensity;
|
||||
} else {
|
||||
o->triangles[i].shade = o->triangles[i].color - (jint16)ambientLight;
|
||||
}
|
||||
} else {
|
||||
// Constant shading and simply assign color to shade
|
||||
o->triangles[i].shade = o->triangles[i].color;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -524,7 +938,17 @@ void j3UtilShutdown(void) {
|
|||
|
||||
|
||||
void j3UtilStartup(void) {
|
||||
// Nothing yet
|
||||
cameraLocation.x = 0;
|
||||
cameraLocation.y = 0;
|
||||
cameraLocation.z = 0;
|
||||
|
||||
cameraAngle.x = 0;
|
||||
cameraAngle.y = 0;
|
||||
cameraAngle.z = 0;
|
||||
|
||||
sunLocation.x = (float)-0.913913;
|
||||
sunLocation.y = (float) 0.389759;
|
||||
sunLocation.z = (float)-0.113369;
|
||||
}
|
||||
|
||||
|
||||
|
@ -552,6 +976,12 @@ bool _j3WorldLoad(j3WorldT **world, char *file) {
|
|||
jint16 x;
|
||||
jint16 y;
|
||||
jint16 z;
|
||||
juint16 vertex0;
|
||||
juint16 vertex1;
|
||||
juint16 vertex2;
|
||||
j3Vector3DT u;
|
||||
j3Vector3DT v;
|
||||
j3Vector3DT normal;
|
||||
byte buffer[4];
|
||||
FILE *in;
|
||||
bool failed = false;
|
||||
|
@ -585,21 +1015,19 @@ bool _j3WorldLoad(j3WorldT **world, char *file) {
|
|||
if (fread(&(*world)->objectCount, sizeof(juint16), 1, in) == 1) {
|
||||
|
||||
// Allocate memory for objects
|
||||
(*world)->objects = (j3ObjectT *)jlMalloc(sizeof(j3ObjectT));
|
||||
(*world)->objects = (j3ObjectT *)jlMalloc(sizeof(j3ObjectT) * (*world)->objectCount);
|
||||
if ((*world)->objects) {
|
||||
|
||||
// Iterate across objects in file
|
||||
for (x=0; x<(*world)->objectCount; x++) {
|
||||
|
||||
// Allocate memory for object elements
|
||||
(*world)->objects->verticies = (j3CoordinatesT *)jlMalloc(sizeof(j3CoordinatesT));
|
||||
(*world)->objects->triangles = (j3TriangleT *)jlMalloc(sizeof(j3TriangleT));
|
||||
if ((*world)->objects->verticies && (*world)->objects->triangles) {
|
||||
// Get vertex count
|
||||
if (fread(&(*world)->objects[x].vertexCount, sizeof(juint16), 1, in) == 1) {
|
||||
|
||||
_j3ObjectReset(&(*world)->objects[x]);
|
||||
// Allocate memory for vertex data
|
||||
(*world)->objects->verticies = (j3CoordinatesT *)jlMalloc(sizeof(j3CoordinatesT) * (*world)->objects[x].vertexCount);
|
||||
if ((*world)->objects->verticies) {
|
||||
|
||||
// Get vertex count
|
||||
if (fread(&(*world)->objects[x].vertexCount, sizeof(juint16), 1, in) == 1) {
|
||||
// Iterate and read verticies
|
||||
for (y=0; y<(*world)->objects[x].vertexCount; y++) {
|
||||
// Read one at a time in case the struct gets padded
|
||||
|
@ -618,9 +1046,19 @@ bool _j3WorldLoad(j3WorldT **world, char *file) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
// Get triangle count
|
||||
if (fread(&(*world)->objects[x].triangleCount, sizeof(juint16), 1, in) == 1) {
|
||||
} else {
|
||||
// Failed to get vertex memory
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
// Get triangle count
|
||||
if (fread(&(*world)->objects[x].triangleCount, sizeof(juint16), 1, in) == 1) {
|
||||
|
||||
// Allocate memory for triangle data
|
||||
(*world)->objects->triangles = (j3TriangleT *)jlMalloc(sizeof(j3TriangleT) * (*world)->objects[x].triangleCount);
|
||||
if ((*world)->objects->triangles) {
|
||||
|
||||
// Iterate and read triangles
|
||||
for (y=0; y<(*world)->objects[x].triangleCount; y++) {
|
||||
// Read one at a time in case the struct gets padded
|
||||
|
@ -631,11 +1069,38 @@ bool _j3WorldLoad(j3WorldT **world, char *file) {
|
|||
}
|
||||
}
|
||||
if (failed) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // vertex & triangle alloc
|
||||
// Compute length of the two co-planer edges of the polygon, since they will be used in the computation of the dot-product later
|
||||
vertex0 = (*world)->objects[x].triangles[y].index[0];
|
||||
vertex1 = (*world)->objects[x].triangles[y].index[1];
|
||||
vertex2 = (*world)->objects[x].triangles[y].index[2];
|
||||
j3MathMakeVector3D((j3VertexT *)&(*world)->objects[x].verticies[vertex0].local, (j3VertexT *)&(*world)->objects[x].verticies[vertex1].local, (j3Vector3DT *)&u);
|
||||
j3MathMakeVector3D((j3VertexT *)&(*world)->objects[x].verticies[vertex0].local, (j3VertexT *)&(*world)->objects[x].verticies[vertex2].local, (j3Vector3DT *)&v);
|
||||
j3MathCrossProduct3D((j3Vector3DT *)&v, (j3Vector3DT *)&u, (j3Vector3DT *)&normal);
|
||||
|
||||
// Compute magnitude of normal, take its inverse and multiply it by
|
||||
// 15, this will change the shading calculation of 15*dp/normal into
|
||||
// dp*normal_length, removing one division
|
||||
(*world)->objects[x].triangles[y].normalLength = (float)15.0 / j3MathVectorMagnatude3D((j3Vector3DT *)&normal);
|
||||
|
||||
//***TODO*** All triangles are one-sided for now
|
||||
(*world)->objects[x].triangles[y].twoSided = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Failed to get triangle memory
|
||||
failed = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
_j3ObjectReset(&(*world)->objects[x]);
|
||||
} else {
|
||||
break; // Stop iterating
|
||||
}
|
||||
|
||||
} // object iterator
|
||||
} // objects alloc
|
||||
} // Object count
|
||||
|
|
36
j3d/j3d.h
36
j3d/j3d.h
|
@ -27,13 +27,22 @@
|
|||
#include "joey.h"
|
||||
|
||||
|
||||
//***TODO*** verticies is vertices
|
||||
|
||||
|
||||
typedef float j3Matrix4x4T[4][4];
|
||||
|
||||
typedef struct {
|
||||
jint16 x;
|
||||
jint16 y;
|
||||
jint16 z;
|
||||
} j3FacingT;
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} j3VertexT;
|
||||
} j3VertexT, j3Vector3DT;
|
||||
|
||||
typedef struct {
|
||||
j3VertexT local; // Original vertex positions
|
||||
|
@ -42,7 +51,13 @@ typedef struct {
|
|||
} j3CoordinatesT;
|
||||
|
||||
typedef struct {
|
||||
juint16 index[3]; // We do this instead of just a typedef so it works with stretch_buffer
|
||||
jint16 color; // Assigned color of this face
|
||||
jint16 shade; // Color of this face after lighting
|
||||
bool lit; // Do we care about lighting?
|
||||
bool visible; // Can we see this triangle?
|
||||
bool twoSided; // Are both sides visible?
|
||||
float normalLength; // Magnatude of surface normal
|
||||
juint16 index[3]; // We do this instead of just a typedef so it works with stretch_buffer
|
||||
} j3TriangleT;
|
||||
|
||||
typedef struct {
|
||||
|
@ -107,6 +122,7 @@ typedef struct {
|
|||
|
||||
|
||||
// Syntatic sugar
|
||||
#define j3DrawSolid(o) _j3DrawSolid(&(o))
|
||||
#define j3DrawWireframe(o) _j3DrawWireframe(&(o))
|
||||
#define j3ObjectReset(o) _j3ObjectReset(&(o))
|
||||
#define j3ObjectUpdate(o) _j3ObjectUpdate(&(o))
|
||||
|
@ -115,13 +131,21 @@ typedef struct {
|
|||
|
||||
|
||||
// Prototypes
|
||||
void j3MathMatrix4x4Identity(j3Matrix4x4T result);
|
||||
void j3MathMatrix4x4Mult(j3Matrix4x4T a, j3Matrix4x4T b, j3Matrix4x4T result);
|
||||
void j3UtilShutdown(void);
|
||||
void j3UtilStartup(void);
|
||||
void j3DrawTriangle2D(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3, jint16 color);
|
||||
void j3MathCrossProduct3D(j3Vector3DT *u, j3Vector3DT *v, j3Vector3DT *normal);
|
||||
float j3MathDotProduct3D(j3Vector3DT *u, j3Vector3DT *v);
|
||||
void j3MathMatrix4x4Identity(j3Matrix4x4T result);
|
||||
void j3MathMatrix4x4Mult(j3Matrix4x4T a, j3Matrix4x4T b, j3Matrix4x4T result);
|
||||
void j3MathMakeVector3D(j3VertexT *init, j3VertexT *term, j3Vector3DT *result);
|
||||
float j3MathVectorMagnatude3D(j3Vector3DT *v);
|
||||
void j3UtilShutdown(void);
|
||||
void j3UtilStartup(void);
|
||||
|
||||
|
||||
// Private Prototypes
|
||||
void _j3DrawSolid(j3ObjectT *o);
|
||||
void _j3DrawTriangleBottom(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3);
|
||||
void _j3DrawTriangleTop(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3);
|
||||
void _j3DrawWireframePair(j3ObjectT *o, juint16 v1, juint16 v2);
|
||||
void _j3DrawWireframe(j3ObjectT *o);
|
||||
void _j3ObjectReset(j3ObjectT *o);
|
||||
|
|
17
j3d/main.c
17
j3d/main.c
|
@ -59,6 +59,8 @@ void printAt(jlStaT *font, jint16 cx, jint16 cy, const char *what, ...) {
|
|||
|
||||
int main(void) {
|
||||
jint16 x;
|
||||
jint16 y;
|
||||
jint16 c;
|
||||
jlStaT *font = NULL;
|
||||
j3WorldT *world = NULL;
|
||||
bool r;
|
||||
|
@ -81,8 +83,18 @@ int main(void) {
|
|||
printAt(font, 1, 1, "Object loading: Success!");
|
||||
jlDisplayPresent();
|
||||
|
||||
// Assign fake colors until we can read them from the J3D
|
||||
c = 1;
|
||||
for (x=0; x<world->objectCount; x++) {
|
||||
for (y=0; y<world->objects[x].triangleCount; y++) {
|
||||
world->objects[x].triangles->color = c++;
|
||||
if (c > 15) {
|
||||
c = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JOEY_LINUX
|
||||
jint16 y;
|
||||
printf("Objects: %d\n", world->objectCount);
|
||||
for (x=0; x<world->objectCount; x++) {
|
||||
printf("Object %d:\n", x);
|
||||
|
@ -121,7 +133,8 @@ int main(void) {
|
|||
for (x=0; x<world->objectCount; x++) {
|
||||
j3ObjectRotate(world->objects[x], 2, 4, 6); // Matching values in code I'm studying
|
||||
j3ObjectUpdate(world->objects[x]);
|
||||
j3DrawWireframe(world->objects[x]);
|
||||
//j3DrawWireframe(world->objects[x]);
|
||||
j3DrawSolid(world->objects[x]);
|
||||
}
|
||||
|
||||
printAt(font, 1, 1, "Verticies: %d", world->objects[0].vertexCount);
|
||||
|
|
Loading…
Add table
Reference in a new issue