2018-09-06 01:48:27 +00:00
|
|
|
#include "camera.h"
|
2018-09-06 01:53:11 +00:00
|
|
|
#include "color.h"
|
2018-09-05 01:50:14 +00:00
|
|
|
#include "engine.h"
|
2018-09-06 01:53:11 +00:00
|
|
|
#include "geometry.h"
|
2018-09-06 02:26:54 +00:00
|
|
|
#include "light.h"
|
2018-09-05 02:50:27 +00:00
|
|
|
#include "loader.h"
|
2018-09-06 01:48:27 +00:00
|
|
|
#include "matrix.h"
|
|
|
|
#include "transform.h"
|
|
|
|
#include "util.h"
|
2018-09-06 02:26:54 +00:00
|
|
|
#include "vec.h"
|
2018-09-07 01:32:15 +00:00
|
|
|
#include <cstring>
|
2018-09-15 01:46:30 +00:00
|
|
|
#include <cstdio>
|
2018-09-05 02:50:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
// GLOBALS
|
|
|
|
static Mesh mesh;
|
2018-09-06 01:48:27 +00:00
|
|
|
static Camera camera;
|
2018-09-19 03:02:12 +00:00
|
|
|
static Light light;
|
2018-09-15 01:46:30 +00:00
|
|
|
static VertexList localVerts;
|
|
|
|
static VertexList transVerts;
|
|
|
|
static FaceList localFaces;
|
|
|
|
static FaceList transFaces;
|
|
|
|
static UVList uvs;
|
|
|
|
static MaterialList materials;
|
|
|
|
static TextureList textures;
|
2018-09-19 02:18:58 +00:00
|
|
|
static Matrix tPersp;
|
|
|
|
static Matrix tScreen;
|
2018-09-05 02:50:27 +00:00
|
|
|
|
2018-09-05 01:50:14 +00:00
|
|
|
|
2018-09-06 01:48:27 +00:00
|
|
|
// PRIVATE PROTOTYPES
|
|
|
|
static void CheckInputs(uint32_t input);
|
2018-09-19 02:18:58 +00:00
|
|
|
static void ComputeNormals(void);
|
|
|
|
static void ClearDepthBuffer(Engine_Buffer &buffer);
|
|
|
|
static void TransformToClipSpace(void);
|
|
|
|
static void TransformToScreenSpace(void);
|
2018-09-19 03:02:12 +00:00
|
|
|
static void LightMesh(void);
|
2018-09-06 01:48:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
// PUBLIC FUNCTIONS
|
2018-09-19 02:18:58 +00:00
|
|
|
int Engine_Init(char *objFilename, char *mtlFilename)
|
2018-09-05 01:50:14 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
int result;
|
2018-09-05 02:50:27 +00:00
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
|
|
|
|
result = ParseOBJ(objFilename, localVerts, localFaces, uvs);
|
2018-09-15 01:46:30 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
return -1;
|
2018-09-15 01:46:30 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
|
2018-09-15 01:46:30 +00:00
|
|
|
result = ParseMTL(mtlFilename, materials, textures);
|
2018-09-05 02:50:27 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
|
2018-09-15 01:46:30 +00:00
|
|
|
printf("Verts: %lu\n", localVerts.size);
|
|
|
|
printf("Faces: %lu\n", localFaces.size);
|
|
|
|
printf("Materials: %lu\n", materials.size);
|
|
|
|
|
|
|
|
transVerts.size = localVerts.size;
|
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Compute vertex and face normals for lighting calculation
|
|
|
|
ComputeNormals();
|
|
|
|
|
|
|
|
|
|
|
|
// Mesh configuration
|
2018-09-19 03:02:12 +00:00
|
|
|
mesh.position.z = 125;
|
|
|
|
mesh.position.y = -125;
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.scale = 1.0f;
|
2018-09-06 01:48:27 +00:00
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Light configuration
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position = Point(-100.0f, 200.0f, 0.0f);
|
|
|
|
light.color = {1.0f, 1.0f, 1.0f, 1.0f};
|
|
|
|
light.intensity = 2.0f;
|
|
|
|
light.falloffConstant = 1.0f;
|
|
|
|
light.falloffLinear = 0.001f;
|
2018-09-06 02:26:54 +00:00
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
|
|
|
|
// Transformation matrices that do not change
|
|
|
|
tPersp = Transform_Perspective(camera);
|
|
|
|
tScreen = Transform_Screen(camera);
|
|
|
|
|
|
|
|
|
2018-09-05 01:50:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine_Render(Engine_Buffer &buffer, uint32_t input)
|
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
// Check for user input
|
2018-09-06 01:48:27 +00:00
|
|
|
CheckInputs(input);
|
|
|
|
|
2018-09-08 01:30:02 +00:00
|
|
|
|
|
|
|
// Clear the z-buffer
|
2018-09-19 02:18:58 +00:00
|
|
|
ClearDepthBuffer(buffer);
|
2018-09-06 01:48:27 +00:00
|
|
|
|
2018-09-06 02:26:54 +00:00
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Transform vertices to clip space
|
|
|
|
TransformToClipSpace();
|
2018-09-15 01:46:30 +00:00
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Clip near/far Z and cull backfaces
|
2018-09-15 01:46:30 +00:00
|
|
|
ClipAndCull(transVerts, localFaces, transFaces, camera.position);
|
2018-09-06 02:26:54 +00:00
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Light vertices and/or faces
|
2018-09-19 03:02:12 +00:00
|
|
|
LightMesh();
|
2018-09-06 02:26:54 +00:00
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
// Transform vertices to screen space
|
|
|
|
TransformToScreenSpace();
|
2018-09-06 01:48:27 +00:00
|
|
|
|
2018-09-15 01:46:30 +00:00
|
|
|
|
|
|
|
// Render
|
|
|
|
RenderMesh(buffer, transFaces, transVerts, uvs, textures);
|
2018-09-05 01:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine_Shutdown(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-09-06 01:48:27 +00:00
|
|
|
|
|
|
|
// PRIVATE FUNCTIONS
|
|
|
|
static void CheckInputs(uint32_t input)
|
|
|
|
{
|
|
|
|
if (CHECK_BIT(input, TRANSLATE_X_POS))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.x += 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
else if (CHECK_BIT(input, TRANSLATE_X_NEG))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.x -= 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CHECK_BIT(input, TRANSLATE_Z_POS))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.z += 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
else if (CHECK_BIT(input, TRANSLATE_Z_NEG))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.z -= 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CHECK_BIT(input, TRANSLATE_Y_POS))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.y += 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
else if (CHECK_BIT(input, TRANSLATE_Y_NEG))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.position.y -= 10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CHECK_BIT(input, ROTATE_X_POS))
|
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.x += .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
else if (CHECK_BIT(input, ROTATE_X_NEG))
|
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.x -= .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
if (CHECK_BIT(input, ROTATE_Y_POS))
|
2018-09-06 01:48:27 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.y += .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
2018-09-19 02:18:58 +00:00
|
|
|
else if (CHECK_BIT(input, ROTATE_Y_NEG))
|
2018-09-06 01:48:27 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.y -= .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
if (CHECK_BIT(input, ROTATE_Z_POS))
|
2018-09-06 01:48:27 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.z += .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
2018-09-19 02:18:58 +00:00
|
|
|
else if (CHECK_BIT(input, ROTATE_Z_NEG))
|
2018-09-06 01:48:27 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
mesh.rotation.z -= .10;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CHECK_BIT(input, SCALE_UP))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.color.b = 0.0f;
|
|
|
|
light.color.g = 0.0f;
|
|
|
|
light.color.r = 1.0f;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
else if (CHECK_BIT(input, SCALE_DOWN))
|
|
|
|
{
|
2018-09-19 03:02:12 +00:00
|
|
|
light.color.b = 1.0f;
|
|
|
|
light.color.g = 1.0f;
|
|
|
|
light.color.r = 1.0f;
|
2018-09-06 01:48:27 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-15 01:46:30 +00:00
|
|
|
|
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
static void ComputeNormals(void)
|
2018-09-15 01:46:30 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
int vertexNormalCount[VERTEX_LIMIT] = {};
|
2018-09-15 01:46:30 +00:00
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
for (size_t f = 0; f < localFaces.size; ++f)
|
2018-09-15 01:46:30 +00:00
|
|
|
{
|
2018-09-19 02:18:58 +00:00
|
|
|
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];
|
2018-09-15 01:46:30 +00:00
|
|
|
|
2018-09-19 02:18:58 +00:00
|
|
|
Point &p0 = localVerts.data[v0].point;
|
|
|
|
Point &p1 = localVerts.data[v1].point;
|
|
|
|
Point &p2 = localVerts.data[v2].point;
|
2018-09-15 01:46:30 +00:00
|
|
|
|
|
|
|
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
|
2018-09-19 02:18:58 +00:00
|
|
|
localVerts.data[v0].normal += normal;
|
|
|
|
localVerts.data[v1].normal += normal;
|
|
|
|
localVerts.data[v2].normal += normal;
|
2018-09-15 01:46:30 +00:00
|
|
|
|
|
|
|
++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
|
2018-09-19 02:18:58 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-19 03:02:12 +00:00
|
|
|
static void LightMesh(void)
|
2018-09-19 02:18:58 +00:00
|
|
|
{
|
|
|
|
for (size_t f = 0; f < transFaces.size; ++f)
|
|
|
|
{
|
|
|
|
Face &face = transFaces.data[f];
|
|
|
|
Material &material = materials.data[face.materialIndex];
|
|
|
|
|
|
|
|
// Gouraud shading
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
Vertex &vert = transVerts.data[face.vertIndex[i]];
|
|
|
|
|
2018-09-19 03:02:12 +00:00
|
|
|
vert.color = ComputeLight(vert, material, light);
|
2018-09-15 01:46:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|