diff --git a/examples/models/m3d_loading/cesium_man.m3d b/examples/models/m3d_loading/cesium_man.m3d new file mode 100644 index 0000000..ddf9f50 Binary files /dev/null and b/examples/models/m3d_loading/cesium_man.m3d differ diff --git a/examples/models/m3d_loading/main.go b/examples/models/m3d_loading/main.go new file mode 100644 index 0000000..2d8ef56 --- /dev/null +++ b/examples/models/m3d_loading/main.go @@ -0,0 +1,156 @@ +/******************************************************************************************* +* +* raylib [models] example - Load models M3D +* +* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* +* Example contributed by bzt (@bztsrc) and reviewed by Ramon Santamaria (@raysan5) +* +* NOTES: +* - Model3D (M3D) fileformat specs: https://gitlab.com/bztsrc/model3d +* - Bender M3D exported: https://gitlab.com/bztsrc/model3d/-/tree/master/blender +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2022-2024 bzt (@bztsrc) +* +********************************************************************************************/ +package main + +import ( + "unsafe" + + "github.com/gen2brain/raylib-go/raylib" +) + +const ( + screenWidth = 800 + screenHeight = 450 +) + +func main() { + // Initialization + rl.InitWindow(screenWidth, screenHeight, "raylib [models] example - M3D model loading") + + // Define the camera to look into our 3d world + camera := rl.Camera{ + Position: rl.NewVector3(1.5, 1.5, 1.5), + Target: rl.NewVector3(0.0, 0.4, 0.0), + Up: rl.NewVector3(0.0, 1.0, 0.0), + Fovy: 45.0, + Projection: rl.CameraPerspective, + } + + position := rl.NewVector3(0.0, 0.0, 0.0) + + modelFileName := "cesium_man.m3d" + drawMesh := true + drawSkeleton := true + animPlaying := false // Store anim state, what to draw + + // Load model + model := rl.LoadModel(modelFileName) + + // Load animations + + animFrameCounter := 0 + animID := 0 + anims := rl.LoadModelAnimations(modelFileName) + animsCount := int32(len(anims)) + + rl.DisableCursor() + rl.SetTargetFPS(60) + + // Main game loop + for !rl.WindowShouldClose() { + // Update + rl.UpdateCamera(&camera, rl.CameraFirstPerson) + + if animsCount > 0 { + // Play animation when space bar is held down (or step one frame with N) + if rl.IsKeyDown(rl.KeySpace) || rl.IsKeyPressed(rl.KeyN) { + animFrameCounter++ + if animFrameCounter >= int(anims[animID].FrameCount) { + animFrameCounter = 0 + } + rl.UpdateModelAnimation(model, anims[animID], int32(animFrameCounter)) + animPlaying = true + } + + // Select animation by pressing C + if rl.IsKeyPressed(rl.KeyC) { + animFrameCounter = 0 + animID++ + if animID >= int(animsCount) { + animID = 0 + } + rl.UpdateModelAnimation(model, anims[animID], 0) + animPlaying = true + } + } + + // Toggle skeleton drawing + if rl.IsKeyPressed(rl.KeyB) { + drawSkeleton = !drawSkeleton + } + + // Toggle mesh drawing + if rl.IsKeyPressed(rl.KeyM) { + drawMesh = !drawMesh + } + + // Draw + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.BeginMode3D(camera) + + // Draw 3d model with texture + if drawMesh { + rl.DrawModel(model, position, 1.0, rl.White) + } + + // Draw the animated skeleton + if drawSkeleton { + modelBones := model.GetBones() + modelPoses := model.GetBindPose() + animBones := unsafe.Slice(anims[animID].Bones, anims[animID].BoneCount) + animPoses := unsafe.Slice(anims[animID].FramePoses, anims[animID].FrameCount) + transforms := unsafe.Slice(animPoses[animFrameCounter], anims[animID].BoneCount) + for bone := 0; bone < int(model.BoneCount)-1; bone++ { + if !animPlaying || animsCount == 0 { + // Display the bind-pose skeleton + rl.DrawCube(modelPoses[bone].Translation, 0.04, 0.04, 0.04, rl.Red) + if modelBones[bone].Parent >= 0 { + rl.DrawLine3D(modelPoses[bone].Translation, modelPoses[modelBones[bone].Parent].Translation, rl.Red) + } + } else { + // // Display the frame-pose skeleton + rl.DrawCube(transforms[bone].Translation, 0.05, 0.05, 0.05, rl.Red) + if animBones[bone].Parent >= 0 { + rl.DrawLine3D(transforms[bone].Translation, transforms[animBones[bone].Parent].Translation, rl.Red) + } + } + } + } + + rl.DrawGrid(10, 1.0) + + rl.EndMode3D() + + rl.DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, screenHeight-80, 10, rl.Maroon) + rl.DrawText("PRESS N to STEP ONE ANIMATION FRAME", 10, screenHeight-60, 10, rl.DarkGray) + rl.DrawText("PRESS C to CYCLE THROUGH ANIMATIONS", 10, screenHeight-40, 10, rl.DarkGray) + rl.DrawText("PRESS M to toggle MESH, B to toggle SKELETON DRAWING", 10, screenHeight-20, 10, rl.DarkGray) + rl.DrawText("(c) CesiumMan model by KhronosGroup", screenWidth-210, screenHeight-20, 10, rl.Gray) + + rl.EndDrawing() + } + + // De-Initialization + rl.UnloadModelAnimations(anims) + rl.UnloadModel(model) + rl.CloseWindow() +}