From c059ece2a4292581d40e17257f8f9f2eec9f3b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20=E2=9D=A4=EF=B8=8F?= Date: Thu, 13 Nov 2025 17:10:13 -0500 Subject: [PATCH] [examples] Added: directional billboard (#5351) * Added models directional billboard example * add killbot texture * various fixes and formatting tweaks * corrected stdlib --- .../models/models_directional_billboard.c | 116 ++++++++++++++++++ .../models/models_directional_billboard.png | Bin 0 -> 20612 bytes examples/models/resources/skillbot.png | Bin 0 -> 2241 bytes 3 files changed, 116 insertions(+) create mode 100644 examples/models/models_directional_billboard.c create mode 100644 examples/models/models_directional_billboard.png create mode 100644 examples/models/resources/skillbot.png diff --git a/examples/models/models_directional_billboard.c b/examples/models/models_directional_billboard.c new file mode 100644 index 000000000..fe1b33b2d --- /dev/null +++ b/examples/models/models_directional_billboard.c @@ -0,0 +1,116 @@ +/******************************************************************************************* +* +* raylib [models] example - directional billboard +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6 +* +* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5) +* +* 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) 2025-2025 Robin (@RobinsAviary) +* Killbot art by patvanmackelberg https://opengameart.org/content/killbot-8-directional under CC0 +* +********************************************************************************************/ + +#include "raylib.h" +#include "raymath.h" +#include + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - directional billboard"); + + // Set up the camera + Camera camera = { 0 }; + camera.position = (Vector3){ 2.0f, 1.0f, 2.0f }; // Starting position + camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Target position + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Up vector + camera.fovy = 45.0f; // FOV + camera.projection = CAMERA_PERSPECTIVE; // Projection type (Standard 3D perspective) + + // Load billboard texture + Texture skillbot = LoadTexture("resources/skillbot.png"); + + // Timer to update animation + float anim_timer = 0.0f; + // Animation frame + unsigned int anim = 0; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_ORBITAL); + + // Update timer with delta time + anim_timer += GetFrameTime(); + + // Update frame index after a certain amount of time (half a second) + if (anim_timer > 0.5f) + { + anim_timer = 0.0f; + anim += 1; + } + + // Reset frame index to zero on overflow + if (anim >= 4) anim = 0; + + // Find the current direction frame based on the camera position to the billboard object + float dir = (float)floor(((Vector2Angle((Vector2){ 2.0f, 0.0f }, (Vector2){ camera.position.x, camera.position.z })/PI)*4.0f) + 0.25f); + + // Correct frame index if angle is negative + if (dir < 0.0f) + { + dir = 8.0f - (float)abs((int)dir); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawGrid(10, 1.0f); + + // Draw billboard pointing straight up to the sky, rotated relative to the camera and offset from the bottom + DrawBillboardPro(camera, skillbot, (Rectangle){ 0.0f + (anim*24.0f), 0.0f + (dir*24.0f), 24.0f, 24.0f }, Vector3Zero(), (Vector3){ 0.0f, 1.0f, 0.0f }, Vector2One(), (Vector2){ 0.5f, 0.0f }, 0, WHITE); + + EndMode3D(); + + // Render various variables for reference + DrawText(TextFormat("animation: %d", anim), 10, 10, 20, DARKGRAY); + DrawText(TextFormat("direction frame: %.0f", dir), 10, 40, 20, DARKGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + // Unload billboard texture + UnloadTexture(skillbot); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/models/models_directional_billboard.png b/examples/models/models_directional_billboard.png new file mode 100644 index 0000000000000000000000000000000000000000..cbbe11065eef52f7389e697660af68e119443e5d GIT binary patch literal 20612 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 bFfc5V@ztIs_WC{p0|SGntDnm{r-UW|!Md5^ literal 0 HcmV?d00001 diff --git a/examples/models/resources/skillbot.png b/examples/models/resources/skillbot.png new file mode 100644 index 0000000000000000000000000000000000000000..537f1338367ec575c714a6e858200eb07bc7ec1b GIT binary patch literal 2241 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

Yvo4TgxgU7wKI4Yjj?CM9?c_z- z9hDiy7;1XO7+zUih`A=|u>T-)Q>@@i_5W^pdwWy<@-~#Wu1K8xVIA-Kgr%Z)&)vLV nAAco$JN6v)|MSilHvgH!mtWaqw0@ZpsN(c=^>bP0l+XkK@GOjN literal 0 HcmV?d00001