/******************************************************************************************* * * raylib [textures] example - Bunnymark * * This example has been created using raylib 1.6 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2014-2019 Ramon Santamaria (@raysan5), 2024 Moritz Voss (@thygrrr) * * ********************************************************************************************/ using System.Diagnostics; using System.Numerics; using static Raylib_cs.Raylib; namespace Examples.Textures; public static class Bunnymark { // limits private const int MaxBunnies = 500_000; private const int BunnyIncrement = 500; private const int BunnyDecrement = 2_500; private const int TARGET_FPS = 60; // This is the maximum amount of elements (quads) per batch private const int MAX_BATCH_ELEMENTS = Rlgl.DEFAULT_BATCH_BUFFER_ELEMENTS; private record struct Bunny() { public Vector2 Position { get; set; } = GetMousePosition(); public Vector2 Speed { get; set; } = new( GetRandomValue(-250, 250) / (float)TARGET_FPS, GetRandomValue(-250, 250) / (float)TARGET_FPS); public Color Color { get; } = new( GetRandomValue(50, 240), GetRandomValue(80, 240), GetRandomValue(100, 240), 255); } public static int Main() { // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [textures] example - bunnymark"); // Load bunny texture Texture2D texBunny = LoadTexture("resources/wabbit_alpha.png"); Vector2 halfSize = new Vector2(texBunny.Width, texBunny.Height) / 2; // Initialize bunnies storage Span bunnies = new Bunny[MaxBunnies]; int bunniesCount = 0; SetTargetFPS(TARGET_FPS); //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) { // Update //---------------------------------------------------------------------------------- if (IsMouseButtonDown(MouseButton.Left) && bunniesCount < MaxBunnies) { // Add a range of new bunnies foreach (ref var bunny in bunnies[bunniesCount..(bunniesCount+BunnyIncrement)]) { bunny = new(); } bunniesCount += BunnyIncrement; } else if (IsMouseButtonDown(MouseButton.Right)) { // Remove the oldest bunnies, shifting them back in the span if (bunniesCount > BunnyDecrement) { bunnies[BunnyDecrement .. bunniesCount].CopyTo(bunnies); } bunniesCount = Math.Max(0, bunniesCount - BunnyDecrement); } // Update bunnies foreach (ref var bunny in bunnies[..bunniesCount]) { // Integrate position bunny.Position += bunny.Speed; // Bounce bunnies off the screen borders bunny.Speed *= (bunny.Position + halfSize) switch { { X: < 0 or > screenWidth, Y: < 40 or > screenHeight} => new(-1, -1), { X: < 0 or > screenWidth} => new(-1, 1), { Y: < 40 or > screenHeight} => new(1,-1), _ => Vector2.One, }; } //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(Color.RayWhite); foreach (var bunny in bunnies[..bunniesCount]) { // NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS), // a draw call is launched and buffer starts being filled again; // before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU... // Process of sending data is costly, and it could happen that GPU data has not been completely // processed for drawing while new data is tried to be sent (updating current in-use buffers) // it could generate a stall and consequently a frame drop, limiting the number of drawn bunnies DrawTexture(texBunny, (int)bunny.Position.X, (int)bunny.Position.Y, bunny.Color); } DrawRectangle(0, 0, screenWidth, 40, Color.Black); DrawText($"bunnies: {bunniesCount}", 120, 10, 20, Color.Green); DrawText($"batched draw calls: {1 + bunniesCount / MAX_BATCH_ELEMENTS}", 320, 10, 20, Color.Maroon); DrawText("Left Mouse: Add Bunnies!!! :D", 10, 400, 20, Color.LightGray); DrawText("Right Mouse: Remove Bunnies", 10, 420, 20, Color.LightGray); DrawFPS(10, 10); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- UnloadTexture(texBunny); CloseWindow(); //-------------------------------------------------------------------------------------- return 0; } static Bunnymark() { Debug.Assert(MaxBunnies % BunnyIncrement == 0 && MaxBunnies % BunnyDecrement == 0, "MaxBunnies must be a common multiple of BunnyIncrement and BunnyDecrement."); } }