models_loading_m3d.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*******************************************************************************************
  2. *
  3. * raylib [models] example - Load models M3D
  4. *
  5. * Example complexity rating: [★★☆☆] 2/4
  6. *
  7. * Example originally created with raylib 4.5, last time updated with raylib 4.5
  8. *
  9. * Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5)
  10. *
  11. * NOTES:
  12. * - Model3D (M3D) fileformat specs: https://gitlab.com/bztsrc/model3d
  13. * - Bender M3D exported: https://gitlab.com/bztsrc/model3d/-/tree/master/blender
  14. *
  15. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  16. * BSD-like license that allows static linking with closed source software
  17. *
  18. * Copyright (c) 2022-2024 bzt (@bztsrc)
  19. *
  20. ********************************************************************************************/
  21. #include "raylib.h"
  22. //------------------------------------------------------------------------------------
  23. // Program main entry point
  24. //------------------------------------------------------------------------------------
  25. int main(void)
  26. {
  27. // Initialization
  28. //--------------------------------------------------------------------------------------
  29. const int screenWidth = 800;
  30. const int screenHeight = 450;
  31. InitWindow(screenWidth, screenHeight, "raylib [models] example - M3D model loading");
  32. // Define the camera to look into our 3d world
  33. Camera camera = { 0 };
  34. camera.position = (Vector3){ 1.5f, 1.5f, 1.5f }; // Camera position
  35. camera.target = (Vector3){ 0.0f, 0.4f, 0.0f }; // Camera looking at point
  36. camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
  37. camera.fovy = 45.0f; // Camera field-of-view Y
  38. camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
  39. Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
  40. char modelFileName[128] = "resources/models/m3d/cesium_man.m3d";
  41. bool drawMesh = 1;
  42. bool drawSkeleton = 1;
  43. bool animPlaying = false; // Store anim state, what to draw
  44. // Load model
  45. Model model = LoadModel(modelFileName); // Load the bind-pose model mesh and basic data
  46. // Load animations
  47. int animsCount = 0;
  48. int animFrameCounter = 0, animId = 0;
  49. ModelAnimation *anims = LoadModelAnimations(modelFileName, &animsCount); // Load skeletal animation data
  50. DisableCursor(); // Limit cursor to relative movement inside the window
  51. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  52. //--------------------------------------------------------------------------------------
  53. // Main game loop
  54. while (!WindowShouldClose()) // Detect window close button or ESC key
  55. {
  56. // Update
  57. //----------------------------------------------------------------------------------
  58. UpdateCamera(&camera, CAMERA_FIRST_PERSON);
  59. if (animsCount)
  60. {
  61. // Play animation when spacebar is held down (or step one frame with N)
  62. if (IsKeyDown(KEY_SPACE) || IsKeyPressed(KEY_N))
  63. {
  64. animFrameCounter++;
  65. if (animFrameCounter >= anims[animId].frameCount) animFrameCounter = 0;
  66. UpdateModelAnimation(model, anims[animId], animFrameCounter);
  67. animPlaying = true;
  68. }
  69. // Select animation by pressing C
  70. if (IsKeyPressed(KEY_C))
  71. {
  72. animFrameCounter = 0;
  73. animId++;
  74. if (animId >= (int)animsCount) animId = 0;
  75. UpdateModelAnimation(model, anims[animId], 0);
  76. animPlaying = true;
  77. }
  78. }
  79. // Toggle skeleton drawing
  80. if (IsKeyPressed(KEY_B)) drawSkeleton ^= 1;
  81. // Toggle mesh drawing
  82. if (IsKeyPressed(KEY_M)) drawMesh ^= 1;
  83. //----------------------------------------------------------------------------------
  84. // Draw
  85. //----------------------------------------------------------------------------------
  86. BeginDrawing();
  87. ClearBackground(RAYWHITE);
  88. BeginMode3D(camera);
  89. // Draw 3d model with texture
  90. if (drawMesh) DrawModel(model, position, 1.0f, WHITE);
  91. // Draw the animated skeleton
  92. if (drawSkeleton)
  93. {
  94. // Loop to (boneCount - 1) because the last one is a special "no bone" bone,
  95. // needed to workaround buggy models
  96. // without a -1, we would always draw a cube at the origin
  97. for (int i = 0; i < model.boneCount - 1; i++)
  98. {
  99. // By default the model is loaded in bind-pose by LoadModel().
  100. // But if UpdateModelAnimation() has been called at least once
  101. // then the model is already in animation pose, so we need the animated skeleton
  102. if (!animPlaying || !animsCount)
  103. {
  104. // Display the bind-pose skeleton
  105. DrawCube(model.bindPose[i].translation, 0.04f, 0.04f, 0.04f, RED);
  106. if (model.bones[i].parent >= 0)
  107. {
  108. DrawLine3D(model.bindPose[i].translation,
  109. model.bindPose[model.bones[i].parent].translation, RED);
  110. }
  111. }
  112. else
  113. {
  114. // Display the frame-pose skeleton
  115. DrawCube(anims[animId].framePoses[animFrameCounter][i].translation, 0.05f, 0.05f, 0.05f, RED);
  116. if (anims[animId].bones[i].parent >= 0)
  117. {
  118. DrawLine3D(anims[animId].framePoses[animFrameCounter][i].translation,
  119. anims[animId].framePoses[animFrameCounter][anims[animId].bones[i].parent].translation, RED);
  120. }
  121. }
  122. }
  123. }
  124. DrawGrid(10, 1.0f); // Draw a grid
  125. EndMode3D();
  126. DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, GetScreenHeight() - 80, 10, MAROON);
  127. DrawText("PRESS N to STEP ONE ANIMATION FRAME", 10, GetScreenHeight() - 60, 10, DARKGRAY);
  128. DrawText("PRESS C to CYCLE THROUGH ANIMATIONS", 10, GetScreenHeight() - 40, 10, DARKGRAY);
  129. DrawText("PRESS M to toggle MESH, B to toggle SKELETON DRAWING", 10, GetScreenHeight() - 20, 10, DARKGRAY);
  130. DrawText("(c) CesiumMan model by KhronosGroup", GetScreenWidth() - 210, GetScreenHeight() - 20, 10, GRAY);
  131. EndDrawing();
  132. //----------------------------------------------------------------------------------
  133. }
  134. // De-Initialization
  135. //--------------------------------------------------------------------------------------
  136. // Unload model animations data
  137. UnloadModelAnimations(anims, animsCount);
  138. UnloadModel(model); // Unload model
  139. CloseWindow(); // Close window and OpenGL context
  140. //--------------------------------------------------------------------------------------
  141. return 0;
  142. }