257 lines
5.2 KiB
C++
257 lines
5.2 KiB
C++
#include "Engine.hpp"
|
|
#include "Loader.hpp"
|
|
#include <cctype>
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
|
|
static int LoadTexture(char* filename, Texture& texture, float opacity);
|
|
|
|
|
|
#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)
|
|
|
|
|
|
int ParseOBJ(char* filename, EngineMemory& memory)
|
|
{
|
|
FILE* fp = fopen(filename, "r");
|
|
|
|
if (fp == nullptr)
|
|
{
|
|
fprintf(stderr, "Error loading file: %s\n", filename);
|
|
return -1;
|
|
}
|
|
|
|
|
|
char line[256];
|
|
unsigned long vertIndex = 0;
|
|
unsigned long uvIndex = 0;
|
|
unsigned long faceIndex = 0;
|
|
int materialIndex = -1;
|
|
|
|
VertexList& verts = memory.localVerts;
|
|
FaceList& faces = memory.localFaces;
|
|
UVList& uvs = memory.uvs;
|
|
|
|
while (fgets(line, sizeof(line), fp))
|
|
{
|
|
char* separator = strchr(line, ' ');
|
|
|
|
if (separator != nullptr)
|
|
{
|
|
*separator = '\0';
|
|
char* type = line;
|
|
char* data = separator + 1;
|
|
|
|
if (strcmp(type, "v") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f %f %f",
|
|
&verts.data[vertIndex].position.x,
|
|
&verts.data[vertIndex].position.y,
|
|
&verts.data[vertIndex].position.z);
|
|
|
|
verts.data[vertIndex].position.w = 1.0f;
|
|
|
|
++vertIndex;
|
|
}
|
|
|
|
else if (strcmp(type, "vt") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f %f",
|
|
&uvs.data[uvIndex].u,
|
|
&uvs.data[uvIndex].v);
|
|
|
|
++uvIndex;
|
|
}
|
|
else if (strcmp(type, "usemtl") == 0)
|
|
{
|
|
++materialIndex;
|
|
}
|
|
|
|
else if (strcmp(type, "f") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%d/%d %d/%d %d/%d",
|
|
&faces.data[faceIndex].vertIndex[0],
|
|
&faces.data[faceIndex].uvIndex[0],
|
|
&faces.data[faceIndex].vertIndex[1],
|
|
&faces.data[faceIndex].uvIndex[1],
|
|
&faces.data[faceIndex].vertIndex[2],
|
|
&faces.data[faceIndex].uvIndex[2]);
|
|
|
|
// Convert to 0-indexed
|
|
faces.data[faceIndex].vertIndex[0] -= 1;
|
|
faces.data[faceIndex].vertIndex[1] -= 1;
|
|
faces.data[faceIndex].vertIndex[2] -= 1;
|
|
faces.data[faceIndex].uvIndex[0] -= 1;
|
|
faces.data[faceIndex].uvIndex[1] -= 1;
|
|
faces.data[faceIndex].uvIndex[2] -= 1;
|
|
|
|
faces.data[faceIndex].materialIndex = materialIndex;
|
|
|
|
++faceIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
verts.size = vertIndex;
|
|
uvs.size = uvIndex;
|
|
faces.size = faceIndex;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ParseMTL(char* filename, EngineMemory& memory)
|
|
{
|
|
FILE* fp = fopen(filename, "r");
|
|
|
|
if (fp == nullptr)
|
|
{
|
|
fprintf(stderr, "Error loading file: %s\n", filename);
|
|
return -1;
|
|
}
|
|
|
|
char line[256];
|
|
int materialIndex = -1;
|
|
|
|
MaterialList& materials = memory.materials;
|
|
TextureList& textures = memory.textures;
|
|
|
|
while (fgets(line, sizeof(line), fp))
|
|
{
|
|
char* separator = strchr(line, ' ');
|
|
|
|
if (separator != nullptr)
|
|
{
|
|
*separator = '\0';
|
|
char* type = line;
|
|
char* data = separator + 1;
|
|
|
|
if (strcmp(type, "newmtl") == 0)
|
|
{
|
|
++materialIndex;
|
|
}
|
|
|
|
else if (strcmp(type, "Ns") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f",
|
|
&materials.data[materialIndex].glossiness);
|
|
}
|
|
|
|
else if (strcmp(type, "Ka") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f %f %f",
|
|
&materials.data[materialIndex].ambient.r,
|
|
&materials.data[materialIndex].ambient.g,
|
|
&materials.data[materialIndex].ambient.b);
|
|
}
|
|
|
|
else if (strcmp(type, "Kd") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f %f %f",
|
|
&materials.data[materialIndex].diffuse.r,
|
|
&materials.data[materialIndex].diffuse.g,
|
|
&materials.data[materialIndex].diffuse.b);
|
|
}
|
|
|
|
else if (strcmp(type, "Ks") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f %f %f",
|
|
&materials.data[materialIndex].specular.r,
|
|
&materials.data[materialIndex].specular.g,
|
|
&materials.data[materialIndex].specular.b);
|
|
}
|
|
|
|
else if (strcmp(type, "d") == 0)
|
|
{
|
|
sscanf(
|
|
data, "%f",
|
|
&materials.data[materialIndex].opacity);
|
|
}
|
|
|
|
else if (strcmp(type, "map_Kd") == 0)
|
|
{
|
|
char* textureFilename = data;
|
|
textureFilename[strcspn(textureFilename, "\r\n")] = 0;
|
|
LoadTexture(
|
|
textureFilename, textures.data[materialIndex],
|
|
materials.data[materialIndex].opacity);
|
|
}
|
|
}
|
|
}
|
|
|
|
materials.size = materialIndex + 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int LoadTexture(char* filename, Texture& texture, float opacity)
|
|
{
|
|
FILE* fp = fopen(filename, "r");
|
|
if (fp == nullptr)
|
|
{
|
|
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);
|
|
|
|
// Padding is added to image to align to 4-byte boundaries
|
|
unsigned long paddingSize = static_cast<unsigned long>(header.width % 4);
|
|
|
|
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);
|
|
texture.texels[y][x].a = (uint8_t)(255 * opacity);
|
|
}
|
|
|
|
// Discard padding byte
|
|
if (paddingSize != 0)
|
|
{
|
|
uint32_t padding;
|
|
fread(&padding, paddingSize, 1, fp);
|
|
}
|
|
}
|
|
|
|
texture.width = (unsigned int)header.width;
|
|
texture.height = (unsigned int)header.height;
|
|
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
}
|
|
|