#include "camera.h" #include "color.h" #include "engine.h" #include "geometry.h" #include "light.h" #include "loader.h" #include "matrix.h" #include "transform.h" #include "util.h" #include "vec.h" #include #include // GLOBALS static Mesh mesh; static Camera camera; static LightList lights; static VertexList localVerts; static VertexList transVerts; static FaceList localFaces; static FaceList transFaces; static UVList uvs; static MaterialList materials; static TextureList textures; // PRIVATE PROTOTYPES static void CheckInputs(uint32_t input); static void ComputeNormals(VertexList &verts, FaceList &faces); // PUBLIC FUNCTIONS int Engine_Init(Engine_Buffer &buffer, char *objFilename, char *mtlFilename) { int result = ParseOBJ(objFilename, localVerts, localFaces, uvs); if (result < 0) { return result; } 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); mesh.position.z = 50; mesh.position.y = -50; camera.SetFOV(90.0f, buffer.width, buffer.height); lights.diffuse = (LightDiffuse*)malloc(sizeof(LightDiffuse)); lights.diffuseCount = 1; lights.ambient.intensity = 1.0f; lights.diffuse[0].intensity = 1.0f; lights.diffuse[0].direction = Vector(1.0f, 1.0f, 1.0f); return 0; } void Engine_Render(Engine_Buffer &buffer, uint32_t input) { CheckInputs(input); // Clear the z-buffer memset(buffer.zbuffer, 0, sizeof(float) * (size_t)(buffer.width * buffer.height)); // 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; } // Clip near and 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]]; ColorF32 totalColor = lights.ambient.ComputeColor(material.ambient); for (int c = 0; c < lights.diffuseCount; ++c) { totalColor += lights.diffuse[c].ComputeColor( material.diffuse, vert.normal); } vert.color = totalColor; } } // 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; } // Render RenderMesh(buffer, transFaces, transVerts, uvs, textures); } void Engine_Shutdown(void) { } // PRIVATE FUNCTIONS static void CheckInputs(uint32_t input) { if (CHECK_BIT(input, TRANSLATE_X_POS)) { mesh.position.x += 10; } else if (CHECK_BIT(input, TRANSLATE_X_NEG)) { mesh.position.x -= 10; } if (CHECK_BIT(input, TRANSLATE_Z_POS)) { mesh.position.z += 10; } else if (CHECK_BIT(input, TRANSLATE_Z_NEG)) { mesh.position.z -= 10; } if (CHECK_BIT(input, TRANSLATE_Y_POS)) { mesh.position.y += 10; } else if (CHECK_BIT(input, TRANSLATE_Y_NEG)) { mesh.position.y -= 10; } if (CHECK_BIT(input, ROTATE_X_POS)) { mesh.rotation[0] += .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; } if (CHECK_BIT(input, ROTATE_Y_POS)) { mesh.rotation[2] += .10; } else if (CHECK_BIT(input, ROTATE_Y_NEG)) { mesh.rotation[2] -= .10; } if (CHECK_BIT(input, SCALE_UP)) { mesh.scale += 0.1f; } else if (CHECK_BIT(input, SCALE_DOWN)) { mesh.scale -= 0.1f; } } static void ComputeNormals(VertexList &verts, FaceList &faces) { int vertexNormalCount[VERTEX_LIMIT]; for (size_t f = 0; f < faces.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]; Point &p0 = verts.data[v0].point; Point &p1 = verts.data[v1].point; Point &p2 = verts.data[v2].point; Vector v01 = p1 - p0; Vector v02 = p2 - p0; 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; ++vertexNormalCount[v0]; ++vertexNormalCount[v1]; ++vertexNormalCount[v2]; } for (size_t v = 0; v < localVerts.size; ++v) { if (vertexNormalCount[v] > 0) { // Compute the average normal for this vertex verts.data[v].normal /= vertexNormalCount[v]; verts.data[v].normal.Normalize(); } } }