You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
7.2 KiB

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