1
0
Fork 0
2018-soft-3d-renderer/src/engine.cpp

263 lines
6.3 KiB
C++

#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 <cstring>
#include <cstdio>
// 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();
}
}
}