]> git.lizzy.rs Git - shadowclad.git/commitdiff
Implement custom Asset3D structure and refactor to use it
authoroutfrost <kotlet.bahn@gmail.com>
Thu, 14 Feb 2019 01:59:51 +0000 (02:59 +0100)
committeroutfrost <kotlet.bahn@gmail.com>
Thu, 14 Feb 2019 01:59:51 +0000 (02:59 +0100)
asset.c
asset.h
debugutil.c
debugutil.h
level.c
level.h
player.c
player.h
render.c
render.h
typedefs.h

diff --git a/asset.c b/asset.c
index ff7c3dbc8623670d8f8d5396aece5147a96bff4a..6dc0bb3a6a94f0f86dd96e369d8ffd41da44c59b 100644 (file)
--- a/asset.c
+++ b/asset.c
+#include <stdlib.h>
 #include <assimp/cimport.h>
 #include <assimp/postprocess.h>
 
-#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 03e268f255a94dd346664fbc5f47f82b85b1399c..c16338f5e573eddf6f93eef5b1eaa61090f4da0f 100644 (file)
--- a/asset.h
+++ b/asset.h
@@ -1,8 +1,43 @@
 #ifndef ASSET_H_
 #define ASSET_H_
 
+#include <GL/gl.h>
+
 #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
index 3c105db2552c10ff14c4ac4b87605e888eba6fe9..4292212dd9dd44231ebd9dad9d43fbf530f76913 100644 (file)
@@ -3,8 +3,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-//#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);
-}
-*/
index bc5d346443ec66717d632181b667f92784227edd..eb77ac98e1f1eaf736927cf165208348bd56e8e4 100644 (file)
@@ -3,10 +3,6 @@
 
 #include <stdio.h>
 
-#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 0917319801ec62f309d12ac5ef08f96502c84da6..a16061ab0b3e4167a14569366499f8ace8f2c6be 100644 (file)
--- a/level.c
+++ b/level.c
@@ -1,17 +1,14 @@
 #include <GL/gl.h>
 #include <stdlib.h>
 
-#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 83fefd908e0248be3f8641bf5d1c05755c84f053..967c78e4095137c15e6392474eaff9c64be66206 100644 (file)
--- a/level.h
+++ b/level.h
@@ -3,8 +3,7 @@
 
 #include <stdint.h>
 
-#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);
index c06a05d982e6c906985442fca7675698010cab48..d81d78b23820486edca92395166ff406567dc7fb 100644 (file)
--- 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
 }
 
index f480c45e7812e819b260abd6ca830b31773c4830..9a0eb929b1940d131725961f8398dd2c5fa96d37 100644 (file)
--- a/player.h
+++ b/player.h
@@ -3,11 +3,10 @@
 
 #include <GL/gl.h>
 
-#include "assimp_types.h"
+#include "asset.h"
 
 typedef struct {
-       const AiScene* sceneData;
-       GLuint* textureIds;
+       const Asset3D* asset3D;
 } PlayerCharacter;
 
 void spawnPlayer();
index 87acb699f18ab8920e1d4ac0fe874ecb486eaf1d..05ab0c1baf19284dc8d05fc15d49538b5b6b9418 100644 (file)
--- a/render.c
+++ b/render.c
@@ -1,8 +1,6 @@
 #include <GL/glut.h>
 #include <stdbool.h>
 
-#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();
index 6b8c632424e5c8b26d2ac15a8c0c3cfe59b17678..e4c46d4cb7a87131108ade05c877f2d0e9d52bb1 100644 (file)
--- a/render.h
+++ b/render.h
@@ -1,8 +1,6 @@
 #ifndef RENDER_H_
 #define RENDER_H_
 
-#include "assimp_types.h"
-
 void initRender();
 void renderScene();
 
index 8343393356479d6e95cb74b7cbe4d13bf37e57e8..8e690ed77e01013b5291c7573984d1ff0bb7781c 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef TYPEDEFS_H_
 #define TYPEDEFS_H_
 
-typedef float point3f[3];
+typedef struct {
+       float x;
+       float y;
+       float z;
+} Vector3D;
 
 #endif