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

224 lines
5.4 KiB
C++
Raw Normal View History

2018-09-05 02:50:27 +00:00
#include "loader.h"
#include <cctype>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
2018-09-05 02:50:27 +00:00
#include <cstring>
// STATIC PROTOTYPES
static char *GetLine(char *buffer, int maxLength, FILE *fp);
2018-09-11 02:51:59 +00:00
static void ComputeNormals(Mesh &mesh);
2018-09-05 02:50:27 +00:00
#pragma pack(push, 1)
struct BMP_Header
{
uint16_t fileType;
uint32_t fileSize;
uint16_t reserved0;
uint16_t reserved1;
uint32_t bitmapOffset;
uint32_t size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bitsPerPixel;
uint32_t compression;
uint32_t sizeOfBitmap;
int32_t horizRes;
int32_t vertRes;
uint32_t colorsUsed;
uint32_t colorsImportant;
};
#pragma pack(pop)
2018-09-05 02:50:27 +00:00
// PUBLIC FUNCTIONS
int LoadMesh(char *filename, Mesh &mesh)
{
FILE *fp;
char buffer[256];
char *token;
char garbage[5];
fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "Error loading file: %s\n", filename);
return -1;
}
token = GetLine(buffer, sizeof(buffer), fp);
while (token != NULL)
{
if (token[0] == 'v')
{
if (token[1] == ' ')
{
Vertex v;
sscanf(
token, "%s %f %f %f",
garbage,
&v.point.x,
&v.point.y,
&v.point.z);
mesh.local.verts.push_back(v);
}
else if (token[1] == 't')
{
TextureCoord textureCoord;
sscanf(
token, "%s %f %f",
garbage,
&textureCoord.u,
&textureCoord.v);
mesh.local.uvs.push_back(textureCoord);
}
2018-09-05 02:50:27 +00:00
}
else if (token[0] == 'f')
{
Face f;
sscanf(token, "%s %d/%d %d/%d %d/%d",
2018-09-05 02:50:27 +00:00
garbage,
&f.vertIndex[0],
&f.textureIndex[0],
2018-09-05 02:50:27 +00:00
&f.vertIndex[1],
&f.textureIndex[1],
&f.vertIndex[2],
&f.textureIndex[2]);
2018-09-05 02:50:27 +00:00
// Convert to 0-indexed
f.vertIndex[0] -= 1;
f.vertIndex[1] -= 1;
f.vertIndex[2] -= 1;
f.textureIndex[0] -= 1;
f.textureIndex[1] -= 1;
f.textureIndex[2] -= 1;
2018-09-05 02:50:27 +00:00
mesh.local.faces.push_back(f);
2018-09-05 02:50:27 +00:00
}
token = GetLine(buffer, sizeof(buffer), fp);
}
2018-09-11 02:51:59 +00:00
ComputeNormals(mesh);
printf("Mesh: %s [v: %lu f: %lu]\n", filename, mesh.local.verts.size(), mesh.local.faces.size());
2018-09-05 02:50:27 +00:00
mesh.transformed.verts.resize(mesh.local.verts.size());
2018-09-05 02:50:27 +00:00
fclose(fp);
return 0;
}
int LoadTexture(char *filename, Texture &texture)
{
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "Could not open file: %s\n", filename);
return -1;
}
BMP_Header header = {};
fread((void*)&header, sizeof(BMP_Header), 1, fp);
fseek(fp, header.bitmapOffset, SEEK_SET);
texture.texels = (ColorU32**)malloc((size_t)header.height * sizeof(ColorU32*));
for (int row = 0; row < header.height; ++row)
{
texture.texels[row] = (ColorU32*)calloc(1, (size_t)header.width * sizeof(ColorU32));
}
// Padding is added to image to align to 4-byte boundaries
size_t paddingSize = header.width % 4;
uint8_t *padding = (uint8_t*)malloc(paddingSize * sizeof(*padding));
for (int y = 0; y < header.height; ++y)
{
for (int x = 0; x < header.width; ++x)
{
fread(&texture.texels[y][x].b, 1, 1, fp);
fread(&texture.texels[y][x].g, 1, 1, fp);
fread(&texture.texels[y][x].r, 1, 1, fp);
}
// Discard padding byte
if (paddingSize != 0)
{
fread(padding, paddingSize, 1, fp);
}
}
texture.width = (unsigned int)header.width;
texture.height = (unsigned int)header.height;
fclose(fp);
return 0;
}
2018-09-05 02:50:27 +00:00
static char *GetLine(char *buffer, int maxLength, FILE *fp)
{
while(true)
{
if (!fgets(buffer, maxLength, fp))
{
return NULL;
}
if (buffer[0] != 'v' && buffer[0] != 'f')
{
continue;
}
return buffer;
}
}
2018-09-11 02:51:59 +00:00
static void ComputeNormals(Mesh &mesh)
{
int *vertexNormalCount = (int*)calloc((size_t)(mesh.local.verts.size()), sizeof(int));
2018-09-11 02:51:59 +00:00
for (size_t f = 0; f < mesh.local.faces.size(); ++f)
2018-09-11 02:51:59 +00:00
{
unsigned int v0 = mesh.local.faces[f].vertIndex[0];
unsigned int v1 = mesh.local.faces[f].vertIndex[1];
unsigned int v2 = mesh.local.faces[f].vertIndex[2];
2018-09-11 02:51:59 +00:00
Vector v01 = mesh.local.verts[v1].point - mesh.local.verts[v0].point;
Vector v02 = mesh.local.verts[v2].point - mesh.local.verts[v0].point;
2018-09-11 02:51:59 +00:00
Vector normal = Vector::Cross(v01, v02);
// Add each vertex's normal to the sum for future averaging
mesh.local.verts[v0].normal += normal;
mesh.local.verts[v1].normal += normal;
mesh.local.verts[v2].normal += normal;
2018-09-11 02:51:59 +00:00
++vertexNormalCount[v0];
++vertexNormalCount[v1];
++vertexNormalCount[v2];
}
for (size_t v = 0; v < mesh.local.verts.size(); ++v)
2018-09-11 02:51:59 +00:00
{
if (vertexNormalCount[v] > 0)
{
// Compute the average normal for this vertex
mesh.local.verts[v].normal /= vertexNormalCount[v];
mesh.local.verts[v].normal.Normalize();
2018-09-11 02:51:59 +00:00
}
}
}