#include "engine.h" #include "loader.h" #include #include #include #include #include // STATIC PROTOTYPES 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) // PUBLIC FUNCTIONS int ParseOBJ(char *filename, EngineMemory &memory) { FILE *fp = fopen(filename, "r"); if (fp == NULL) { fprintf(stderr, "Error loading file: %s\n", filename); return -1; } char line[256]; int vertIndex = 0; int uvIndex = 0; int 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 != NULL) { *separator = '\0'; char *type = line; char *data = separator + 1; if (strcmp(type, "v") == 0) { sscanf( data, "%f %f %f", &verts.data[vertIndex].point.x, &verts.data[vertIndex].point.y, &verts.data[vertIndex].point.z); verts.data[vertIndex].point.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 = (size_t)vertIndex; uvs.size = (size_t)uvIndex; faces.size = (size_t)faceIndex; return 0; } int ParseMTL(char *filename, EngineMemory &memory) { FILE *fp = fopen(filename, "r"); if (fp == NULL) { 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 != NULL) { *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].specularExp); } 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 = (size_t)(materialIndex + 1); return 0; } static int LoadTexture(char *filename, Texture &texture, float opacity) { 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); // Padding is added to image to align to 4-byte boundaries size_t paddingSize = 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; }