BIG UPDATE: Support model animations!
This commit is contained in:
parent
22dece2935
commit
d89d24c5e8
3 changed files with 383 additions and 50 deletions
|
@ -66,10 +66,10 @@
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Draw rectangle shapes using font texture white character instead of default white texture
|
// Draw rectangle shapes using font texture white character instead of default white texture
|
||||||
// Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
|
// Allows drawing rectangles and text with a single draw call, very useful for GUI systems!
|
||||||
#define SUPPORT_FONT_TEXTURE
|
#define SUPPORT_FONT_TEXTURE 1
|
||||||
// Use QUADS instead of TRIANGLES for drawing when possible
|
// Use QUADS instead of TRIANGLES for drawing when possible
|
||||||
// Some lines-based shapes could still use lines
|
// Some lines-based shapes could still use lines
|
||||||
#define SUPPORT_QUADS_DRAW_MODE
|
#define SUPPORT_QUADS_DRAW_MODE 1
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: textures - Configuration Flags
|
// Module: textures - Configuration Flags
|
||||||
|
@ -114,6 +114,8 @@
|
||||||
// Selected desired model fileformats to be supported for loading
|
// Selected desired model fileformats to be supported for loading
|
||||||
#define SUPPORT_FILEFORMAT_OBJ 1
|
#define SUPPORT_FILEFORMAT_OBJ 1
|
||||||
#define SUPPORT_FILEFORMAT_MTL 1
|
#define SUPPORT_FILEFORMAT_MTL 1
|
||||||
|
#define SUPPORT_FILEFORMAT_IQM 1
|
||||||
|
#define SUPPORT_FILEFORMAT_GLTF 1
|
||||||
// Support procedural mesh generation functions, uses external par_shapes.h library
|
// Support procedural mesh generation functions, uses external par_shapes.h library
|
||||||
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
||||||
#define SUPPORT_MESH_GENERATION 1
|
#define SUPPORT_MESH_GENERATION 1
|
||||||
|
|
382
src/models.c
382
src/models.c
|
@ -57,11 +57,6 @@
|
||||||
#include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
|
#include "external/tinyobj_loader_c.h" // OBJ/MTL file formats loading
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_IQM)
|
|
||||||
#define RIQM_IMPLEMENTATION
|
|
||||||
#include "external/riqm.h" // IQM file format loading
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
||||||
#define CGLTF_IMPLEMENTATION
|
#define CGLTF_IMPLEMENTATION
|
||||||
#include "external/cgltf.h" // glTF file format loading
|
#include "external/cgltf.h" // glTF file format loading
|
||||||
|
@ -629,6 +624,9 @@ Model LoadModel(const char *fileName)
|
||||||
#if defined(SUPPORT_FILEFORMAT_IQM)
|
#if defined(SUPPORT_FILEFORMAT_IQM)
|
||||||
if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
|
if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Make sure model transform is set to identity matrix!
|
||||||
|
model.transform = MatrixIdentity();
|
||||||
|
|
||||||
if (model.meshCount == 0)
|
if (model.meshCount == 0)
|
||||||
{
|
{
|
||||||
|
@ -638,7 +636,12 @@ Model LoadModel(const char *fileName)
|
||||||
model.meshes = (Mesh *)calloc(model.meshCount, sizeof(Mesh));
|
model.meshes = (Mesh *)calloc(model.meshCount, sizeof(Mesh));
|
||||||
model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
|
model.meshes[0] = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Upload vertex data to GPU (static mesh)
|
||||||
|
for (int i = 0; i < model.meshCount; i++) rlLoadMesh(&model.meshes[i], false);
|
||||||
|
}
|
||||||
|
|
||||||
if (model.materialCount == 0)
|
if (model.materialCount == 0)
|
||||||
{
|
{
|
||||||
TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName);
|
TraceLog(LOG_WARNING, "[%s] No materials can be loaded, default to white material", fileName);
|
||||||
|
@ -686,32 +689,14 @@ void UnloadModel(Model model)
|
||||||
free(model.meshes);
|
free(model.meshes);
|
||||||
free(model.materials);
|
free(model.materials);
|
||||||
free(model.meshMaterial);
|
free(model.meshMaterial);
|
||||||
|
|
||||||
|
// Unload animation data
|
||||||
|
free(model.bones);
|
||||||
|
free(model.bindPose);
|
||||||
|
|
||||||
TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
|
TraceLog(LOG_INFO, "Unloaded model data from RAM and VRAM");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load mesh from file
|
|
||||||
// NOTE: Mesh data loaded in CPU and GPU
|
|
||||||
Mesh LoadMesh(const char *fileName)
|
|
||||||
{
|
|
||||||
Mesh mesh = { 0 };
|
|
||||||
|
|
||||||
// TODO: Review this function, should still exist?
|
|
||||||
|
|
||||||
#if defined(SUPPORT_MESH_GENERATION)
|
|
||||||
if (mesh.vertexCount == 0)
|
|
||||||
{
|
|
||||||
TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!");
|
|
||||||
mesh = GenMeshCube(1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
|
|
||||||
#else
|
|
||||||
rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unload mesh from memory (RAM and/or VRAM)
|
// Unload mesh from memory (RAM and/or VRAM)
|
||||||
void UnloadMesh(Mesh *mesh)
|
void UnloadMesh(Mesh *mesh)
|
||||||
{
|
{
|
||||||
|
@ -2386,7 +2371,6 @@ void MeshBinormals(Mesh *mesh)
|
||||||
static Model LoadOBJ(const char *fileName)
|
static Model LoadOBJ(const char *fileName)
|
||||||
{
|
{
|
||||||
Model model = { 0 };
|
Model model = { 0 };
|
||||||
model.transform = MatrixIdentity();
|
|
||||||
|
|
||||||
tinyobj_attrib_t attrib;
|
tinyobj_attrib_t attrib;
|
||||||
tinyobj_shape_t *meshes = NULL;
|
tinyobj_shape_t *meshes = NULL;
|
||||||
|
@ -2486,8 +2470,7 @@ static Model LoadOBJ(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
model.meshes[m] = mesh; // Assign mesh data to model
|
model.meshes[m] = mesh; // Assign mesh data to model
|
||||||
rlLoadMesh(&model.meshes[m], false); // Upload vertex data to GPU (static mesh)
|
|
||||||
|
|
||||||
// Assign mesh material for current mesh
|
// Assign mesh material for current mesh
|
||||||
model.meshMaterial[m] = attrib.material_ids[m];
|
model.meshMaterial[m] = attrib.material_ids[m];
|
||||||
}
|
}
|
||||||
|
@ -2555,13 +2538,336 @@ static Model LoadOBJ(const char *fileName)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
#if defined(SUPPORT_FILEFORMAT_IQM)
|
||||||
// Load IQM mesh data
|
// Load IQM mesh data
|
||||||
static Model LoadIQM(const char *fileName)
|
static Model LoadIQM(const char *fileName)
|
||||||
{
|
{
|
||||||
|
#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
|
||||||
|
#define IQM_VERSION 2 // only IQM version 2 supported
|
||||||
|
|
||||||
|
#define BONE_NAME_LENGTH 32 // BoneInfo name string length
|
||||||
|
#define MESH_NAME_LENGTH 32 // Mesh name string length
|
||||||
|
|
||||||
|
// IQM file structs
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
typedef struct IQMHeader {
|
||||||
|
char magic[16];
|
||||||
|
unsigned int version;
|
||||||
|
unsigned int filesize;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int num_text, ofs_text;
|
||||||
|
unsigned int num_meshes, ofs_meshes;
|
||||||
|
unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
|
||||||
|
unsigned int num_triangles, ofs_triangles, ofs_adjacency;
|
||||||
|
unsigned int num_joints, ofs_joints;
|
||||||
|
unsigned int num_poses, ofs_poses;
|
||||||
|
unsigned int num_anims, ofs_anims;
|
||||||
|
unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
|
||||||
|
unsigned int num_comment, ofs_comment;
|
||||||
|
unsigned int num_extensions, ofs_extensions;
|
||||||
|
} IQMHeader;
|
||||||
|
|
||||||
|
typedef struct IQMMesh {
|
||||||
|
unsigned int name;
|
||||||
|
unsigned int material;
|
||||||
|
unsigned int first_vertex, num_vertexes;
|
||||||
|
unsigned int first_triangle, num_triangles;
|
||||||
|
} IQMMesh;
|
||||||
|
|
||||||
|
typedef struct IQMTriangle {
|
||||||
|
unsigned int vertex[3];
|
||||||
|
} IQMTriangle;
|
||||||
|
|
||||||
|
// NOTE: Adjacency unused by default
|
||||||
|
typedef struct IQMAdjacency {
|
||||||
|
unsigned int triangle[3];
|
||||||
|
} IQMAdjacency;
|
||||||
|
|
||||||
|
typedef struct IQMJoint {
|
||||||
|
unsigned int name;
|
||||||
|
int parent;
|
||||||
|
float translate[3], rotate[4], scale[3];
|
||||||
|
} IQMJoint;
|
||||||
|
|
||||||
|
typedef struct IQMPose {
|
||||||
|
int parent;
|
||||||
|
unsigned int mask;
|
||||||
|
float channeloffset[10];
|
||||||
|
float channelscale[10];
|
||||||
|
} IQMPose;
|
||||||
|
|
||||||
|
typedef struct IQMAnim {
|
||||||
|
unsigned int name;
|
||||||
|
unsigned int first_frame, num_frames;
|
||||||
|
float framerate;
|
||||||
|
unsigned int flags;
|
||||||
|
} IQMAnim;
|
||||||
|
|
||||||
|
typedef struct IQMVertexArray {
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int format;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int offset;
|
||||||
|
} IQMVertexArray;
|
||||||
|
|
||||||
|
// NOTE: Bounds unused by default
|
||||||
|
typedef struct IQMBounds {
|
||||||
|
float bbmin[3], bbmax[3];
|
||||||
|
float xyradius, radius;
|
||||||
|
} IQMBounds;
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// IQM vertex data types
|
||||||
|
typedef enum {
|
||||||
|
IQM_POSITION = 0,
|
||||||
|
IQM_TEXCOORD = 1,
|
||||||
|
IQM_NORMAL = 2,
|
||||||
|
IQM_TANGENT = 3, // NOTE: Tangents unused by default
|
||||||
|
IQM_BLENDINDEXES = 4,
|
||||||
|
IQM_BLENDWEIGHTS = 5,
|
||||||
|
IQM_COLOR = 6, // NOTE: Vertex colors unused by default
|
||||||
|
IQM_CUSTOM = 0x10 // NOTE: Custom vertex values unused by default
|
||||||
|
} IQMVertexType;
|
||||||
|
|
||||||
Model model = { 0 };
|
Model model = { 0 };
|
||||||
|
|
||||||
// TODO: Load IQM file
|
FILE *iqmFile;
|
||||||
|
IQMHeader iqm;
|
||||||
|
|
||||||
|
IQMMesh *imesh;
|
||||||
|
IQMTriangle *tri;
|
||||||
|
IQMVertexArray *va;
|
||||||
|
IQMJoint *ijoint;
|
||||||
|
|
||||||
|
float *vertex = NULL;
|
||||||
|
float *normal = NULL;
|
||||||
|
float *text = NULL;
|
||||||
|
char *blendi = NULL;
|
||||||
|
unsigned char *blendw = NULL;
|
||||||
|
|
||||||
|
iqmFile = fopen(fileName, "rb");
|
||||||
|
|
||||||
|
if (iqmFile == NULL)
|
||||||
|
{
|
||||||
|
TraceLog(LOG_WARNING, "[%s] IQM file could not be opened", fileName);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&iqm,sizeof(IQMHeader), 1, iqmFile); // Read IQM header
|
||||||
|
|
||||||
|
if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
|
||||||
|
{
|
||||||
|
TraceLog(LOG_WARNING, "[%s] IQM file does not seem to be valid", fileName);
|
||||||
|
fclose(iqmFile);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iqm.version != IQM_VERSION)
|
||||||
|
{
|
||||||
|
TraceLog(LOG_WARNING, "[%s] IQM file version is not supported (%i).", fileName, iqm.version);
|
||||||
|
fclose(iqmFile);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meshes data processing
|
||||||
|
imesh = malloc(sizeof(IQMMesh)*iqm.num_meshes);
|
||||||
|
fseek(iqmFile, iqm.ofs_meshes, SEEK_SET);
|
||||||
|
fread(imesh, sizeof(IQMMesh)*iqm.num_meshes, 1, iqmFile);
|
||||||
|
|
||||||
|
model.meshCount = iqm.num_meshes;
|
||||||
|
model.meshes = malloc(sizeof(Mesh)*iqm.num_meshes);
|
||||||
|
|
||||||
|
char name[MESH_NAME_LENGTH];
|
||||||
|
|
||||||
|
for (int i = 0; i < iqm.num_meshes; i++)
|
||||||
|
{
|
||||||
|
fseek(iqmFile,iqm.ofs_text+imesh[i].name,SEEK_SET);
|
||||||
|
fread(name, sizeof(char)*MESH_NAME_LENGTH, 1, iqmFile); // Mesh name not used...
|
||||||
|
model.meshes[i].vertexCount = imesh[i].num_vertexes;
|
||||||
|
|
||||||
|
model.meshes[i].vertices = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default vertex positions
|
||||||
|
model.meshes[i].normals = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default vertex normals
|
||||||
|
model.meshes[i].texcoords = malloc(sizeof(float)*imesh[i].num_vertexes*2); // Default vertex texcoords
|
||||||
|
|
||||||
|
model.meshes[i].boneIds = malloc(sizeof(int)*imesh[i].num_vertexes*4); // Up-to 4 bones supported!
|
||||||
|
model.meshes[i].boneWeights = malloc(sizeof(float)*imesh[i].num_vertexes*4); // Up-to 4 bones supported!
|
||||||
|
|
||||||
|
model.meshes[i].triangleCount = imesh[i].num_triangles;
|
||||||
|
model.meshes[i].indices = malloc(sizeof(unsigned short)*imesh[i].num_triangles*3);
|
||||||
|
|
||||||
|
// Animated verted data, what we actually process for rendering
|
||||||
|
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
||||||
|
model.meshes[i].animVertices = malloc(sizeof(float)*imesh[i].num_vertexes*3);
|
||||||
|
model.meshes[i].animNormals = malloc(sizeof(float)*imesh[i].num_vertexes*3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangles data processing
|
||||||
|
tri = malloc(sizeof(IQMTriangle)*iqm.num_triangles);
|
||||||
|
fseek(iqmFile, iqm.ofs_triangles, SEEK_SET);
|
||||||
|
fread(tri, sizeof(IQMTriangle)*iqm.num_triangles, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int tcounter = 0;
|
||||||
|
|
||||||
|
for (int i = imesh[m].first_triangle; i < imesh[m].first_triangle+imesh[m].num_triangles; i++)
|
||||||
|
{
|
||||||
|
// IQM triangles are stored counter clockwise, but raylib sets opengl to clockwise drawing, so we swap them around
|
||||||
|
model.meshes[m].indices[tcounter+2] = tri[i].vertex[0] - imesh[m].first_vertex;
|
||||||
|
model.meshes[m].indices[tcounter+1] = tri[i].vertex[1] - imesh[m].first_vertex;
|
||||||
|
model.meshes[m].indices[tcounter] = tri[i].vertex[2] - imesh[m].first_vertex;
|
||||||
|
tcounter += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex arrays data processing
|
||||||
|
va = malloc(sizeof(IQMVertexArray)*iqm.num_vertexarrays);
|
||||||
|
fseek(iqmFile, iqm.ofs_vertexarrays, SEEK_SET);
|
||||||
|
fread(va, sizeof(IQMVertexArray)*iqm.num_vertexarrays, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int i = 0; i < iqm.num_vertexarrays; i++)
|
||||||
|
{
|
||||||
|
switch (va[i].type)
|
||||||
|
{
|
||||||
|
case IQM_POSITION:
|
||||||
|
{
|
||||||
|
vertex = malloc(sizeof(float)*iqm.num_vertexes*3);
|
||||||
|
fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
|
fread(vertex, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int vCounter = 0;
|
||||||
|
for (int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].vertices[vCounter] = vertex[i];
|
||||||
|
model.meshes[m].animVertices[vCounter] = vertex[i];
|
||||||
|
vCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IQM_NORMAL:
|
||||||
|
{
|
||||||
|
normal = malloc(sizeof(float)*iqm.num_vertexes*3);
|
||||||
|
fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
|
fread(normal, sizeof(float)*iqm.num_vertexes*3, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int vCounter = 0;
|
||||||
|
for (int i = imesh[m].first_vertex*3; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*3; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].normals[vCounter] = normal[i];
|
||||||
|
model.meshes[m].animNormals[vCounter] = normal[i];
|
||||||
|
vCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IQM_TEXCOORD:
|
||||||
|
{
|
||||||
|
text = malloc(sizeof(float)*iqm.num_vertexes*2);
|
||||||
|
fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
|
fread(text, sizeof(float)*iqm.num_vertexes*2, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int vCounter = 0;
|
||||||
|
for (int i = imesh[m].first_vertex*2; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*2; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].texcoords[vCounter] = text[i];
|
||||||
|
vCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IQM_BLENDINDEXES:
|
||||||
|
{
|
||||||
|
blendi = malloc(sizeof(char)*iqm.num_vertexes*4);
|
||||||
|
fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
|
fread(blendi, sizeof(char)*iqm.num_vertexes*4, 1, iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int boneCounter = 0;
|
||||||
|
for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].boneIds[boneCounter] = blendi[i];
|
||||||
|
boneCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case IQM_BLENDWEIGHTS:
|
||||||
|
{
|
||||||
|
blendw = malloc(sizeof(unsigned char)*iqm.num_vertexes*4);
|
||||||
|
fseek(iqmFile,va[i].offset,SEEK_SET);
|
||||||
|
fread(blendw,sizeof(unsigned char)*iqm.num_vertexes*4,1,iqmFile);
|
||||||
|
|
||||||
|
for (int m = 0; m < iqm.num_meshes; m++)
|
||||||
|
{
|
||||||
|
int boneCounter = 0;
|
||||||
|
for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||||
|
{
|
||||||
|
model.meshes[m].boneWeights[boneCounter] = blendw[i]/255.0f;
|
||||||
|
boneCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bones (joints) data processing
|
||||||
|
ijoint = malloc(sizeof(IQMJoint)*iqm.num_joints);
|
||||||
|
fseek(iqmFile, iqm.ofs_joints, SEEK_SET);
|
||||||
|
fread(ijoint, sizeof(IQMJoint)*iqm.num_joints, 1, iqmFile);
|
||||||
|
|
||||||
|
model.boneCount = iqm.num_joints;
|
||||||
|
model.bones = malloc(sizeof(BoneInfo)*iqm.num_joints);
|
||||||
|
model.bindPose = malloc(sizeof(Transform)*iqm.num_joints);
|
||||||
|
|
||||||
|
for (int i = 0; i < iqm.num_joints; i++)
|
||||||
|
{
|
||||||
|
// Bones
|
||||||
|
model.bones[i].parent = ijoint[i].parent;
|
||||||
|
fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET);
|
||||||
|
fread(model.bones[i].name,sizeof(char)*BONE_NAME_LENGTH, 1, iqmFile);
|
||||||
|
|
||||||
|
// Bind pose (base pose)
|
||||||
|
model.bindPose[i].translation.x = ijoint[i].translate[0];
|
||||||
|
model.bindPose[i].translation.y = ijoint[i].translate[1];
|
||||||
|
model.bindPose[i].translation.z = ijoint[i].translate[2];
|
||||||
|
|
||||||
|
model.bindPose[i].rotation.x = ijoint[i].rotate[0];
|
||||||
|
model.bindPose[i].rotation.y = ijoint[i].rotate[1];
|
||||||
|
model.bindPose[i].rotation.z = ijoint[i].rotate[2];
|
||||||
|
model.bindPose[i].rotation.w = ijoint[i].rotate[3];
|
||||||
|
|
||||||
|
model.bindPose[i].scale.x = ijoint[i].scale[0];
|
||||||
|
model.bindPose[i].scale.y = ijoint[i].scale[1];
|
||||||
|
model.bindPose[i].scale.z = ijoint[i].scale[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build bind pose from parent joints
|
||||||
|
for (int i = 0; i < model.boneCount; i++)
|
||||||
|
{
|
||||||
|
if (model.bones[i].parent >= 0)
|
||||||
|
{
|
||||||
|
model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
|
||||||
|
model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
|
||||||
|
model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
|
||||||
|
model.bindPose[i].scale = Vector3MultiplyV(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(iqmFile);
|
||||||
|
free(imesh);
|
||||||
|
free(tri);
|
||||||
|
free(va);
|
||||||
|
free(vertex);
|
||||||
|
free(normal);
|
||||||
|
free(text);
|
||||||
|
free(blendi);
|
||||||
|
free(blendw);
|
||||||
|
free(ijoint);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
@ -2593,23 +2899,23 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
// glTF data loading
|
// glTF data loading
|
||||||
cgltf_options options = {0};
|
cgltf_options options = {0};
|
||||||
cgltf_data data;
|
cgltf_data *data;
|
||||||
cgltf_result result = cgltf_parse(&options, buffer, size, &data);
|
cgltf_result result = cgltf_parse(&options, buffer, size, &data);
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
if (result == cgltf_result_success)
|
if (result == cgltf_result_success)
|
||||||
{
|
{
|
||||||
printf("Type: %u\n", data.file_type);
|
// printf("Type: %u\n", data.file_type);
|
||||||
printf("Version: %d\n", data.version);
|
// printf("Version: %d\n", data.version);
|
||||||
printf("Meshes: %lu\n", data.meshes_count);
|
// printf("Meshes: %lu\n", data.meshes_count);
|
||||||
|
|
||||||
// TODO: Process glTF data and map to model
|
// TODO: Process glTF data and map to model
|
||||||
|
|
||||||
// NOTE: data.buffers[] should be loaded to model.meshes and data.images[] should be loaded to model.materials
|
// NOTE: data.buffers[] should be loaded to model.meshes and data.images[] should be loaded to model.materials
|
||||||
// Use buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName);
|
// Use buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName);
|
||||||
|
|
||||||
cgltf_free(&data);
|
cgltf_free(data);
|
||||||
}
|
}
|
||||||
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
|
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
|
||||||
|
|
||||||
|
|
45
src/raylib.h
45
src/raylib.h
|
@ -307,10 +307,10 @@ typedef struct Mesh {
|
||||||
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
|
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
|
||||||
|
|
||||||
// Animation vertex data
|
// Animation vertex data
|
||||||
float *baseVertices; // Vertex base position (required to apply bones transformations)
|
float *animVertices; // Animated vertex positions (after bones transformations)
|
||||||
float *baseNormals; // Vertex base normals (required to apply bones transformations)
|
float *animNormals; // Animated normals (after bones transformations)
|
||||||
float *weightBias; // Vertex weight bias
|
int *boneIds; // Vertex bone ids, up to 4 bones influence by vertex (skinning)
|
||||||
int *weightId; // Vertex weight id
|
float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
|
||||||
|
|
||||||
// OpenGL identifiers
|
// OpenGL identifiers
|
||||||
unsigned int vaoId; // OpenGL Vertex Array Object id
|
unsigned int vaoId; // OpenGL Vertex Array Object id
|
||||||
|
@ -337,6 +337,19 @@ typedef struct Material {
|
||||||
float *params; // Material generic parameters (if required)
|
float *params; // Material generic parameters (if required)
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
|
// Transformation properties
|
||||||
|
typedef struct Transform {
|
||||||
|
Vector3 translation; // Translation
|
||||||
|
Quaternion rotation; // Rotation
|
||||||
|
Vector3 scale; // Scale
|
||||||
|
} Transform;
|
||||||
|
|
||||||
|
// Bone information
|
||||||
|
typedef struct BoneInfo {
|
||||||
|
char name[32]; // Bone name
|
||||||
|
int parent; // Bone parent
|
||||||
|
} BoneInfo;
|
||||||
|
|
||||||
// Model type
|
// Model type
|
||||||
typedef struct Model {
|
typedef struct Model {
|
||||||
Matrix transform; // Local transform matrix
|
Matrix transform; // Local transform matrix
|
||||||
|
@ -346,10 +359,23 @@ typedef struct Model {
|
||||||
|
|
||||||
int materialCount; // Number of materials
|
int materialCount; // Number of materials
|
||||||
Material *materials; // Materials array
|
Material *materials; // Materials array
|
||||||
|
|
||||||
int *meshMaterial; // Mesh material number
|
int *meshMaterial; // Mesh material number
|
||||||
|
|
||||||
|
// Animation data
|
||||||
|
int boneCount; // Number of bones
|
||||||
|
BoneInfo *bones; // Bones information (skeleton)
|
||||||
|
Transform *bindPose; // Bones base transformation (pose)
|
||||||
} Model;
|
} Model;
|
||||||
|
|
||||||
|
// Model animation
|
||||||
|
typedef struct ModelAnimation {
|
||||||
|
int boneCount; // Number of bones
|
||||||
|
BoneInfo *bones; // Bones information (skeleton)
|
||||||
|
|
||||||
|
int frameCount; // Number of animation frames
|
||||||
|
Transform **framePoses; // Poses array by frame
|
||||||
|
} ModelAnimation;
|
||||||
|
|
||||||
// Ray type (useful for raycast)
|
// Ray type (useful for raycast)
|
||||||
typedef struct Ray {
|
typedef struct Ray {
|
||||||
Vector3 position; // Ray position (origin)
|
Vector3 position; // Ray position (origin)
|
||||||
|
@ -1228,17 +1254,16 @@ RLAPI void DrawGizmo(Vector3 position);
|
||||||
// Model loading/unloading functions
|
// Model loading/unloading functions
|
||||||
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
|
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
|
||||||
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh
|
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh
|
||||||
|
//RLAPI void LoadModelAnimations(const char fileName, ModelAnimation *anims, int *animsCount); // Load model animations from file
|
||||||
|
//RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose
|
||||||
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
|
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
|
||||||
|
|
||||||
// Mesh loading/unloading functions
|
|
||||||
RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
|
|
||||||
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
|
|
||||||
RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
|
|
||||||
|
|
||||||
// Mesh manipulation functions
|
// Mesh manipulation functions
|
||||||
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
||||||
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
||||||
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
||||||
|
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
|
||||||
|
RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file
|
||||||
|
|
||||||
// Mesh generation functions
|
// Mesh generation functions
|
||||||
RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh
|
RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue