diff --git a/include/camera.h b/include/camera.h index e106509..bef7754 100644 --- a/include/camera.h +++ b/include/camera.h @@ -1,5 +1,6 @@ #ifndef CAMERA_H +#include "engine.h" #include "point.h" #include "util.h" #include @@ -14,27 +15,28 @@ struct Camera position.y = 0.0f; position.z = 0.0f; - rotation[0] = 0.0f; - rotation[1] = 0.0f; - rotation[2] = 0.0f; + rotation.x = 0.0f; + rotation.y = 0.0f; + rotation.z = 0.0f; - nearClip = 5.0f; - farClip = 600.0f; + zClipBias0 = + (CAMERA_FAR_CLIP + CAMERA_NEAR_CLIP) + / (CAMERA_FAR_CLIP - CAMERA_NEAR_CLIP); + + zClipBias1 = + (-2.0f * CAMERA_FAR_CLIP * CAMERA_NEAR_CLIP) + / (CAMERA_FAR_CLIP - CAMERA_NEAR_CLIP); + + xZoom = 1.0f / tanf(DEG_TO_RAD(CAMERA_FOV/2.0f)); + yZoom = (xZoom * WINDOW_WIDTH) / WINDOW_HEIGHT; + + xScale = (0.5f * WINDOW_WIDTH) - 0.5f; + yScale = (0.5f * WINDOW_HEIGHT) - 0.5f; } - inline void SetFOV(float fov, int winWidth, int winHeight) - { - xZoom = 1.0f / tanf(DEG_TO_RAD(fov/2.0f)); - yZoom = (xZoom * winWidth) / winHeight; - - xScale = (0.5f * winWidth) - 0.5f; - yScale = (0.5f * winHeight) - 0.5f; - } - - Point position; - float rotation[3]; - float nearClip, farClip; + Point rotation; + float zClipBias0, zClipBias1; float xZoom, yZoom; float xScale, yScale; }; diff --git a/include/engine.h b/include/engine.h index 8385bf7..cd6ddae 100644 --- a/include/engine.h +++ b/include/engine.h @@ -3,11 +3,22 @@ #include -// CONSTANTS +// WINDOW CONFIGURATION #define WINDOW_WIDTH (1920) #define WINDOW_HEIGHT (1080) #define WINDOW_FPS (30) +// CAMERA CONFIGURATION +#define CAMERA_FOV (90.0f) +#define CAMERA_NEAR_CLIP (5.0f) +#define CAMERA_FAR_CLIP (600.0f) + +// GEOMETRY CONFIGURATION +#define FACE_LIMIT (30000) +#define MATERIAL_LIMIT (10) +#define TEXTURE_SIZE_LIMIT (1024) +#define VERTEX_LIMIT (20000) + // ENUMS enum Engine_Input @@ -40,7 +51,7 @@ struct Engine_Buffer // FUNCTIONS -int Engine_Init(Engine_Buffer &buffer, char *objFilename, char *mtlFilename); +int Engine_Init(char *objFilename, char *mtlFilename); void Engine_Render(Engine_Buffer &buffer, uint32_t input); void Engine_Shutdown(void); diff --git a/include/geometry.h b/include/geometry.h index 3b7e574..4ac4ab6 100644 --- a/include/geometry.h +++ b/include/geometry.h @@ -6,13 +6,6 @@ #include -// CONSTANTS -#define VERTEX_LIMIT (20000) -#define FACE_LIMIT (30000) -#define MATERIAL_LIMIT (10) -#define TEXTURE_SIZE_LIMIT (1024) - - // STRUCTURES struct Texture { @@ -82,21 +75,8 @@ struct FaceList struct Mesh { - inline Mesh(void) - { - position.x = 0.0f; - position.y = 0.0f; - position.z = 0.0f; - - rotation[0] = 0.0f; - rotation[1] = 0.0f; - rotation[2] = 0.0f; - - scale = 1.0f; - } - Point position; - float rotation[3]; + Point rotation; float scale; }; diff --git a/include/transform.h b/include/transform.h index 431681b..39f8aad 100644 --- a/include/transform.h +++ b/include/transform.h @@ -1,15 +1,15 @@ #ifndef TRANSFORM_H - +#include "camera.h" #include "matrix.h" -Matrix Transform_Translate(float x, float y, float z); -Matrix Transform_Rotate(float x, float y, float z); -Matrix Transform_Scale(float s); -Matrix Transform_View(Point &position, float rotation[]); -Matrix Transform_Perspective(float zoomX, float zoomY, float nearClip, float farClip); -Matrix Transform_Screen(float xScale, float yScale); +Matrix Transform_Translate(Point &translation); +Matrix Transform_Rotate(Point &rotation); +Matrix Transform_Scale(float scale); +Matrix Transform_View(Camera &camera); +Matrix Transform_Perspective(Camera &camera); +Matrix Transform_Screen(Camera &camera); #define TRANSFORM_H diff --git a/src/engine.cpp b/src/engine.cpp index 3fa1abd..6420008 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -23,117 +23,94 @@ static FaceList transFaces; static UVList uvs; static MaterialList materials; static TextureList textures; +static Matrix tPersp; +static Matrix tScreen; // PRIVATE PROTOTYPES static void CheckInputs(uint32_t input); -static void ComputeNormals(VertexList &verts, FaceList &faces); +static void ComputeNormals(void); +static void ClearDepthBuffer(Engine_Buffer &buffer); +static void TransformToClipSpace(void); +static void TransformToScreenSpace(void); +static void ComputeLighting(void); // PUBLIC FUNCTIONS -int Engine_Init(Engine_Buffer &buffer, char *objFilename, char *mtlFilename) +int Engine_Init(char *objFilename, char *mtlFilename) { - int result = ParseOBJ(objFilename, localVerts, localFaces, uvs); + int result; + + result = ParseOBJ(objFilename, localVerts, localFaces, uvs); if (result < 0) { - return result; + return -1; } + result = ParseMTL(mtlFilename, materials, textures); if (result < 0) { return -1; } + printf("Verts: %lu\n", localVerts.size); printf("Faces: %lu\n", localFaces.size); printf("Materials: %lu\n", materials.size); transVerts.size = localVerts.size; - ComputeNormals(localVerts, localFaces); + // Compute vertex and face normals for lighting calculation + ComputeNormals(); + + + // Mesh configuration mesh.position.z = 50; mesh.position.y = -50; + mesh.scale = 1.0f; - camera.SetFOV(90.0f, buffer.width, buffer.height); + // Light configuration lights.ambient.intensity = 1.0f; lights.diffuse.intensity = 1.0f; lights.diffuse.direction = Vector(1.0f, 1.0f, 1.0f); + + // Transformation matrices that do not change + tPersp = Transform_Perspective(camera); + tScreen = Transform_Screen(camera); + + return 0; } void Engine_Render(Engine_Buffer &buffer, uint32_t input) { + // Check for user input CheckInputs(input); // Clear the z-buffer - memset(buffer.zbuffer, 0, sizeof(float) * (size_t)(buffer.width * buffer.height)); + ClearDepthBuffer(buffer); - // Local space to world space - Matrix tTranslate = Transform_Translate( - mesh.position.x, mesh.position.y, mesh.position.z); - - Matrix tRotate = Transform_Rotate( - mesh.rotation[0], mesh.rotation[1], mesh.rotation[2]); - - Matrix tScale = Transform_Scale(mesh.scale); - - // World space to camera (view) space - Matrix tView = Transform_View(camera.position, camera.rotation); - - // Camera space to perspective - Matrix tPersp = Transform_Perspective( - camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip); - - for (size_t v = 0; v < localVerts.size; ++v) - { - transVerts.data[v].point = localVerts.data[v].point * tScale * tRotate * tTranslate * tView * tPersp; - transVerts.data[v].normal = localVerts.data[v].normal * tScale * tRotate * tTranslate; - } + // Transform vertices to clip space + TransformToClipSpace(); - // Clip near and far Z, and cull backfaces + // Clip near/far Z and cull backfaces ClipAndCull(transVerts, localFaces, transFaces, camera.position); - // Lighting - for (size_t f = 0; f < transFaces.size; ++f) - { - Face &face = transFaces.data[f]; - Material &material = materials.data[face.materialIndex]; - - // TODO: Fix weird lighting - material.ambient = {1.0,1.0,1.0,1.0}; - material.diffuse = {0.5,0.5,0.5,0.5}; - - // Gouraud shading - for (int i = 0; i < 3; ++i) - { - Vertex &vert = transVerts.data[face.vertIndex[i]]; - - vert.color = - lights.ambient.ComputeColor(material.ambient) - + lights.diffuse.ComputeColor(material.diffuse, vert.normal); - } - } + // Light vertices and/or faces + ComputeLighting(); - // Perspective to screen - Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale); - - for (size_t v = 0; v < transVerts.size; ++v) - { - transVerts.data[v].point *= tScreen; - transVerts.data[v].point.x /= transVerts.data[v].point.w; - transVerts.data[v].point.y /= transVerts.data[v].point.w; - transVerts.data[v].point.z /= transVerts.data[v].point.w; - } + // Transform vertices to screen space + TransformToScreenSpace(); // Render @@ -177,29 +154,29 @@ static void CheckInputs(uint32_t input) if (CHECK_BIT(input, ROTATE_X_POS)) { - mesh.rotation[0] += .10; + mesh.rotation.x += .10; } else if (CHECK_BIT(input, ROTATE_X_NEG)) { - mesh.rotation[0] -= .10; - } - - if (CHECK_BIT(input, ROTATE_Z_POS)) - { - mesh.rotation[1] += .10; - } - else if (CHECK_BIT(input, ROTATE_Z_NEG)) - { - mesh.rotation[1] -= .10; + mesh.rotation.x -= .10; } if (CHECK_BIT(input, ROTATE_Y_POS)) { - mesh.rotation[2] += .10; + mesh.rotation.y += .10; } else if (CHECK_BIT(input, ROTATE_Y_NEG)) { - mesh.rotation[2] -= .10; + mesh.rotation.y -= .10; + } + + if (CHECK_BIT(input, ROTATE_Z_POS)) + { + mesh.rotation.z += .10; + } + else if (CHECK_BIT(input, ROTATE_Z_NEG)) + { + mesh.rotation.z -= .10; } if (CHECK_BIT(input, SCALE_UP)) @@ -213,19 +190,19 @@ static void CheckInputs(uint32_t input) } -static void ComputeNormals(VertexList &verts, FaceList &faces) +static void ComputeNormals(void) { - int vertexNormalCount[VERTEX_LIMIT]; + int vertexNormalCount[VERTEX_LIMIT] = {}; - for (size_t f = 0; f < faces.size; ++f) + for (size_t f = 0; f < localFaces.size; ++f) { - size_t v0 = (size_t)faces.data[f].vertIndex[0]; - size_t v1 = (size_t)faces.data[f].vertIndex[1]; - size_t v2 = (size_t)faces.data[f].vertIndex[2]; + size_t v0 = (size_t)localFaces.data[f].vertIndex[0]; + size_t v1 = (size_t)localFaces.data[f].vertIndex[1]; + size_t v2 = (size_t)localFaces.data[f].vertIndex[2]; - Point &p0 = verts.data[v0].point; - Point &p1 = verts.data[v1].point; - Point &p2 = verts.data[v2].point; + Point &p0 = localVerts.data[v0].point; + Point &p1 = localVerts.data[v1].point; + Point &p2 = localVerts.data[v2].point; Vector v01 = p1 - p0; Vector v02 = p2 - p0; @@ -233,9 +210,9 @@ static void ComputeNormals(VertexList &verts, FaceList &faces) Vector normal = Vector::Cross(v01, v02); // Add each vertex's normal to the sum for future averaging - verts.data[v0].normal += normal; - verts.data[v1].normal += normal; - verts.data[v2].normal += normal; + localVerts.data[v0].normal += normal; + localVerts.data[v1].normal += normal; + localVerts.data[v2].normal += normal; ++vertexNormalCount[v0]; ++vertexNormalCount[v1]; @@ -247,8 +224,66 @@ static void ComputeNormals(VertexList &verts, FaceList &faces) if (vertexNormalCount[v] > 0) { // Compute the average normal for this vertex - verts.data[v].normal /= vertexNormalCount[v]; - verts.data[v].normal.Normalize(); + localVerts.data[v].normal /= vertexNormalCount[v]; + localVerts.data[v].normal.Normalize(); + } + } +} + + +static void ClearDepthBuffer(Engine_Buffer &buffer) +{ + memset(buffer.zbuffer, 0, sizeof(float) * (size_t)(buffer.width * buffer.height)); +} + + +static void TransformToClipSpace(void) +{ + Matrix tTranslate = Transform_Translate(mesh.position); + Matrix tRotate = Transform_Rotate(mesh.rotation); + Matrix tScale = Transform_Scale(mesh.scale); + Matrix tView = Transform_View(camera); + + for (size_t v = 0; v < localVerts.size; ++v) + { + transVerts.data[v].point = + localVerts.data[v].point * tScale * tRotate * tTranslate * tView * tPersp; + + transVerts.data[v].normal = + localVerts.data[v].normal * tScale * tRotate * tTranslate; + } +} + +static void TransformToScreenSpace(void) +{ + for (size_t v = 0; v < transVerts.size; ++v) + { + transVerts.data[v].point *= tScreen; + transVerts.data[v].point.x /= transVerts.data[v].point.w; + transVerts.data[v].point.y /= transVerts.data[v].point.w; + transVerts.data[v].point.z /= transVerts.data[v].point.w; + } +} + +static void ComputeLighting(void) +{ + for (size_t f = 0; f < transFaces.size; ++f) + { + Face &face = transFaces.data[f]; + Material &material = materials.data[face.materialIndex]; + + // TODO: Fix weird lighting + material.ambient = {1.0,1.0,1.0,1.0}; + material.diffuse = {0.5,0.5,0.5,0.5}; + + // Gouraud shading + for (int i = 0; i < 3; ++i) + { + Vertex &vert = transVerts.data[face.vertIndex[i]]; + + vert.color = + lights.ambient.ComputeColor(material.ambient) + + lights.diffuse.ComputeColor(material.diffuse, vert.normal); } } } diff --git a/src/main.cpp b/src/main.cpp index 1b49f68..717e5cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) buffer.width = platform.surface->w; buffer.height = platform.surface->h; - result = Engine_Init(buffer, objFilename, mtlFilename); + result = Engine_Init(objFilename, mtlFilename); if (result < 0) { diff --git a/src/platform.cpp b/src/platform.cpp index 38cbb31..3d97a0d 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -154,19 +154,19 @@ static void HandleEvent( } break; case SDLK_j: { - SET_BIT(platform.input, ROTATE_Z_POS); + SET_BIT(platform.input, ROTATE_Y_POS); } break; case SDLK_l: { - SET_BIT(platform.input, ROTATE_Z_NEG); + SET_BIT(platform.input, ROTATE_Y_NEG); } break; case SDLK_u: { - SET_BIT(platform.input, ROTATE_Y_POS); + SET_BIT(platform.input, ROTATE_Z_POS); } break; case SDLK_o: { - SET_BIT(platform.input, ROTATE_Y_NEG); + SET_BIT(platform.input, ROTATE_Z_NEG); } break; case SDLK_UP: { @@ -216,19 +216,19 @@ static void HandleEvent( } break; case SDLK_j: { - CLEAR_BIT(platform.input, ROTATE_Z_POS); + CLEAR_BIT(platform.input, ROTATE_Y_POS); } break; case SDLK_l: { - CLEAR_BIT(platform.input, ROTATE_Z_NEG); + CLEAR_BIT(platform.input, ROTATE_Y_NEG); } break; case SDLK_u: { - CLEAR_BIT(platform.input, ROTATE_Y_POS); + CLEAR_BIT(platform.input, ROTATE_Z_POS); } break; case SDLK_o: { - CLEAR_BIT(platform.input, ROTATE_Y_NEG); + CLEAR_BIT(platform.input, ROTATE_Z_NEG); } break; case SDLK_UP: { diff --git a/src/transform.cpp b/src/transform.cpp index 0a96c87..63351b9 100644 --- a/src/transform.cpp +++ b/src/transform.cpp @@ -4,22 +4,22 @@ // PUBLIC FUNCTIONS -Matrix Transform_Translate(float x, float y, float z) +Matrix Transform_Translate(Point &translation) { Matrix result; - result.e41 = x; - result.e42 = y; - result.e43 = z; + result.e41 = translation.x; + result.e42 = translation.y; + result.e43 = translation.z; return result; } -Matrix Transform_Rotate(float x, float y, float z) +Matrix Transform_Rotate(Point &rotation) { // YXZ Euler rotation - float cosThetaY = cosf(y); - float sinThetaY = sinf(y); + float cosThetaY = cosf(rotation.y); + float sinThetaY = sinf(rotation.y); Matrix tRotateY; @@ -29,8 +29,8 @@ Matrix Transform_Rotate(float x, float y, float z) tRotateY.e33 = cosThetaY; - float cosThetaX = cosf(x); - float sinThetaX = sinf(x); + float cosThetaX = cosf(rotation.x); + float sinThetaX = sinf(rotation.x); Matrix tRotateX; @@ -40,8 +40,8 @@ Matrix Transform_Rotate(float x, float y, float z) tRotateX.e33 = cosThetaX; - float cosThetaZ = cosf(z); - float sinThetaZ = sinf(z); + float cosThetaZ = cosf(rotation.z); + float sinThetaZ = sinf(rotation.z); Matrix tRotateZ; @@ -56,49 +56,51 @@ Matrix Transform_Rotate(float x, float y, float z) return result; } -Matrix Transform_Scale(float s) +Matrix Transform_Scale(float scale) { Matrix result; - result.e11 = s; - result.e22 = s; - result.e33 = s; + result.e11 = scale; + result.e22 = scale; + result.e33 = scale; return result; } -Matrix Transform_View(Point &position, float rotation[]) +Matrix Transform_View(Camera &camera) { - Matrix tInvTranslate = Transform_Translate(-position.x, -position.y, -position.z); + Point invPosition = -camera.position; + Matrix tInvTranslate = Transform_Translate(invPosition); - Matrix tInvRotate = Transform_Rotate(-rotation[0], -rotation[1], -rotation[2]); + Point invRotation = -camera.rotation; + Matrix tInvRotate = Transform_Rotate(invRotation); Matrix result = tInvTranslate * tInvRotate; return result; } -Matrix Transform_Perspective(float zoomX, float zoomY, float nearClip, float farClip) +Matrix Transform_Perspective(Camera &camera) { Matrix result; - result.e11 = zoomX; - result.e22 = zoomY; - result.e33 = (farClip + nearClip) / (farClip - nearClip); + result.e11 = camera.xZoom; + result.e22 = camera.yZoom; + result.e33 = camera.zClipBias0; result.e34 = 1; - result.e43 = (-2.0f * farClip * nearClip) / (farClip - nearClip); + result.e43 = camera.zClipBias1; return result; } -Matrix Transform_Screen(float xScale, float yScale) +Matrix Transform_Screen(Camera &camera) { Matrix result; - result.e11 = xScale; - result.e41 = xScale; - result.e22 = -yScale; - result.e42 = yScale; + result.e11 = camera.xScale; + result.e41 = camera.xScale; + result.e22 = -camera.yScale; + result.e42 = camera.yScale; return result; }