aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2019-04-05 13:15:56 +0200
committerRay <raysan5@gmail.com>2019-04-05 13:15:56 +0200
commit92733d6695e0cdab3b42972f2cd6ed48d98ec689 (patch)
tree2b46d7f3c026b62166fea4e5ca039d1a9391fbcd /examples
parent38a13b76d13c6e4f6f6c02bfd63900de56de4a42 (diff)
downloadraylib-92733d6695e0cdab3b42972f2cd6ed48d98ec689.tar.gz
raylib-92733d6695e0cdab3b42972f2cd6ed48d98ec689.zip
BIG UPDATE: New models functions for animations!
Multiple functions added and some reviewed to adapt to the new multi-mesh, multi-material and animated models.
Diffstat (limited to 'examples')
-rw-r--r--examples/models/models_animation.c (renamed from examples/others/iqm_loader/models_iqm_animation.c)51
-rw-r--r--examples/models/resources/guy/guy.blend (renamed from examples/others/iqm_loader/resources/guy.blend)bin665304 -> 665304 bytes
-rw-r--r--examples/models/resources/guy/guy.iqm (renamed from examples/others/iqm_loader/resources/guy.iqm)bin39408 -> 39408 bytes
-rw-r--r--examples/models/resources/guy/guyanim.iqm (renamed from examples/others/iqm_loader/resources/guyanim.iqm)bin18244 -> 18244 bytes
-rw-r--r--examples/models/resources/guy/guytex.png (renamed from examples/others/iqm_loader/resources/guytex.png)bin302388 -> 302388 bytes
-rw-r--r--examples/others/iqm_loader/riqm.h739
6 files changed, 29 insertions, 761 deletions
diff --git a/examples/others/iqm_loader/models_iqm_animation.c b/examples/models/models_animation.c
index 18dd8577..a75241b3 100644
--- a/examples/others/iqm_loader/models_iqm_animation.c
+++ b/examples/models/models_animation.c
@@ -1,19 +1,16 @@
/*******************************************************************************************
*
-* raylib [models] example - Load IQM 3d model with animations and play them
+* raylib [models] example - Load 3d model with animations and play them
*
-* This example has been created using raylib 2.0 (www.raylib.com)
+* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
-* Copyright (c) 2018 @culacant and @raysan5
+* Copyright (c) 2019 Ramon Santamaria (@raysan5) and @culacant
*
********************************************************************************************/
#include "raylib.h"
-#define RIQM_IMPLEMENTATION
-#include "riqm.h"
-
int main()
{
// Initialization
@@ -21,7 +18,7 @@ int main()
int screenWidth = 800;
int screenHeight = 450;
- InitWindow(screenWidth, screenHeight, "raylib [models] example - iqm animation");
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation");
// Define the camera to look into our 3d world
Camera camera = { 0 };
@@ -31,26 +28,25 @@ int main()
camera.fovy = 45.0f; // Camera field-of-view Y
camera.type = CAMERA_PERSPECTIVE; // Camera mode type
- // Load the animated model mesh and basic data
- AnimatedModel model = LoadAnimatedModel("resources/guy.iqm");
- // Load model texture and set material
- // NOTE: There is only 1 mesh and 1 material (both at index 0), thats what the 2 0's are
- model = AnimatedModelAddTexture(model, "resources/guytex.png"); // REPLACE!
- model = SetMeshMaterial(model, 0, 0); // REPLACE!
+ Model model = LoadModel("resources/guy/guy.iqm"); // Load the animated model mesh and basic data
+ Texture2D texture = LoadTexture("resources/guy/guytex.png"); // Load model texture and set material
+ SetMaterialTexture(&model.materials[0], MAP_DIFFUSE, texture); // Set model material map texture
+
+ Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
// Load animation data
- Animation anim = LoadAnimationFromIQM("resources/guyanim.iqm");
-
+ int animsCount = 0;
+ ModelAnimation *anims = LoadModelAnimations("resources/guy/guyanim.iqm", &animsCount);
int animFrameCounter = 0;
- SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
+ SetCameraMode(camera, CAMERA_FREE); // Set free camera mode
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
- while (!WindowShouldClose()) // Detect window close button or ESC key
+ while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
@@ -60,7 +56,8 @@ int main()
if (IsKeyDown(KEY_SPACE))
{
animFrameCounter++;
- AnimateModel(model, anim, animFrameCounter); // Animate the model with animation data and frame
+ UpdateModelAnimation(model, anims[0], animFrameCounter);
+ if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0;
}
//----------------------------------------------------------------------------------
@@ -72,14 +69,18 @@ int main()
BeginMode3D(camera);
- DrawAnimatedModel(model, Vector3Zero(), 1.0f, WHITE); // Draw animated model
+ DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
+
+ for (int i = 0; i < model.boneCount; i++)
+ {
+ DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED);
+ }
DrawGrid(10, 1.0f); // Draw a grid
EndMode3D();
-
- DrawText("PRESS SPACE to PLAY IQM MODEL ANIMATION", 10, 10, 20, MAROON);
+ DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON);
DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY);
EndDrawing();
@@ -88,8 +89,10 @@ int main()
// De-Initialization
//--------------------------------------------------------------------------------------
- UnloadAnimation(anim); // Unload animation data
- UnloadAnimatedModel(model); // Unload animated model
+ // Unload model animations data
+ for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]);
+
+ UnloadModel(model); // Unload model
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/others/iqm_loader/resources/guy.blend b/examples/models/resources/guy/guy.blend
index 3880467d..3880467d 100644
--- a/examples/others/iqm_loader/resources/guy.blend
+++ b/examples/models/resources/guy/guy.blend
Binary files differ
diff --git a/examples/others/iqm_loader/resources/guy.iqm b/examples/models/resources/guy/guy.iqm
index 36bed5e0..36bed5e0 100644
--- a/examples/others/iqm_loader/resources/guy.iqm
+++ b/examples/models/resources/guy/guy.iqm
Binary files differ
diff --git a/examples/others/iqm_loader/resources/guyanim.iqm b/examples/models/resources/guy/guyanim.iqm
index 824a68a3..824a68a3 100644
--- a/examples/others/iqm_loader/resources/guyanim.iqm
+++ b/examples/models/resources/guy/guyanim.iqm
Binary files differ
diff --git a/examples/others/iqm_loader/resources/guytex.png b/examples/models/resources/guy/guytex.png
index 7f813552..7f813552 100644
--- a/examples/others/iqm_loader/resources/guytex.png
+++ b/examples/models/resources/guy/guytex.png
Binary files differ
diff --git a/examples/others/iqm_loader/riqm.h b/examples/others/iqm_loader/riqm.h
index 694e3a95..41ef8a14 100644
--- a/examples/others/iqm_loader/riqm.h
+++ b/examples/others/iqm_loader/riqm.h
@@ -49,67 +49,13 @@
// Types and Structures Definition
//----------------------------------------------------------------------------------
-#define JOINT_NAME_LENGTH 32 // Joint name string length
-#define MESH_NAME_LENGTH 32 // Mesh name string length
-
-typedef struct Joint {
- char name[JOINT_NAME_LENGTH];
- int parent;
-} Joint;
-
-typedef struct Pose {
- Vector3 translation;
- Quaternion rotation;
- Vector3 scale;
-} Pose;
-
-typedef struct Animation {
- int jointCount; // Number of joints (bones)
- Joint *joints; // Joints array
- // NOTE: Joints in anims do not have names
-
- int frameCount; // Number of animation frames
- float framerate; // Frame change speed
-
- Pose **framepose; // Poses array by frame (and one pose by joint)
-} Animation;
-
-// Animated Model type
-typedef struct AnimatedModel {
- Matrix transform; // Local transform matrix
-
- int meshCount; // Number of meshes
- Mesh *meshes; // Meshes array
-
- int materialCount; // Number of materials
- Material *materials; // Materials array
-
- int *meshMaterialId; // Mesh materials ids
-
- // Animation required data
- int jointCount; // Number of joints (and keyposes)
- Joint *joints; // Mesh joints (bones)
- Pose *basepose; // Mesh base-poses by joint
-} AnimatedModel;
+#define BONE_NAME_LENGTH 32 // BoneInfo name string length
+#define MESH_NAME_LENGTH 32 // Mesh name string length
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
-// Loading/Unloading functions
-RIQMDEF AnimatedModel LoadAnimatedModel(const char *filename);
-RIQMDEF void UnloadAnimatedModel(AnimatedModel model);
-RIQMDEF Animation LoadAnimation(const char *filename);
-RIQMDEF void UnloadAnimation(Animation anim);
-
-RIQMDEF AnimatedModel AnimatedModelAddTexture(AnimatedModel model, const char *filename); // GENERIC!
-RIQMDEF AnimatedModel SetMeshMaterial(AnimatedModel model, int meshid, int textureid); // GENERIC!
-
-// Usage functionality
-RIQMDEF bool CheckSkeletonsMatch(AnimatedModel model, Animation anim);
-RIQMDEF void AnimateModel(AnimatedModel model, Animation anim, int frame);
-RIQMDEF void DrawAnimatedModel(AnimatedModel model, Vector3 position, float scale, Color tint);
-RIQMDEF void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint);
#endif // RIQM_H
@@ -133,90 +79,6 @@ RIQMDEF void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
-#define IQM_VERSION 2 // only IQM version 2 supported
-#define ANIMJOINTNAME "ANIMJOINT" // default joint name (used in Animation)
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// 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;
-
-typedef struct IQMAdjacency { // adjacency unused by default
- 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;
-
-typedef struct IQMBounds { // bounds unused by default
- float bbmin[3], bbmax[3];
- float xyradius, radius;
-} IQMBounds;
-
-
-typedef enum {
- IQM_POSITION = 0,
- IQM_TEXCOORD = 1,
- IQM_NORMAL = 2,
- IQM_TANGENT = 3, // tangents unused by default
- IQM_BLENDINDEXES = 4,
- IQM_BLENDWEIGHTS = 5,
- IQM_COLOR = 6, // vertex colors unused by default
- IQM_CUSTOM = 0x10 // custom vertex values unused by default
-} IQMVertexType;
//----------------------------------------------------------------------------------
// Global Variables Definition
@@ -225,609 +87,12 @@ typedef enum {
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
-static AnimatedModel LoadIQM(const char *filename);
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
-// Load .iqm file and initialize animated model
-AnimatedModel LoadAnimatedModel(const char *filename)
-{
- AnimatedModel out = LoadIQM(filename);
-
- for (int i = 0; i < out.meshCount; i++) rlLoadMesh(&out.meshes[i], false);
-
- out.transform = MatrixIdentity();
- out.meshMaterialId = malloc(sizeof(int)*out.meshCount);
- out.materials = NULL;
- out.materialCount = 0;
-
- for (int i = 0; i < out.meshCount; i++) out.meshMaterialId[i] = -1;
-
- return out;
-}
-
-// Add a texture to an animated model
-AnimatedModel AnimatedModelAddTexture(AnimatedModel model, const char *filename)
-{
- Texture2D texture = LoadTexture(filename);
-
- model.materials = realloc(model.materials, sizeof(Material)*(model.materialCount + 1));
- model.materials[model.materialCount] = LoadMaterialDefault();
- model.materials[model.materialCount].maps[MAP_DIFFUSE].texture = texture;
- model.materialCount++;
-
- return model;
-}
-
-// Set the material for a meshes
-AnimatedModel SetMeshMaterial(AnimatedModel model, int meshid, int textureid)
-{
- if (meshid > model.meshCount)
- {
- TraceLog(LOG_WARNING, "MeshId greater than meshCount\n");
- return model;
- }
-
- if (textureid > model.materialCount)
- {
- TraceLog(LOG_WARNING,"textureid greater than materialCount\n");
- return model;
- }
-
- model.meshMaterialId[meshid] = textureid;
-
- return model;
-}
-
-// Load animations from a .iqm file
-Animation LoadAnimationFromIQM(const char *filename)
-{
- Animation animation = { 0 };
-
- FILE *iqmFile;
- IQMHeader iqm;
-
- iqmFile = fopen(filename,"rb");
-
- if (!iqmFile)
- {
- TraceLog(LOG_ERROR, "[%s] Unable to open file", filename);
- return animation;
- }
-
- // header
- fread(&iqm, sizeof(IQMHeader), 1, iqmFile);
-
- if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
- {
- TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic);
- fclose(iqmFile);
- return animation;
- }
-
- if (iqm.version != IQM_VERSION)
- {
- TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version);
- fclose(iqmFile);
- return animation;
- }
-
- // header
- if (iqm.num_anims > 1) TraceLog(LOG_WARNING, "More than 1 animation in file, only the first one will get loaded");
-
- // joints
- IQMPose *poses;
- poses = malloc(sizeof(IQMPose)*iqm.num_poses);
- fseek(iqmFile, iqm.ofs_poses, SEEK_SET);
- fread(poses, sizeof(IQMPose)*iqm.num_poses, 1, iqmFile);
-
- animation.jointCount = iqm.num_poses;
- animation.joints = malloc(sizeof(Joint)*iqm.num_poses);
-
- for (int j = 0; j < iqm.num_poses; j++)
- {
- strcpy(animation.joints[j].name, ANIMJOINTNAME);
- animation.joints[j].parent = poses[j].parent;
- }
-
- // animations
- IQMAnim anim = {0};
- fseek(iqmFile, iqm.ofs_anims, SEEK_SET);
- fread(&anim, sizeof(IQMAnim), 1, iqmFile);
-
- animation.frameCount = anim.num_frames;
- animation.framerate = anim.framerate;
-
- // frameposes
- unsigned short *framedata = malloc(sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels);
- fseek(iqmFile, iqm.ofs_frames, SEEK_SET);
- fread(framedata, sizeof(unsigned short)*iqm.num_frames*iqm.num_framechannels, 1, iqmFile);
-
- animation.framepose = malloc(sizeof(Pose*)*anim.num_frames);
- for (int j = 0; j < anim.num_frames; j++) animation.framepose[j] = malloc(sizeof(Pose)*iqm.num_poses);
-
- int dcounter = anim.first_frame*iqm.num_framechannels;
-
- for (int frame = 0; frame < anim.num_frames; frame++)
- {
- for (int i = 0; i < iqm.num_poses; i++)
- {
- animation.framepose[frame][i].translation.x = poses[i].channeloffset[0];
-
- if (poses[i].mask & 0x01)
- {
- animation.framepose[frame][i].translation.x += framedata[dcounter]*poses[i].channelscale[0];
- dcounter++;
- }
-
- animation.framepose[frame][i].translation.y = poses[i].channeloffset[1];
-
- if (poses[i].mask & 0x02)
- {
- animation.framepose[frame][i].translation.y += framedata[dcounter]*poses[i].channelscale[1];
- dcounter++;
- }
-
- animation.framepose[frame][i].translation.z = poses[i].channeloffset[2];
-
- if (poses[i].mask & 0x04)
- {
- animation.framepose[frame][i].translation.z += framedata[dcounter]*poses[i].channelscale[2];
- dcounter++;
- }
-
- animation.framepose[frame][i].rotation.x = poses[i].channeloffset[3];
-
- if (poses[i].mask & 0x08)
- {
- animation.framepose[frame][i].rotation.x += framedata[dcounter]*poses[i].channelscale[3];
- dcounter++;
- }
-
- animation.framepose[frame][i].rotation.y = poses[i].channeloffset[4];
-
- if (poses[i].mask & 0x10)
- {
- animation.framepose[frame][i].rotation.y += framedata[dcounter]*poses[i].channelscale[4];
- dcounter++;
- }
-
- animation.framepose[frame][i].rotation.z = poses[i].channeloffset[5];
-
- if (poses[i].mask & 0x20)
- {
- animation.framepose[frame][i].rotation.z += framedata[dcounter]*poses[i].channelscale[5];
- dcounter++;
- }
-
- animation.framepose[frame][i].rotation.w = poses[i].channeloffset[6];
-
- if (poses[i].mask & 0x40)
- {
- animation.framepose[frame][i].rotation.w += framedata[dcounter]*poses[i].channelscale[6];
- dcounter++;
- }
-
- animation.framepose[frame][i].scale.x = poses[i].channeloffset[7];
-
- if (poses[i].mask & 0x80)
- {
- animation.framepose[frame][i].scale.x += framedata[dcounter]*poses[i].channelscale[7];
- dcounter++;
- }
-
- animation.framepose[frame][i].scale.y = poses[i].channeloffset[8];
-
- if (poses[i].mask & 0x100)
- {
- animation.framepose[frame][i].scale.y += framedata[dcounter]*poses[i].channelscale[8];
- dcounter++;
- }
-
- animation.framepose[frame][i].scale.z = poses[i].channeloffset[9];
-
- if (poses[i].mask & 0x200)
- {
- animation.framepose[frame][i].scale.z += framedata[dcounter]*poses[i].channelscale[9];
- dcounter++;
- }
-
- animation.framepose[frame][i].rotation = QuaternionNormalize(animation.framepose[frame][i].rotation);
- }
- }
-
- // Build frameposes
- for (int frame = 0; frame < anim.num_frames; frame++)
- {
- for (int i = 0; i < animation.jointCount; i++)
- {
- if (animation.joints[i].parent >= 0)
- {
- animation.framepose[frame][i].rotation = QuaternionMultiply(animation.framepose[frame][animation.joints[i].parent].rotation, animation.framepose[frame][i].rotation);
- animation.framepose[frame][i].translation = Vector3RotateByQuaternion(animation.framepose[frame][i].translation, animation.framepose[frame][animation.joints[i].parent].rotation);
- animation.framepose[frame][i].translation = Vector3Add(animation.framepose[frame][i].translation, animation.framepose[frame][animation.joints[i].parent].translation);
- animation.framepose[frame][i].scale = Vector3MultiplyV(animation.framepose[frame][i].scale, animation.framepose[frame][animation.joints[i].parent].scale);
- }
- }
- }
-
- free(framedata);
- free(poses);
-
- fclose(iqmFile);
-
- return animation;
-}
-
-// Unload animated model
-void UnloadAnimatedModel(AnimatedModel model)
-{
- free(model.materials);
- free(model.meshMaterialId);
- free(model.joints);
- free(model.basepose);
-
- for (int i = 0; i < model.meshCount; i++) rlUnloadMesh(&model.meshes[i]);
-
- free(model.meshes);
-}
-
-// Unload animation
-void UnloadAnimation(Animation anim)
-{
- free(anim.joints);
- free(anim.framepose);
-
- for (int i = 0; i < anim.frameCount; i++) free(anim.framepose[i]);
-}
-
-// Check if skeletons match, only parents and jointCount are checked
-bool CheckSkeletonsMatch(AnimatedModel model, Animation anim)
-{
- if (model.jointCount != anim.jointCount) return 0;
-
- for (int i = 0; i < model.jointCount; i++)
- {
- if (model.joints[i].parent != anim.joints[i].parent) return 0;
- }
-
- return 1;
-}
-
-// Calculate the animated vertex positions and normals based on an animation at a given frame
-void AnimateModel(AnimatedModel model, Animation anim, int frame)
-{
- if (frame >= anim.frameCount) frame = frame%anim.frameCount;
-
- for (int m = 0; m < model.meshCount; m++)
- {
- Vector3 outv = {0};
- Vector3 outn = {0};
-
- Vector3 baset = {0};
- Quaternion baser = {0};
- Vector3 bases = {0};
-
- Vector3 outt = {0};
- Quaternion outr = {0};
- Vector3 outs = {0};
-
- int vcounter = 0;
- int wcounter = 0;
- int weightId = 0;
-
- for (int i = 0; i < model.meshes[m].vertexCount; i++)
- {
- weightId = model.meshes[m].weightId[wcounter];
- baset = model.basepose[weightId].translation;
- baser = model.basepose[weightId].rotation;
- bases = model.basepose[weightId].scale;
- outt = anim.framepose[frame][weightId].translation;
- outr = anim.framepose[frame][weightId].rotation;
- outs = anim.framepose[frame][weightId].scale;
-
- // vertices
- // NOTE: We use meshes.baseVertices (default position) to calculate meshes.vertices (animated position)
- outv = (Vector3){ model.meshes[m].baseVertices[vcounter], model.meshes[m].baseVertices[vcounter + 1], model.meshes[m].baseVertices[vcounter + 2] };
- outv = Vector3MultiplyV(outv, outs);
- outv = Vector3Subtract(outv, baset);
- outv = Vector3RotateByQuaternion(outv, QuaternionMultiply(outr, QuaternionInvert(baser)));
- outv = Vector3Add(outv, outt);
- model.meshes[m].vertices[vcounter] = outv.x;
- model.meshes[m].vertices[vcounter + 1] = outv.y;
- model.meshes[m].vertices[vcounter + 2] = outv.z;
-
- // normals
- // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
- outn = (Vector3){ model.meshes[m].baseNormals[vcounter], model.meshes[m].baseNormals[vcounter + 1], model.meshes[m].baseNormals[vcounter + 2] };
- outn = Vector3RotateByQuaternion(outn, QuaternionMultiply(outr, QuaternionInvert(baser)));
- model.meshes[m].normals[vcounter] = outn.x;
- model.meshes[m].normals[vcounter + 1] = outn.y;
- model.meshes[m].normals[vcounter + 2] = outn.z;
- vcounter += 3;
- wcounter += 4;
- }
- }
-}
-
-// Draw an animated model
-void DrawAnimatedModel(AnimatedModel model, Vector3 position, float scale, Color tint)
-{
- Vector3 vScale = { scale, scale, scale };
- Vector3 rotationAxis = { 1.0f, 0.0f,0.0f };
-
- DrawAnimatedModelEx(model, position, rotationAxis, -90.0f, vScale, tint);
-}
-
-// Draw an animated model with extended parameters
-void DrawAnimatedModelEx(AnimatedModel model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
-{
- if (model.materialCount == 0)
- {
- TraceLog(LOG_WARNING,"No materials set, can't draw animated meshes\n");
- return;
- }
-
- Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
- Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
- Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
-
- Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
- model.transform = MatrixMultiply(model.transform, matTransform);
-
- for (int i = 0; i < model.meshCount; i++)
- {
- rlUpdateMesh(model.meshes[i], 0, model.meshes[i].vertexCount); // Update vertex position
- rlUpdateMesh(model.meshes[i], 2, model.meshes[i].vertexCount); // Update vertex normals
- rlDrawMesh(model.meshes[i], model.materials[model.meshMaterialId[i]], model.transform); // Draw meshes
- }
-}
-
-// Load animated model meshes from IQM file
-static AnimatedModel LoadIQM(const char *filename)
-{
- AnimatedModel model = { 0 };
-
- FILE *iqmFile;
- IQMHeader iqm;
-
- IQMMesh *imesh;
- IQMTriangle *tri;
- IQMVertexArray *va;
- IQMJoint *ijoint;
-
- float *vertex;
- float *normal;
- float *text;
- char *blendi;
- unsigned char *blendw;
-
- iqmFile = fopen(filename, "rb");
-
- if (!iqmFile)
- {
- TraceLog(LOG_ERROR, "[%s] Unable to open file", filename);
- return model;
- }
-
- // header
- fread(&iqm,sizeof(IQMHeader), 1, iqmFile);
-
- if (strncmp(iqm.magic, IQM_MAGIC, sizeof(IQM_MAGIC)))
- {
- TraceLog(LOG_ERROR, "Magic Number \"%s\"does not match.", iqm.magic);
- fclose(iqmFile);
- return model;
- }
-
- if(iqm.version != IQM_VERSION)
- {
- TraceLog(LOG_ERROR, "IQM version %i is incorrect.", iqm.version);
- fclose(iqmFile);
- return model;
- }
-
- // meshes
- 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].baseVertices = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default IQM base position
- model.meshes[i].baseNormals = malloc(sizeof(float)*imesh[i].num_vertexes*3); // Default IQM base normal
-
- model.meshes[i].texcoords = malloc(sizeof(float)*imesh[i].num_vertexes*2);
- model.meshes[i].weightId = malloc(sizeof(int)*imesh[i].num_vertexes*4);
- model.meshes[i].weightBias = malloc(sizeof(float)*imesh[i].num_vertexes*4);
-
- model.meshes[i].triangleCount = imesh[i].num_triangles;
- model.meshes[i].indices = malloc(sizeof(unsigned short)*imesh[i].num_triangles*3);
-
- // What we actually process for rendering, should be updated transforming meshes.vertices and meshes.normals
- model.meshes[i].vertices = malloc(sizeof(float)*imesh[i].num_vertexes*3);
- model.meshes[i].normals = malloc(sizeof(float)*imesh[i].num_vertexes*3);
- }
-
- // tris
- 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;
- }
- }
-
- // vertarrays
- 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].baseVertices[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].baseNormals[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 vcounter = 0;
- for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
- {
- model.meshes[m].weightId[vcounter] = blendi[i];
- vcounter++;
- }
- }
- } 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 vcounter = 0;
- for (int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
- {
- model.meshes[m].weightBias[vcounter] = blendw[i]/255.0f;
- vcounter++;
- }
- }
- } break;
- }
- }
-
- // joints, include base poses
- ijoint = malloc(sizeof(IQMJoint)*iqm.num_joints);
- fseek(iqmFile, iqm.ofs_joints, SEEK_SET);
- fread(ijoint, sizeof(IQMJoint)*iqm.num_joints, 1, iqmFile);
-
- model.jointCount = iqm.num_joints;
- model.joints = malloc(sizeof(Joint)*iqm.num_joints);
- model.basepose = malloc(sizeof(Pose)*iqm.num_joints);
-
- for (int i = 0; i < iqm.num_joints; i++)
- {
- // joints
- model.joints[i].parent = ijoint[i].parent;
- fseek(iqmFile, iqm.ofs_text + ijoint[i].name, SEEK_SET);
- fread(model.joints[i].name,sizeof(char)*JOINT_NAME_LENGTH, 1, iqmFile);
-
- // basepose
- model.basepose[i].translation.x = ijoint[i].translate[0];
- model.basepose[i].translation.y = ijoint[i].translate[1];
- model.basepose[i].translation.z = ijoint[i].translate[2];
-
- model.basepose[i].rotation.x = ijoint[i].rotate[0];
- model.basepose[i].rotation.y = ijoint[i].rotate[1];
- model.basepose[i].rotation.z = ijoint[i].rotate[2];
- model.basepose[i].rotation.w = ijoint[i].rotate[3];
-
- model.basepose[i].scale.x = ijoint[i].scale[0];
- model.basepose[i].scale.y = ijoint[i].scale[1];
- model.basepose[i].scale.z = ijoint[i].scale[2];
- }
-
- // build base pose
- for (int i = 0; i < model.jointCount; i++)
- {
- if (model.joints[i].parent >= 0)
- {
- model.basepose[i].rotation = QuaternionMultiply(model.basepose[model.joints[i].parent].rotation, model.basepose[i].rotation);
- model.basepose[i].translation = Vector3RotateByQuaternion(model.basepose[i].translation, model.basepose[model.joints[i].parent].rotation);
- model.basepose[i].translation = Vector3Add(model.basepose[i].translation, model.basepose[model.joints[i].parent].translation);
- model.basepose[i].scale = Vector3MultiplyV(model.basepose[i].scale, model.basepose[model.joints[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;
-}
#endif