From 131fbda1ea691492ee719ba9027d3efe9ae5aa4b Mon Sep 17 00:00:00 2001 From: outfrost Date: Thu, 14 Feb 2019 02:59:51 +0100 Subject: [PATCH] Implement custom Asset3D structure and refactor to use it --- asset.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++-- asset.h | 37 ++++++++++++- debugutil.c | 34 ------------ debugutil.h | 4 -- level.c | 82 ++------------------------- level.h | 8 +-- player.c | 8 +-- player.h | 5 +- render.c | 58 +++++++++---------- render.h | 2 - typedefs.h | 6 +- 11 files changed, 235 insertions(+), 166 deletions(-) diff --git a/asset.c b/asset.c index ff7c3db..6dc0bb3 100644 --- a/asset.c +++ b/asset.c @@ -1,11 +1,133 @@ +#include #include #include -#include "assimp_types.h" - +#include "asset.h" #include "logger.h" +#include "tga.h" + +static const AiScene* importScene(const char* path); +static Vector3D convertAiVector3D(AiVector3D vect); +static const char* replaceFileExtension(const AiString path, const char* ext); + + + +const Asset3D* importAsset(const char* path) { + const AiScene* scene = importScene(path); + if (scene == NULL) { + return NULL; + } + + const unsigned int numMeshes = scene->mNumMeshes; + const unsigned int numMaterials = scene->mNumMaterials; + + Asset3D* asset = malloc(sizeof(Asset3D)); + asset->numMeshes = numMeshes; + asset->meshes = malloc(numMeshes * sizeof(Mesh)); + asset->numMaterials = numMaterials; + asset->materials = malloc(numMaterials * sizeof(Material)); + + for (unsigned int meshIndex = 0; meshIndex < numMeshes; ++meshIndex) { + const AiMesh* aiMesh = scene->mMeshes[meshIndex]; + const unsigned int numVertices = aiMesh->mNumVertices; + const unsigned int numFaces = aiMesh->mNumFaces; + + Mesh mesh = { .numVertices = numVertices, + .vertices = malloc(numVertices * sizeof(Vector3D)), + .normals = NULL, + .textureCoords = NULL, + .numFaces = numFaces, + .faces = malloc(numFaces * sizeof(Face)), + .materialIndex = aiMesh->mMaterialIndex }; + + for (unsigned int vertIndex = 0; vertIndex < numVertices; ++vertIndex) { + mesh.vertices[vertIndex] = convertAiVector3D( + aiMesh->mVertices[vertIndex]); + } + + if (aiMesh->mNormals != NULL) { + mesh.normals = malloc(numVertices * sizeof(Vector3D)); + for (unsigned int normIndex = 0; normIndex < numVertices; ++normIndex) { + mesh.normals[normIndex] = convertAiVector3D( + aiMesh->mNormals[normIndex]); + } + } + + if (aiMesh->mTextureCoords != NULL) { + mesh.textureCoords = malloc(numVertices * sizeof(Vector3D)); + for (unsigned int texcIndex = 0; texcIndex < numVertices; ++texcIndex) { + mesh.textureCoords[texcIndex] = convertAiVector3D( + aiMesh->mTextureCoords[0][texcIndex]); + } + } + + for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { + const AiFace aiFace = aiMesh->mFaces[faceIndex]; + const unsigned int numIndices = aiFace.mNumIndices; + + Face face = { .numIndices = numIndices, + .indices = malloc(numIndices + * sizeof(unsigned int)) }; + + for (unsigned int i = 0; i < numIndices; ++i) { + face.indices[i] = aiFace.mIndices[i]; + } + + mesh.faces[faceIndex] = face; + } + + asset->meshes[meshIndex] = mesh; + } + + GLuint* textureIds = malloc(numMaterials * sizeof(GLuint)); + glGenTextures(numMaterials, textureIds); + + for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) { + Material material = { .textureId = textureIds[matIndex] }; + + glBindTexture(GL_TEXTURE_2D, material.textureId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + AiString originalTexturePath; + if (aiGetMaterialTexture(scene->mMaterials[matIndex], + aiTextureType_DIFFUSE, + 0, + &originalTexturePath, + NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { + const char* textureFile = replaceFileExtension(originalTexturePath, ".tga"); + const size_t textureFileLength = strlen(textureFile); + char* texturePath = malloc(strlen("assets/") + textureFileLength + 1); + strcpy(texturePath, "assets/"); + strncat(texturePath, textureFile, textureFileLength); + + TgaImage* textureImage = readTga(texturePath); + if (textureImage == NULL) { + logError("Asset texture file not found: %s", texturePath); + } + else { + glTexImage2D(GL_TEXTURE_2D, + 0, + textureImage->imageComponents, + textureImage->header.imageWidth, + textureImage->header.imageHeight, + 0, + textureImage->imageFormat, + GL_UNSIGNED_BYTE, + textureImage->bytes); + free(textureImage->bytes); + free(textureImage); + } + } + + asset->materials[matIndex] = material; + } + glBindTexture(GL_TEXTURE_2D, 0); + + aiReleaseImport(scene); + return asset; +} -const AiScene* importScene(const char* path) { +static const AiScene* importScene(const char* path) { const AiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices); if (scene == NULL) { logError("Failed to import asset from %s", path); @@ -16,5 +138,32 @@ const AiScene* importScene(const char* path) { scene = NULL; } return scene; - // TODO aiReleaseImport(scene); +} + +static Vector3D convertAiVector3D(AiVector3D vect) { + return (Vector3D) { .x = vect.x, + .y = vect.y, + .z = vect.z }; +} + +/** BUGS + * The following function will not work properly with texture + * file names (excluding directory part) beginning with '.' + */ +static const char* replaceFileExtension(const AiString path, const char* ext) { + size_t lengthToCopy = path.length; + + char* lastDotSubstr = strrchr(path.data, '.'); + if (lastDotSubstr != NULL) { + if (strpbrk(lastDotSubstr, "\\/") == NULL) { + lengthToCopy = lastDotSubstr - path.data; + } + } + + size_t extLength = strlen(ext) + 1; + char* newPath = malloc(lengthToCopy + extLength); + strncpy(newPath, path.data, lengthToCopy); + strncpy(newPath + lengthToCopy, ext, extLength); + + return newPath; } diff --git a/asset.h b/asset.h index 03e268f..c16338f 100644 --- a/asset.h +++ b/asset.h @@ -1,8 +1,43 @@ #ifndef ASSET_H_ #define ASSET_H_ +#include + #include "assimp_types.h" -const AiScene* importScene(const char* path); +#include "typedefs.h" + +typedef struct Asset3D Asset3D; +typedef struct Mesh Mesh; +typedef struct Face Face; +typedef struct Material Material; + +struct Asset3D { + unsigned int numMeshes; + Mesh* meshes; + unsigned int numMaterials; + Material* materials; +}; + +struct Mesh { + unsigned int numVertices; + Vector3D* vertices; + Vector3D* normals; + Vector3D* textureCoords; + unsigned int numFaces; + Face* faces; + unsigned int materialIndex; +}; + +struct Face { + unsigned int numIndices; + unsigned int* indices; +}; + +struct Material { + GLuint textureId; +}; + +const Asset3D* importAsset(const char* path); #endif diff --git a/debugutil.c b/debugutil.c index 3c105db..4292212 100644 --- a/debugutil.c +++ b/debugutil.c @@ -3,8 +3,6 @@ #include #include -//#include "assimp_types.h" - char* getGlInfoString() { const char* glVersion = (const char*) glGetString(GL_VERSION); const char* glslVersion = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); @@ -24,35 +22,3 @@ char* getGlInfoString() { return glInfoString; } -/* -void dumpScene(FILE* stream, const AiScene* scene) { - if (scene == NULL) { - fprintf(stream, "NULL"); - return; - } - fprintf(stream, "{ mFlags = %u, mRootNode = %p, mNumMeshes = %u, mMeshes = %p, mNumMaterials = %u, mMaterials = %p, mNumAnimations = %u, mAnimations = %p, mNumTextures = %u, mTextures = %p, mNumLights = %u, mLights = %p }", - (*scene).mFlags, - (void*) (*scene).mRootNode, - (*scene).mNumMeshes, - (void*) (*scene).mMeshes, - (*scene).mNumMaterials, - (void*) (*scene).mMaterials, - (*scene).mNumAnimations, - (void*) (*scene).mAnimations, - (*scene).mNumTextures, - (void*) (*scene).mTextures, - (*scene).mNumLights, - (void*) (*scene).mLights); -} - -void dumpNode(FILE* stream, const AiNode* node) { - if (node == NULL) { - fprintf(stream, "NULL"); - return; - } - fprintf(stream, "{ mName = %s, mNumMeshes = %u, mMeshes = %p }", - (*node).mName.data, - (*node).mNumMeshes, - (void*) (*node).mMeshes); -} -*/ diff --git a/debugutil.h b/debugutil.h index bc5d346..eb77ac9 100644 --- a/debugutil.h +++ b/debugutil.h @@ -3,10 +3,6 @@ #include -#include "assimp_types.h" - char* getGlInfoString(); -void dumpScene(FILE* stream, const AiScene* scene); -void dumpNode(FILE* stream, const AiNode* node); #endif diff --git a/level.c b/level.c index 0917319..a16061a 100644 --- a/level.c +++ b/level.c @@ -1,17 +1,14 @@ #include #include -#include "asset.h" #include "level.h" #include "logger.h" #include "player.h" static Block blockEmpty = { .type = BLOCKTYPE_SPACE, - .sceneData = NULL, - .textureIds = NULL }; + .asset3D = NULL }; static Block blockWall01 = { .type = BLOCKTYPE_OBSTACLE, - .sceneData = NULL, - .textureIds = NULL }; + .asset3D = NULL }; static Block* testBlocks[9] = { &blockWall01, &blockWall01, &blockWall01, &blockEmpty, &blockEmpty, &blockEmpty, @@ -22,57 +19,12 @@ BlockGrid levelGrid = { .width = 3, .blocks = testBlocks }; #define DEFAULT_PLAYER_SPAWN_POS { -BLOCKGRID_CELL_SIZE, 0.0f, -BLOCKGRID_CELL_SIZE } -AiVector3D playerSpawnPos = DEFAULT_PLAYER_SPAWN_POS; - -static const char* replaceFileExtension(const AiString path, const char* ext); +Vector3D playerSpawnPos = DEFAULT_PLAYER_SPAWN_POS; void initLevel() { - const AiScene* sceneData = importScene("assets/wall01.3ds"); - blockWall01.sceneData = sceneData; - if (sceneData != NULL) { - const unsigned int numTextures = sceneData->mNumMeshes; - - blockWall01.textureIds = malloc(numTextures * sizeof(GLuint)); - glGenTextures(numTextures, blockWall01.textureIds); - - for (unsigned int i = 0; i < numTextures; ++i) { - glBindTexture(GL_TEXTURE_2D, blockWall01.textureIds[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - AiString originalTexturePath; - if (aiGetMaterialTexture(sceneData->mMaterials[sceneData->mMeshes[i]->mMaterialIndex], - aiTextureType_DIFFUSE, - 0, - &originalTexturePath, - NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) { - const char* textureFile = replaceFileExtension(originalTexturePath, ".tga"); - size_t textureFileLength = strlen(textureFile); - char* texturePath = malloc(strlen("assets/") + textureFileLength + 1); - strcpy(texturePath, "assets/"); - strncat(texturePath, textureFile, textureFileLength); - TgaImage* textureImage = readTga(texturePath); - if (textureImage == NULL) { - logError("Asset texture file not found: %s", texturePath); - } - else { - glTexImage2D(GL_TEXTURE_2D, - 0, - textureImage->imageComponents, - textureImage->header.imageWidth, - textureImage->header.imageHeight, - 0, - textureImage->imageFormat, - GL_UNSIGNED_BYTE, - textureImage->bytes); - free(textureImage->bytes); - } - } - } - - glBindTexture(GL_TEXTURE_2D, 0); - } + blockWall01.asset3D = importAsset("assets/wall01.3ds"); buildLevelFromImage(readTga("assets/level01.tga")); } @@ -93,7 +45,7 @@ void buildLevelFromImage(TgaImage* image) { .blocks = malloc(image->header.imageWidth * image->header.imageHeight * sizeof(Block*)) }; - playerSpawnPos = (AiVector3D) DEFAULT_PLAYER_SPAWN_POS; + playerSpawnPos = (Vector3D) DEFAULT_PLAYER_SPAWN_POS; for (int row = 0; row < newGrid.depth; ++row) { for (int x = 0; x < newGrid.width; ++x) { @@ -108,7 +60,7 @@ void buildLevelFromImage(TgaImage* image) { break; case 0xFF00FFFF: block = &blockEmpty; - playerSpawnPos = (AiVector3D) { x * BLOCKGRID_CELL_SIZE, 0.0f, z * BLOCKGRID_CELL_SIZE }; + playerSpawnPos = (Vector3D) { x * BLOCKGRID_CELL_SIZE, 0.0f, z * BLOCKGRID_CELL_SIZE }; break; default: block = &blockEmpty; @@ -121,25 +73,3 @@ void buildLevelFromImage(TgaImage* image) { levelGrid = newGrid; spawnPlayer(); } - -/** BUGS - * The following function will not work properly with texture - * file names (excluding directory part) beginning with '.' - */ -static const char* replaceFileExtension(const AiString path, const char* ext) { - size_t lengthToCopy = path.length; - - char* lastDotSubstr = strrchr(path.data, '.'); - if (lastDotSubstr != NULL) { - if (strpbrk(lastDotSubstr, "\\/") == NULL) { - lengthToCopy = lastDotSubstr - path.data; - } - } - - size_t extLength = strlen(ext) + 1; - char* newPath = malloc(lengthToCopy + extLength); - strncpy(newPath, path.data, lengthToCopy); - strncpy(newPath + lengthToCopy, ext, extLength); - - return newPath; -} diff --git a/level.h b/level.h index 83fefd9..967c78e 100644 --- a/level.h +++ b/level.h @@ -3,8 +3,7 @@ #include -#include "assimp_types.h" - +#include "asset.h" #include "tga.h" typedef enum { @@ -16,8 +15,7 @@ typedef enum { typedef struct { const BlockType type; - const AiScene* sceneData; - GLuint* textureIds; + const Asset3D* asset3D; } Block; typedef struct { @@ -29,7 +27,7 @@ typedef struct { #define BLOCKGRID_CELL_SIZE 2.5f BlockGrid levelGrid; -AiVector3D playerSpawnPos; +Vector3D playerSpawnPos; void initLevel(); void buildLevelFromImage(TgaImage* image); diff --git a/player.c b/player.c index c06a05d..d81d78b 100644 --- a/player.c +++ b/player.c @@ -1,17 +1,15 @@ -#include "asset.h" #include "level.h" #include "logger.h" #include "player.h" -PlayerCharacter playerCharacter = { .sceneData = NULL, - .textureIds = NULL }; +PlayerCharacter playerCharacter = { .asset3D = NULL }; -static AiVector3D playerPos; +static Vector3D playerPos; void initPlayer() { - playerCharacter.sceneData = importScene("assets/playercharacter.3ds"); + playerCharacter.asset3D = importAsset("assets/playercharacter.3ds"); // TODO import textures } diff --git a/player.h b/player.h index f480c45..9a0eb92 100644 --- a/player.h +++ b/player.h @@ -3,11 +3,10 @@ #include -#include "assimp_types.h" +#include "asset.h" typedef struct { - const AiScene* sceneData; - GLuint* textureIds; + const Asset3D* asset3D; } PlayerCharacter; void spawnPlayer(); diff --git a/render.c b/render.c index 87acb69..05ab0c1 100644 --- a/render.c +++ b/render.c @@ -1,8 +1,6 @@ #include #include -#include "assimp_types.h" - #include "level.h" #include "performance.h" #include "typedefs.h" @@ -58,29 +56,23 @@ void renderScene() { } static void drawAxes() { - point3f xAxisStart = { 0.0f, 0.0f, 0.0f }; - point3f xAxisEnd = { AXIS_RADIUS, 0.0f, 0.0f }; - point3f yAxisStart = { 0.0f, 0.0f, 0.0f }; - point3f yAxisEnd = { 0.0f, AXIS_RADIUS, 0.0f }; - point3f zAxisStart = { 0.0f, 0.0f, 0.0f }; - point3f zAxisEnd = { 0.0f, 0.0f, AXIS_RADIUS }; - + // X axis glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_LINES); - glVertex3fv(xAxisStart); - glVertex3fv(xAxisEnd); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(AXIS_RADIUS, 0.0f, 0.0f); glEnd(); - + // Y axis glColor3f(0.0f, 1.0f, 0.0f); glBegin(GL_LINES); - glVertex3fv(yAxisStart); - glVertex3fv(yAxisEnd); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, AXIS_RADIUS, 0.0f); glEnd(); - + // Z axis glColor3f(0.0f, 0.0f, 1.0f); glBegin(GL_LINES); - glVertex3fv(zAxisStart); - glVertex3fv(zAxisEnd); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, 0.0f, AXIS_RADIUS); glEnd(); } @@ -98,23 +90,25 @@ static void renderBlockGrid(const BlockGrid grid) { } static void drawBlock(const Block* block) { - if (block->sceneData == NULL) { + if (block->asset3D == NULL) { return; } glColor3f(0.5f, 1.0f, 0.0f); - for (int i = 0; i < block->sceneData->mNumMeshes; ++i) { - glBindTexture(GL_TEXTURE_2D, block->textureIds[i]); - const AiMesh* mesh = block->sceneData->mMeshes[i]; - bool hasNormals = mesh->mNormals != NULL; - bool hasTextureCoords = mesh->mTextureCoords[0] != NULL; + const Asset3D* asset3D = block->asset3D; + for (int meshIndex = 0; meshIndex < asset3D->numMeshes; ++meshIndex) { + const Mesh mesh = asset3D->meshes[meshIndex]; + glBindTexture(GL_TEXTURE_2D, + asset3D->materials[mesh.materialIndex].textureId); + bool hasNormals = mesh.normals != NULL; + bool hasTextureCoords = mesh.textureCoords != NULL; - for (int k = 0; k < mesh->mNumFaces; ++k) { - const AiFace face = mesh->mFaces[k]; + for (int faceIndex = 0; faceIndex < mesh.numFaces; ++faceIndex) { + const Face face = mesh.faces[faceIndex]; GLenum faceMode; - switch (face.mNumIndices) { + switch (face.numIndices) { case 1: faceMode = GL_POINTS; break; case 2: faceMode = GL_LINES; break; case 3: faceMode = GL_TRIANGLES; break; @@ -123,16 +117,18 @@ static void drawBlock(const Block* block) { glBegin(faceMode); - for (int l = 0; l < face.mNumIndices; ++l) { - unsigned int vertexIndex = face.mIndices[l]; + for (int i = 0; i < face.numIndices; ++i) { + unsigned int vertIndex = face.indices[i]; if (hasNormals) { if (hasTextureCoords) { - AiVector3D coords = mesh->mTextureCoords[0][vertexIndex]; + Vector3D coords = mesh.textureCoords[vertIndex]; glTexCoord2f(coords.x, coords.y); } - glNormal3fv(&mesh->mNormals[vertexIndex].x); + Vector3D normal = mesh.normals[vertIndex]; + glNormal3f(normal.x, normal.y, normal.z); } - glVertex3fv((const GLfloat*) &mesh->mVertices[vertexIndex]); + Vector3D vertex = mesh.vertices[vertIndex]; + glVertex3f(vertex.x, vertex.y, vertex.z); } glEnd(); diff --git a/render.h b/render.h index 6b8c632..e4c46d4 100644 --- a/render.h +++ b/render.h @@ -1,8 +1,6 @@ #ifndef RENDER_H_ #define RENDER_H_ -#include "assimp_types.h" - void initRender(); void renderScene(); diff --git a/typedefs.h b/typedefs.h index 8343393..8e690ed 100644 --- a/typedefs.h +++ b/typedefs.h @@ -1,6 +1,10 @@ #ifndef TYPEDEFS_H_ #define TYPEDEFS_H_ -typedef float point3f[3]; +typedef struct { + float x; + float y; + float z; +} Vector3D; #endif -- 2.44.0