1
0
Fork 0
2018-soft-3d-renderer/Source/Loader.cpp

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;
}