diff --git a/Examples/Core/BasicWindow.cs b/Examples/Core/BasicWindow.cs index 51f8d76..4180912 100644 --- a/Examples/Core/BasicWindow.cs +++ b/Examples/Core/BasicWindow.cs @@ -1,21 +1,28 @@ /******************************************************************************************* * -* raylib [core] example - Basic window +* raylib [core] example - basic window +* +* Example complexity rating: [★☆☆☆] 1/4 * * Welcome to raylib! * -* To test examples, just press F6 and execute raylib_compile_execute script +* To test examples, just press F6 and execute 'raylib_compile_execute' script * Note that compiled executable is placed in the same folder as .c file * +* To test the examples on Web, press F6 and execute 'raylib_compile_execute_web' script +* Web version of the program is generated in the same folder as .c file +* * You can find all basic examples on C:\raylib\raylib\examples folder or * raylib official webpage: www.raylib.com * * Enjoy using raylib. :) * -* This example has been created using raylib 1.0 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example originally created with raylib 1.0, last time updated with raylib 1.0 * -* Copyright (c) 2013-2016 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) 2013-2026 Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -53,7 +60,7 @@ public class BasicWindow BeginDrawing(); ClearBackground(Color.RayWhite); - DrawText("Congrats! You created your first window!", 190, 200, 20, Color.Maroon); + DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/Examples/Core/Camera2dDemo.cs b/Examples/Core/Camera2dDemo.cs index 2c2568e..1463c24 100644 --- a/Examples/Core/Camera2dDemo.cs +++ b/Examples/Core/Camera2dDemo.cs @@ -2,10 +2,14 @@ * * raylib [core] example - 2d camera * -* This example has been created using raylib 1.5 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★★☆☆] 2/4 * -* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.5, last time updated with raylib 3.0 +* +* 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) 2016-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/Examples/Core/Customlogging.cs b/Examples/Core/Customlogging.cs index bf0efe7..3fdf64a 100644 --- a/Examples/Core/Customlogging.cs +++ b/Examples/Core/Customlogging.cs @@ -50,7 +50,7 @@ public unsafe class CustomLogging // First thing we do is setting our custom logger to ensure everything raylib logs // will use our own logger instead of its internal one - Raylib.SetTraceLogCallback(&LogCustom); + SetTraceLogCallback(&LogCustom); InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging"); @@ -79,7 +79,7 @@ public unsafe class CustomLogging // De-Initialization //-------------------------------------------------------------------------------------- CloseWindow(); - Raylib.SetTraceLogCallback(&Logging.LogConsole); + SetTraceLogCallback(&Logging.LogConsole); //-------------------------------------------------------------------------------------- return 0; diff --git a/Examples/Core/DeltaTime.cs b/Examples/Core/DeltaTime.cs new file mode 100644 index 0000000..8577636 --- /dev/null +++ b/Examples/Core/DeltaTime.cs @@ -0,0 +1,129 @@ +using System.Numerics; + +namespace Examples.Core; +/******************************************************************************************* + * + * raylib [core] example - delta time + * + * Example complexity rating: [★☆☆☆] 1/4 + * + * Example originally created with raylib 5.5, last time updated with raylib 6.0 + * + * 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 Robin (@RobinsAviary) + * + ********************************************************************************************/ + +using static Raylib_cs.Raylib; + +public class DeltaTime +{ + public static int Main() + { + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - delta time"); + + int currentFps = 60; + + Vector2 deltaCircle = new Vector2(0, (float)screenHeight / 3.0f); + Vector2 frameCircle = new Vector2(0, (float)screenHeight * (2.0f / 3.0f)); + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + const float speed = 10.0f; + const float circleRadius = 32.0f; + + // Main game loop + while (!WindowShouldClose()) + { + // Update + //---------------------------------------------------------------------------------- + // Adjust the FPS target based on the mouse wheel + float mouseWheel = GetMouseWheelMove(); + if (mouseWheel != 0) + { + currentFps += (int)mouseWheel; + if (currentFps < 0) + { + currentFps = 0; + } + SetTargetFPS(currentFps); + } + + // GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time) + // Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS + + // Multiply by 6.0 (an arbitrary value) in order to make the speed + // visually closer to the other circle (at 60 fps), for comparison + deltaCircle.X += GetFrameTime() * 6.0f * speed; + // This circle can move faster or slower visually depending on the FPS + frameCircle.X += 0.1f * speed; + + // If either circle is off the screen, reset it back to the start + if (deltaCircle.X > screenWidth) + { + deltaCircle.X = 0; + } + + if (frameCircle.X > screenWidth) + { + frameCircle.X = 0; + } + + // Reset both circles positions + if (IsKeyPressed(KeyboardKey.R)) + { + deltaCircle.X = 0; + frameCircle.X = 0; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(Color.RayWhite); + + // Draw both circles to the screen + DrawCircleV(deltaCircle, circleRadius, Color.Red); + DrawCircleV(frameCircle, circleRadius, Color.Blue); + + // Draw the help text + // Determine what help text to show depending on the current FPS target + var fpsText = ""; + if (currentFps <= 0) + { + fpsText = $"FPS: unlimited ({GetFPS()})"; + } + else + { + fpsText = $"FPS: {GetFPS()} (target: {currentFps})"; + } + DrawText(fpsText, 10, 10, 20, Color.DarkGray); + DrawText($"Frame time: {GetFrameTime():F2} ms", 10, 30, 20, Color.DarkGray); + DrawText("Use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, Color.DarkGray); + + // Draw the text above the circles + DrawText("FUNC: x += GetFrameTime()*speed", 10, 90, 20, Color.Red); + DrawText("FUNC: x += speed", 10, 240, 20, Color.Blue); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); + //-------------------------------------------------------------------------------------- + + return 0; + } +} diff --git a/Examples/Core/InputGamepad.cs b/Examples/Core/InputGamepad.cs index 39fe911..883ab4e 100644 --- a/Examples/Core/InputGamepad.cs +++ b/Examples/Core/InputGamepad.cs @@ -1,19 +1,24 @@ /******************************************************************************************* -* -* raylib [core] example - Gamepad input -* -* NOTE: This example requires a Gamepad connected to the system -* raylib is configured to work with the following gamepads: -* - Xbox 360 Controller (Xbox 360, Xbox One) -* - PLAYSTATION(R)3 Controller -* Check raylib.h for buttons configuration -* -* 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) 2013-2016 Ramon Santamaria (@raysan5) -* -********************************************************************************************/ + * + * raylib [core] example - input gamepad + * + * Example complexity rating: [★☆☆☆] 1/4 + * + * NOTE: This example requires a Gamepad connected to the system + * raylib is configured to work with the following gamepads: + * - Xbox 360 Controller (Xbox 360, Xbox One) + * - PLAYSTATION(R)3 Controller + * Check raylib.h for buttons configuration + * + * Example originally created with raylib 1.1, last time updated with raylib 4.2 + * + * 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) 2013-2025 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + using System.Numerics; using Raylib_cs; @@ -25,10 +30,10 @@ public class InputGamepad { // NOTE: Gamepad name ID depends on drivers and OS // These are some possible names the gamepads could have. - public const string XBOX360_LEGACY_NAME_ID = "Xbox Controller"; - public const string XBOX360_NAME_ID = "Xbox 360 Controller"; - public const string XBOX360_NAME_ID_RPI = "Microsoft X-Box 360 pad"; - public const string PS3_NAME_ID = "PLAYSTATION(R)3 Controller"; + public const string XBOX_ALIAS_1 = "xbox"; + public const string XBOX_ALIAS_2 = "x-box"; + public const string PS_ALIAS_1 = "playstation"; + public const string PS_ALIAS_2 = "sony"; public static int Main() { @@ -47,12 +52,32 @@ public class InputGamepad SetTargetFPS(60); //-------------------------------------------------------------------------------------- + int gamepad = 0; + Rectangle vibrateButton = new Rectangle(); + // Main game loop while (!WindowShouldClose()) { // Update //---------------------------------------------------------------------------------- - // ... + if (IsKeyPressed(KeyboardKey.Left) && gamepad > 0) + { + gamepad--; + } + + if (IsKeyPressed(KeyboardKey.Right)) + { + gamepad++; + } + + Vector2 mousePosition = GetMousePosition(); + + vibrateButton = new Rectangle(10, 70.0f + 20 * GetGamepadAxisCount(gamepad) + 20, 75, 24); + if (IsMouseButtonPressed(MouseButton.Left) && CheckCollisionPointRec(mousePosition, vibrateButton)) + { + SetGamepadVibration(gamepad, 1.0f, 1.0f, 1.0f); + } + //---------------------------------------------------------------------------------- // Draw @@ -60,50 +85,49 @@ public class InputGamepad BeginDrawing(); ClearBackground(Color.RayWhite); - if (IsGamepadAvailable(0)) + if (IsGamepadAvailable(gamepad)) { - string gamepadName = GetGamepadName_(0); - DrawText($"GP1: {gamepadName}", 10, 10, 10, Color.Black); + string gamepadName = GetGamepadName_(gamepad); + DrawText($"GP{gamepad}: {gamepadName}", 10, 10, 10, Color.Black); - if (gamepadName == XBOX360_LEGACY_NAME_ID || - gamepadName == XBOX360_NAME_ID || - gamepadName == XBOX360_NAME_ID_RPI) + if (gamepadName.Contains(XBOX_ALIAS_1, StringComparison.OrdinalIgnoreCase)|| + gamepadName.Contains(XBOX_ALIAS_2, StringComparison.OrdinalIgnoreCase)) { DrawTexture(texXboxPad, 0, 0, Color.DarkGray); // Draw buttons: xbox home - if (IsGamepadButtonDown(0, GamepadButton.Middle)) + if (IsGamepadButtonDown(gamepad, GamepadButton.Middle)) { DrawCircle(394, 89, 19, Color.Red); } // Draw buttons: basic - if (IsGamepadButtonDown(0, GamepadButton.MiddleRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight)) { DrawCircle(436, 150, 9, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.MiddleLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft)) { DrawCircle(352, 150, 9, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft)) { DrawCircle(501, 151, 15, Color.Blue); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceDown)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown)) { DrawCircle(536, 187, 15, Color.Lime); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight)) { DrawCircle(572, 151, 15, Color.Maroon); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceUp)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp)) { DrawCircle(536, 115, 15, Color.Gold); } @@ -111,33 +135,33 @@ public class InputGamepad // Draw buttons: d-pad DrawRectangle(317, 202, 19, 71, Color.Black); DrawRectangle(293, 228, 69, 19, Color.Black); - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceUp)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp)) { DrawRectangle(317, 202, 19, 26, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceDown)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown)) { DrawRectangle(317, 202 + 45, 19, 26, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft)) { DrawRectangle(292, 228, 25, 19, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight)) { DrawRectangle(292 + 44, 228, 26, 19, Color.Red); } // Draw buttons: left-right back - if (IsGamepadButtonDown(0, GamepadButton.LeftTrigger1)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1)) { DrawCircle(259, 61, 20, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.RightTrigger1)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1)) { DrawCircle(536, 61, 20, Color.Red); } @@ -146,8 +170,8 @@ public class InputGamepad DrawCircle(259, 152, 39, Color.Black); DrawCircle(259, 152, 34, Color.LightGray); DrawCircle( - 259 + (int)(GetGamepadAxisMovement(0, GamepadAxis.LeftX) * 20), - 152 + (int)(GetGamepadAxisMovement(0, GamepadAxis.LeftY) * 20), + 259 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20), + 152 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20), 25, Color.Black ); @@ -156,36 +180,36 @@ public class InputGamepad DrawCircle(461, 237, 38, Color.Black); DrawCircle(461, 237, 33, Color.LightGray); DrawCircle( - 461 + (int)(GetGamepadAxisMovement(0, GamepadAxis.RightX) * 20), - 237 + (int)(GetGamepadAxisMovement(0, GamepadAxis.RightY) * 20), + 461 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightX) * 20), + 237 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightY) * 20), 25, Color.Black ); // Draw axis: left-right triggers - float leftTriggerX = GetGamepadAxisMovement(0, GamepadAxis.LeftTrigger); - float rightTriggerX = GetGamepadAxisMovement(0, GamepadAxis.RightTrigger); + float leftTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger); + float rightTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger); DrawRectangle(170, 30, 15, 70, Color.Gray); DrawRectangle(604, 30, 15, 70, Color.Gray); DrawRectangle(170, 30, 15, (int)(((1.0f + leftTriggerX) / 2.0f) * 70), Color.Red); DrawRectangle(604, 30, 15, (int)(((1.0f + rightTriggerX) / 2.0f) * 70), Color.Red); } - else if (gamepadName == PS3_NAME_ID) + else if (gamepadName.Contains(PS_ALIAS_1, StringComparison.OrdinalIgnoreCase) || gamepadName.Contains(PS_ALIAS_2, StringComparison.OrdinalIgnoreCase)) { DrawTexture(texPs3Pad, 0, 0, Color.DarkGray); // Draw buttons: ps - if (IsGamepadButtonDown(0, GamepadButton.Middle)) + if (IsGamepadButtonDown(gamepad, GamepadButton.Middle)) { DrawCircle(396, 222, 13, Color.Red); } // Draw buttons: basic - if (IsGamepadButtonDown(0, GamepadButton.MiddleLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft)) { DrawRectangle(328, 170, 32, 13, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.MiddleRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight)) { DrawTriangle( new Vector2(436, 168), @@ -195,22 +219,22 @@ public class InputGamepad ); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceUp)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp)) { DrawCircle(557, 144, 13, Color.Lime); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight)) { DrawCircle(586, 173, 13, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceDown)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown)) { DrawCircle(557, 203, 13, Color.Violet); } - if (IsGamepadButtonDown(0, GamepadButton.RightFaceLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft)) { DrawCircle(527, 173, 13, Color.Pink); } @@ -218,33 +242,33 @@ public class InputGamepad // Draw buttons: d-pad DrawRectangle(225, 132, 24, 84, Color.Black); DrawRectangle(195, 161, 84, 25, Color.Black); - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceUp)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp)) { DrawRectangle(225, 132, 24, 29, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceDown)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown)) { DrawRectangle(225, 132 + 54, 24, 30, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceLeft)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft)) { DrawRectangle(195, 161, 30, 25, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.LeftFaceRight)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight)) { DrawRectangle(195 + 54, 161, 30, 25, Color.Red); } // Draw buttons: left-right back buttons - if (IsGamepadButtonDown(0, GamepadButton.LeftTrigger1)) + if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1)) { DrawCircle(239, 82, 20, Color.Red); } - if (IsGamepadButtonDown(0, GamepadButton.RightTrigger1)) + if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1)) { DrawCircle(557, 82, 20, Color.Red); } @@ -253,8 +277,8 @@ public class InputGamepad DrawCircle(319, 255, 35, Color.Black); DrawCircle(319, 255, 31, Color.LightGray); DrawCircle( - 319 + (int)(GetGamepadAxisMovement(0, GamepadAxis.LeftX) * 20), - 255 + (int)(GetGamepadAxisMovement(0, GamepadAxis.LeftY) * 20), + 319 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20), + 255 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20), 25, Color.Black ); @@ -263,15 +287,15 @@ public class InputGamepad DrawCircle(475, 255, 35, Color.Black); DrawCircle(475, 255, 31, Color.LightGray); DrawCircle( - 475 + (int)(GetGamepadAxisMovement(0, GamepadAxis.RightX) * 20), - 255 + (int)(GetGamepadAxisMovement(0, GamepadAxis.RightY) * 20), + 475 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightX) * 20), + 255 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightY) * 20), 25, Color.Black ); // Draw axis: left-right triggers - float leftTriggerX = GetGamepadAxisMovement(0, GamepadAxis.LeftTrigger); - float rightTriggerX = GetGamepadAxisMovement(0, GamepadAxis.RightTrigger); + float leftTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger); + float rightTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger); DrawRectangle(169, 48, 15, 70, Color.Gray); DrawRectangle(611, 48, 15, 70, Color.Gray); DrawRectangle(169, 48, 15, (int)(((1.0f - leftTriggerX) / 2.0f) * 70), Color.Red); @@ -283,12 +307,12 @@ public class InputGamepad // TODO: Draw generic gamepad } - DrawText($"DETECTED AXIS [{GetGamepadAxisCount(0)}]:", 10, 50, 10, Color.Maroon); + DrawText($"DETECTED AXIS [{GetGamepadAxisCount(gamepad)}]:", 10, 50, 10, Color.Maroon); - for (int i = 0; i < GetGamepadAxisCount(0); i++) + for (int i = 0; i < GetGamepadAxisCount(gamepad); i++) { DrawText( - $"AXIS {i}: {GetGamepadAxisMovement(0, (GamepadAxis)i)}", + $"AXIS {i}: {GetGamepadAxisMovement(gamepad, (GamepadAxis)i)}", 20, 70 + 20 * i, 10, @@ -296,6 +320,10 @@ public class InputGamepad ); } + DrawRectangleRec(vibrateButton, Color.SkyBlue); + DrawText("VIBRATE", (int)(vibrateButton.X + 14), (int)(vibrateButton.Y + 1), 10, Color.DarkGray); + + if (GetGamepadButtonPressed() != (int)GamepadButton.Unknown) { DrawText($"DETECTED BUTTON: {GetGamepadButtonPressed()}", 10, 430, 10, Color.Red); @@ -307,7 +335,7 @@ public class InputGamepad } else { - DrawText("GP1: NOT DETECTED", 10, 10, 10, Color.Gray); + DrawText($"GP{gamepad}: NOT DETECTED", 10, 10, 10, Color.Gray); DrawTexture(texXboxPad, 0, 0, Color.LightGray); } diff --git a/Examples/Core/InputGestures.cs b/Examples/Core/InputGestures.cs index 8367e9e..fda7d5c 100644 --- a/Examples/Core/InputGestures.cs +++ b/Examples/Core/InputGestures.cs @@ -1,11 +1,15 @@ /******************************************************************************************* * -* raylib [core] example - Gestures Detection +* raylib [core] example - input gestures * -* This example has been created using raylib 1.4 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★★☆☆] 2/4 * -* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.4, last time updated with raylib 4.2 +* +* 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) 2016-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -25,7 +29,7 @@ public class InputGestures const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [core] example - gestures detection"); + InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures"); Vector2 touchPosition = new(0, 0); Rectangle touchArea = new(220, 10, screenWidth - 230, screenHeight - 20); diff --git a/Examples/Core/InputGesturesTestBed.cs b/Examples/Core/InputGesturesTestBed.cs new file mode 100644 index 0000000..6595051 --- /dev/null +++ b/Examples/Core/InputGesturesTestBed.cs @@ -0,0 +1,434 @@ +/******************************************************************************************* + * + * raylib [core] example - input gestures testbed + * + * Example complexity rating: [★★★☆] 3/4 + * + * Example originally created with raylib 5.0, last time updated with raylib 6.0 + * + * Example contributed by ubkp (@ubkp) 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) 2023-2025 ubkp (@ubkp) + * + ********************************************************************************************/ + +using System.Numerics; + +namespace Examples.Core; + +using static Raylib_cs.Raylib; + +public class InputGesturesTestBed +{ + public const int GESTURE_LOG_SIZE = 20; + public const int MAX_TOUCH_COUNT = 32; + + //------------------------------------------------------------------------------------ + // Program main entry point + //------------------------------------------------------------------------------------ + + public static int Main() + { +// Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed"); + + Vector2 messagePosition = new Vector2( 160, 7 ); + + // Last gesture variables definitions + Gesture lastGesture = 0; + Vector2 lastGesturePosition = new Vector2( 165, 130 ); + + // Gesture log variables definitions + // NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures + string[] gestureLog = new string[GESTURE_LOG_SIZE + 1]; + for (int i= 0; i < GESTURE_LOG_SIZE; i++) + { + gestureLog[i] = new string(new char[12]); + } + ; + // NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around) + int gestureLogIndex = GESTURE_LOG_SIZE; + Gesture previousGesture = 0; + + // Log mode values: + // - 0 shows repeated events + // - 1 hides repeated events + // - 2 shows repeated events but hide hold events + // - 3 hides repeated events and hide hold events + int logMode = 1; + + Color gestureColor = new Color(0, 0, 0, 255 ); + Rectangle logButton1 = new Rectangle( 53, 7, 48, 26 ); + Rectangle logButton2 = new Rectangle( 108, 7, 36, 26 ); + Vector2 gestureLogPosition = new Vector2( 10, 10 ); + + // Protractor variables definitions + float angleLength = 90.0f; + float currentAngleDegrees = 0.0f; + Vector2 finalVector = new Vector2( 0.0f, 0.0f ); + Vector2 protractorPosition = new Vector2( 266.0f, 315.0f ); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //-------------------------------------------------------------------------------------- + // Handle common gestures data + int i, ii; // Iterators that will be reused by all for loops + Gesture currentGesture = GetGestureDetected(); + float currentDragDegrees = GetGestureDragAngle(); + float currentPitchDegrees = GetGesturePinchAngle(); + int touchCount = GetTouchPointCount(); + + // Handle last gesture + if ((currentGesture != 0) && ((int)currentGesture != 4) && (currentGesture != previousGesture)) + { + lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display + } + + // Handle gesture log + if (IsMouseButtonReleased(MouseButton.Left)) + { + if (CheckCollisionPointRec(GetMousePosition(), logButton1)) + { + switch (logMode) + { + case 3: logMode = 2; break; + case 2: logMode = 3; break; + case 1: logMode = 0; break; + default: logMode = 1; break; + } + } + else if (CheckCollisionPointRec(GetMousePosition(), logButton2)) + { + switch (logMode) + { + case 3: logMode = 1; break; + case 2: logMode = 0; break; + case 1: logMode = 3; break; + default: logMode = 2; break; + } + } + } + + int fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled + if (currentGesture != 0) + { + if (logMode == 3) // 3 hides repeated events and hide hold events + { + if ((((int)currentGesture != 4) && (currentGesture != previousGesture)) || ((int)currentGesture < 3)) + { + fillLog = 1; + } + } + else if (logMode == 2) // 2 shows repeated events but hide hold events + { + if ((int)currentGesture != 4) + { + fillLog = 1; + } + } + else if (logMode == 1) // 1 hides repeated events + { + if (currentGesture != previousGesture) + { + fillLog = 1; + } + } + else // 0 shows repeated events + { + fillLog = 1; + } + } + + if (fillLog > 0) // If one of the conditions from logMode was met, fill the gesture log + { + previousGesture = currentGesture; + gestureColor = GetGestureColor((int)currentGesture); + if (gestureLogIndex <= 0) + { + gestureLogIndex = GESTURE_LOG_SIZE; + } + gestureLogIndex--; + + // Copy the gesture respective name to the gesture log array + gestureLog[gestureLogIndex] = GetGestureName((int)currentGesture); + } + + // Handle protractor + if ((int)currentGesture > 255) + { + currentAngleDegrees = currentPitchDegrees; // Pinch In and Pinch Out + } + else if ((int)currentGesture > 15) + { + currentAngleDegrees = currentDragDegrees; // Swipe Right, Swipe Left, Swipe Up and Swipe Down + } + else if (currentGesture > 0) + { + currentAngleDegrees = 0.0f; // Tap, Doubletap, Hold and Grab + } + + float currentAngleRadians = + ((currentAngleDegrees + 90.0f) * MathF.PI / 180); // Convert the current angle to Radians + // Calculate the final vector for display + finalVector = new Vector2( + (angleLength * MathF.Sin(currentAngleRadians)) + protractorPosition.X, + (angleLength * MathF.Cos(currentAngleRadians)) + protractorPosition.Y + ) + ; + + // Handle touch and mouse pointer points + Vector2[] touchPosition = new Vector2[MAX_TOUCH_COUNT]; + + Vector2 mousePosition = Vector2.Zero; + if (currentGesture != Gesture.None) + { + if (touchCount != 0) + { + for (i = 0; i < touchCount; i++) + { + touchPosition[i] = GetTouchPosition(i); // Fill the touch positions + } + } + else + { + mousePosition = GetMousePosition(); + } + } + //-------------------------------------------------------------------------------------- + + // Draw + //-------------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(Color.RayWhite); + + // Draw common elements + DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 5, 10, Color.Black); + DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", (int)messagePosition.X + 15, + (int)messagePosition.Y + 5, 10, Color.Black); + DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 35, 10, Color.Black); + DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.", + (int)messagePosition.X + 15, (int)messagePosition.Y + 35, 10, Color.Black); + + // Draw last gesture + DrawText("Last gesture", (int)lastGesturePosition.X + 33, (int)lastGesturePosition.Y - 47, 20, Color.Black); + DrawText("Swipe Tap Pinch Touch", (int)lastGesturePosition.X + 17, + (int)lastGesturePosition.Y - 18, 10, Color.Black); + DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y, 20, 20, + lastGesture == Gesture.SwipeUp ? Color.Red : Color.LightGray); + DrawRectangle((int)lastGesturePosition.X, (int)lastGesturePosition.Y + 20, 20, 20, + lastGesture == Gesture.SwipeLeft ? Color.Red : Color.LightGray); + DrawRectangle((int)lastGesturePosition.X + 40, (int)lastGesturePosition.Y + 20, 20, 20, + lastGesture == Gesture.SwipeRight ? Color.Red : Color.LightGray); + DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y + 40, 20, 20, + lastGesture == Gesture.SwipeDown ? Color.Red : Color.LightGray); + DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 16, 10, + lastGesture == Gesture.Tap ? Color.Blue : Color.LightGray); + DrawRing(new Vector2( + lastGesturePosition.X + 103, lastGesturePosition.Y + 16 + ), 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == Gesture.Drag ? Color.Lime : Color.LightGray); + DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 43, 10, + lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray); + DrawCircle((int)lastGesturePosition.X + 103, (int)lastGesturePosition.Y + 43, 10, + lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray); + DrawTriangle(new Vector2( + lastGesturePosition.X + 122, lastGesturePosition.Y + 16 + ), new Vector2( + lastGesturePosition.X + 137, lastGesturePosition.Y + 26 + ), new Vector2( + lastGesturePosition.X + 137, lastGesturePosition.Y + 6 + ), lastGesture == Gesture.PinchOut ? Color.Orange : Color.LightGray); + DrawTriangle(new Vector2( + lastGesturePosition.X + 147, lastGesturePosition.Y + 6 + ), new Vector2( + lastGesturePosition.X + 147, lastGesturePosition.Y + 26 + ), new Vector2( + lastGesturePosition.X + 162, lastGesturePosition.Y + 16 + ), lastGesture == Gesture.PinchOut ? Color.Orange : Color.Gray); + DrawTriangle(new Vector2( + lastGesturePosition.X + 125, lastGesturePosition.Y + 33 + ), new Vector2( + lastGesturePosition.X + 125, lastGesturePosition.Y + 53 + ), new Vector2( + lastGesturePosition.X + 140, lastGesturePosition.Y + 43 + ), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray); + DrawTriangle(new Vector2( + lastGesturePosition.X + 144, lastGesturePosition.Y + 43 + ), new Vector2( + lastGesturePosition.X + 159, lastGesturePosition.Y + 53 + ), new Vector2( + lastGesturePosition.X + 159, lastGesturePosition.Y + 33 + ), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray); + for (i = 0; i < 4; i++) + { + DrawCircle((int)lastGesturePosition.X + 180, (int)lastGesturePosition.Y + 7 + i * 15, 5, + touchCount <= i ? Color.LightGray : gestureColor); + } + + // Draw gesture log + DrawText("Log", (int)gestureLogPosition.X, (int)gestureLogPosition.Y, 20, Color.Black); + + // Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle) + for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) + { + DrawText(gestureLog[ii], (int)gestureLogPosition.X, (int)gestureLogPosition.Y + 410 - i * 20, 20, + (i == 0 ? gestureColor : Color.LightGray)); + } + + Color logButton1Color, logButton2Color; + switch (logMode) + { + case 3: + logButton1Color = Color.Maroon; + logButton2Color = Color.Maroon; + break; + case 2: + logButton1Color = Color.Gray; + logButton2Color = Color.Maroon; + break; + case 1: + logButton1Color = Color.Maroon; + logButton2Color = Color.Gray; + break; + default: + logButton1Color = Color.Gray; + logButton2Color = Color.Gray; + break; + } + + DrawRectangleRec(logButton1, logButton1Color); + DrawText("Hide", (int)logButton1.X + 7, (int)logButton1.Y + 3, 10, Color.White); + DrawText("Repeat", (int)logButton1.X + 7, (int)logButton1.Y + 13, 10, Color.White); + DrawRectangleRec(logButton2, logButton2Color); + DrawText("Hide", (int)logButton1.X + 62, (int)logButton1.Y + 3, 10, Color.White); + DrawText("Hold", (int)logButton1.X + 62, (int)logButton1.Y + 13, 10, Color.White); + + // Draw protractor + DrawText("Angle", (int)protractorPosition.X + 55, (int)protractorPosition.Y + 76, 10, Color.Black); + + // Note: Official it's using raylibs functions for string manipulation. But in C# it will end up in an unsafe handling. + string angleString = currentAngleDegrees.ToString("F3"); + int angleStringDot = angleString.IndexOf('.'); + string angleStringTrim = angleString.Substring(0, angleStringDot + 3); + + DrawText(angleStringTrim, (int)protractorPosition.X + 55, (int)protractorPosition.Y + 92, 20, gestureColor); + DrawCircleV(protractorPosition, 80.0f, Color.White); + DrawLineEx(new Vector2( + protractorPosition.X - 90, protractorPosition.Y + ), new Vector2( + protractorPosition.X + 90, protractorPosition.Y + ), 3.0f, Color.LightGray); + DrawLineEx(new Vector2( + protractorPosition.X, protractorPosition.Y - 90 + ), new Vector2( + protractorPosition.X, protractorPosition.Y + 90 + ), 3.0f, Color.LightGray); + DrawLineEx(new Vector2( + protractorPosition.X - 80, protractorPosition.Y - 45 + ), new Vector2( + protractorPosition.X + 80, protractorPosition.Y + 45 + ), 3.0f, Color.Green); + DrawLineEx(new Vector2( + protractorPosition.X - 80, protractorPosition.Y + 45 + ), new Vector2( + protractorPosition.X + 80, protractorPosition.Y - 45 + ), 3.0f, Color.Green); + DrawText("0", (int)protractorPosition.X + 96, (int)protractorPosition.Y - 9, 20, Color.Black); + DrawText("30", (int)protractorPosition.X + 74, (int)protractorPosition.Y - 68, 20, Color.Black); + DrawText("90", (int)protractorPosition.X - 11, (int)protractorPosition.Y - 110, 20, Color.Black); + DrawText("150", (int)protractorPosition.X - 100, (int)protractorPosition.Y - 68, 20, Color.Black); + DrawText("180", (int)protractorPosition.X - 124, (int)protractorPosition.Y - 9, 20, Color.Black); + DrawText("210", (int)protractorPosition.X - 100, (int)protractorPosition.Y + 50, 20, Color.Black); + DrawText("270", (int)protractorPosition.X - 18, (int)protractorPosition.Y + 92, 20, Color.Black); + DrawText("330", (int)protractorPosition.X + 72, (int)protractorPosition.Y + 50, 20, Color.Black); + if (currentAngleDegrees != 0.0f) + { + DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor); + } + + // Draw touch and mouse pointer points + if (currentGesture != Gesture.None) + { + if (touchCount != 0) + { + for (i = 0; i < touchCount; i++) + { + DrawCircleV(touchPosition[i], 50.0f, Fade(gestureColor, 0.5f)); + DrawCircleV(touchPosition[i], 5.0f, gestureColor); + } + + if (touchCount == 2) + { + DrawLineEx(touchPosition[0], touchPosition[1], (((int)currentGesture == 512) ? 8.0f : 12.0f), + gestureColor); + } + } + else + { + DrawCircleV(mousePosition, 35.0f, Fade(gestureColor, 0.5f)); + DrawCircleV(mousePosition, 5.0f, gestureColor); + } + } + + EndDrawing(); + //-------------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; + } + + static string GetGestureName(int gesture) + { + switch (gesture) + { + case 0: return "None"; break; + case 1: return "Tap"; break; + case 2: return "Double Tap"; break; + case 4: return "Hold"; break; + case 8: return "Drag"; break; + case 16: return "Swipe Right"; break; + case 32: return "Swipe Left"; break; + case 64: return "Swipe Up"; break; + case 128: return "Swipe Down"; break; + case 256: return "Pinch In"; break; + case 512: return "Pinch Out"; break; + default: return "Unknown"; break; + } + } + +// Get color for gesture value + static Color GetGestureColor(int gesture) + { + switch (gesture) + { + case 0: return Color.Black; break; + case 1: return Color.Blue; break; + case 2: return Color.SkyBlue; break; + case 4: return Color.Black; break; + case 8: return Color.Lime; break; + case 16: return Color.Red; break; + case 32: return Color.Red; break; + case 64: return Color.Red; break; + case 128: return Color.Red; break; + case 256: return Color.Violet; break; + case 512: return Color.Orange; break; + default: return Color.Black; break; + } + } +} diff --git a/Examples/Core/InputKeys.cs b/Examples/Core/InputKeys.cs index 252f09d..56e7823 100644 --- a/Examples/Core/InputKeys.cs +++ b/Examples/Core/InputKeys.cs @@ -1,11 +1,15 @@ /******************************************************************************************* * -* raylib [core] example - Keyboard input +* raylib [core] example - input keys * -* This example has been created using raylib 1.0 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★☆☆☆] 1/4 * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.0, last time updated with raylib 1.0 +* +* 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) 2014-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/Examples/Core/InputMouse.cs b/Examples/Core/InputMouse.cs index 6d4ae15..6207883 100644 --- a/Examples/Core/InputMouse.cs +++ b/Examples/Core/InputMouse.cs @@ -1,14 +1,19 @@ /******************************************************************************************* * -* raylib [core] example - Mouse input +* raylib [core] example - input mouse * -* This example has been created using raylib 1.0 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★☆☆☆] 1/4 * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.0, last time updated with raylib 5.5 +* +* 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) 2014-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ + using System.Numerics; using static Raylib_cs.Raylib; @@ -36,6 +41,19 @@ public class InputMouse { // Update //---------------------------------------------------------------------------------- + + if (IsKeyPressed(KeyboardKey.H)) + { + if (IsCursorHidden()) + { + ShowCursor(); + } + else + { + HideCursor(); + } + } + ballPosition = GetMousePosition(); if (IsMouseButtonPressed(MouseButton.Left)) @@ -50,6 +68,18 @@ public class InputMouse { ballColor = Color.DarkBlue; } + else if (IsMouseButtonPressed(MouseButton.Extra)) + { + ballColor = Color.Yellow; + } + else if (IsMouseButtonPressed(MouseButton.Forward)) + { + ballColor = Color.Orange; + } + else if (IsMouseButtonPressed(MouseButton.Back)) + { + ballColor = Color.Beige; + } //---------------------------------------------------------------------------------- // Draw @@ -60,6 +90,16 @@ public class InputMouse DrawCircleV(ballPosition, 40, ballColor); DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, Color.DarkGray); + DrawText("Press 'H' to toggle cursor visibility", 10, 30, 20, Color.DarkGray); + + if (IsCursorHidden()) + { + DrawText("CURSOR HIDDEN", 20, 60, 20, Color.Red); + } + else + { + DrawText("CURSOR VISIBLE", 20, 60, 20, Color.Lime); + } EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/Examples/Core/InputMouseWheel.cs b/Examples/Core/InputMouseWheel.cs index fe144ec..d0c4c5f 100644 --- a/Examples/Core/InputMouseWheel.cs +++ b/Examples/Core/InputMouseWheel.cs @@ -1,11 +1,15 @@ /******************************************************************************************* * -* raylib [core] examples - Mouse wheel input +* raylib [core] example - input mouse wheel * -* This test has been created using raylib 1.1 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★☆☆☆] 1/4 * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Example originally created with raylib 1.1, last time updated with raylib 1.3 +* +* 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) 2014-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -24,10 +28,8 @@ public class InputMouseWheel InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse wheel"); - int boxPositionY = screenHeight / 2 - 40; - - // Scrolling speed in pixels - int scrollSpeed = 4; + int boxPositionY = screenHeight/2 - 40; + int scrollSpeed = 4; // Scrolling speed in pixels SetTargetFPS(60); //-------------------------------------------------------------------------------------- diff --git a/Examples/Core/InputMultitouch.cs b/Examples/Core/InputMultitouch.cs index 266d198..f075bd8 100644 --- a/Examples/Core/InputMultitouch.cs +++ b/Examples/Core/InputMultitouch.cs @@ -1,13 +1,17 @@ /******************************************************************************************* * -* raylib [core] example - Input multitouch +* raylib [core] example - input multitouch * -* This example has been created using raylib 2.1 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★☆☆☆] 1/4 +* +* Example originally created with raylib 2.1, last time updated with raylib 2.5 * * Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5) * -* Copyright (c) 2019 Berni (@Berni8k) and 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) 2019-2025 Berni (@Berni8k) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/Examples/Core/InputVirtualControls.cs b/Examples/Core/InputVirtualControls.cs new file mode 100644 index 0000000..be1b0aa --- /dev/null +++ b/Examples/Core/InputVirtualControls.cs @@ -0,0 +1,216 @@ +/******************************************************************************************* + * + * raylib [core] example - input virtual controls + * + * Example complexity rating: [★★☆☆] 2/4 + * + * Example originally created with raylib 5.0, last time updated with raylib 5.0 + * + * Example contributed by GreenSnakeLinux (@GreenSnakeLinux), + * reviewed by Ramon Santamaria (@raysan5), oblerion (@oblerion) and danilwhale (@danilwhale) + * + * 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) 2024-2025 GreenSnakeLinux (@GreenSnakeLinux) and Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + +using System.Numerics; + +namespace Examples.Core; + +using static Raylib_cs.Raylib; + +public enum PadButton +{ + BUTTON_NONE = -1, + BUTTON_UP, + BUTTON_LEFT, + BUTTON_RIGHT, + BUTTON_DOWN, + BUTTON_MAX +} + +public class InputVirtualControls +{ + public static int Main() + { + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls"); + + Vector2 padPosition = new Vector2(100, 350); + float buttonRadius = 30; + + Vector2[] buttonPositions = + [ + new Vector2( + padPosition.X,padPosition.Y - buttonRadius * 1.5f + ), // Up + new Vector2( + padPosition.X - buttonRadius * 1.5f, padPosition.Y + ), // Left + new Vector2( + padPosition.X + buttonRadius * 1.5f, padPosition.Y + ), // Right + new Vector2( + padPosition.X, padPosition.Y + buttonRadius * 1.5f + ) // Down + ]; + + Vector2[][] arrowTris = [ + // Up + [ + new Vector2( + buttonPositions[0].X, buttonPositions[0].Y - 12 + ), + new Vector2( + buttonPositions[0].X - 9, buttonPositions[0].Y + 9 + ), + new Vector2( + buttonPositions[0].X + 9, buttonPositions[0].Y + 9 + ) + ], + // Left + [ + new Vector2( + buttonPositions[1].X + 9, buttonPositions[1].Y - 9 + ), + new Vector2( + buttonPositions[1].X - 12, buttonPositions[1].Y + ), + new Vector2( + buttonPositions[1].X + 9, buttonPositions[1].Y + 9 + ) + ], + // Right + [ + new Vector2( + buttonPositions[2].X + 12, buttonPositions[2].Y + ), + new Vector2( + buttonPositions[2].X - 9, buttonPositions[2].Y - 9 + ), + new Vector2( + buttonPositions[2].X - 9, buttonPositions[2].Y + 9 + ) + ], + // Down + [ + new Vector2( + buttonPositions[3].X - 9, buttonPositions[3].Y - 9 + ), + new Vector2( + buttonPositions[3].X, buttonPositions[3].Y + 12 + ), + new Vector2( + buttonPositions[3].X + 9, buttonPositions[3].Y - 9 + ) + ] + ] + ; + + Color[] buttonLabelColors = [ + Color.Yellow, // Up + Color.Blue, // Left + Color.Red, // Right + Color.Green // Down + ]; + + int pressedButton = (int)PadButton.BUTTON_NONE; + Vector2 inputPosition = new Vector2( 0, 0 ); + + Vector2 playerPosition = new Vector2( (float)screenWidth / 2, (float)screenHeight / 2 ); + float playerSpeed = 75f; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //-------------------------------------------------------------------------- + if ((GetTouchPointCount() > 0)) + { + inputPosition = GetTouchPosition(0); // Use touch position + } + else + { + inputPosition = GetMousePosition(); // Use mouse position + } + + // Reset pressed button to none + pressedButton = (int)PadButton.BUTTON_NONE; + + // Make sure user is pressing left mouse button if they're from desktop + if ((GetTouchPointCount() > 0) || + ((GetTouchPointCount() == 0) && IsMouseButtonDown(MouseButton.Left))) + { + // Find nearest D-Pad button to the input position + for (int i = 0; i < (int)PadButton.BUTTON_MAX; i++) + { + float distX = MathF.Abs(buttonPositions[i].X - inputPosition.X); + float distY = MathF.Abs(buttonPositions[i].Y - inputPosition.Y); + + if ((distX + distY < buttonRadius)) + { + pressedButton = i; + break; + } + } + } + + // Move player according to pressed button + switch ((PadButton)pressedButton) + { + case PadButton.BUTTON_UP: playerPosition.Y -= playerSpeed * GetFrameTime(); break; + case PadButton.BUTTON_LEFT: playerPosition.X -= playerSpeed * GetFrameTime(); break; + case PadButton.BUTTON_RIGHT: playerPosition.X += playerSpeed * GetFrameTime(); break; + case PadButton.BUTTON_DOWN: playerPosition.Y += playerSpeed * GetFrameTime(); break; + default: break; + } + + ; + //-------------------------------------------------------------------------- + + // Draw + //-------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(Color.RayWhite); + + // Draw world + DrawCircleV(playerPosition, 50, Color.Maroon); + + // Draw GUI + for (int i = 0; i < (int)PadButton.BUTTON_MAX; i++) + { + DrawCircleV(buttonPositions[i], buttonRadius, (i == pressedButton) ? Color.DarkGray : Color.Black); + + DrawTriangle( + arrowTris[i][0], + arrowTris[i][1], + arrowTris[i][2], + buttonLabelColors[i] + ); + } + + DrawText("move the player with D-Pad buttons", 10, 10, 20, Color.DarkGray); + + EndDrawing(); + //-------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; + } +} diff --git a/Examples/Models/AnimationDemo.cs b/Examples/Models/LoadingIqm.cs similarity index 65% rename from Examples/Models/AnimationDemo.cs rename to Examples/Models/LoadingIqm.cs index 708f753..6905544 100644 --- a/Examples/Models/AnimationDemo.cs +++ b/Examples/Models/LoadingIqm.cs @@ -1,28 +1,31 @@ /******************************************************************************************* * -* raylib [models] example - Load 3d model with animations and play them +* raylib [models] example - loading iqm * -* This example has been created using raylib 2.5 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 2.5, last time updated with raylib 3.5 * * Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5) * -* Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5) +* NOTES: To export an IQM model from blender, make sure it is not posed, the vertices need +* to be in the same position as they would be in edit mode and the scale of the models is +* set to 0; scaling can be set from the export menu * -******************************************************************************************** +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software * -* To export a model from blender, make sure it is not posed, the vertices need to be in the -* same position as they would be in edit mode. -* and that the scale of your models is set to 0. Scaling can be done from the export menu. +* Copyright (c) 2019-2025 Culacant (@culacant) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ using System.Numerics; +using System.Runtime.InteropServices; using static Raylib_cs.Raylib; namespace Examples.Models; -public class AnimationDemo +public class LoadingIqm { public unsafe static int Main() { @@ -36,20 +39,22 @@ public class AnimationDemo // Define the camera to look into our 3d world Camera3D camera = new(); camera.Position = new Vector3(10.0f, 10.0f, 10.0f); - camera.Target = new Vector3(0.0f, 0.0f, 0.0f); + camera.Target = new Vector3(0.0f, 4.0f, 0.0f); camera.Up = new Vector3(0.0f, 1.0f, 0.0f); camera.FovY = 45.0f; camera.Projection = CameraProjection.Perspective; Model model = LoadModel("resources/models/iqm/guy.iqm"); Texture2D texture = LoadTexture("resources/models/iqm/guytex.png"); - Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture); - + Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture); Vector3 position = new(0.0f, 0.0f, 0.0f); + // Load animation data - int animsCount = 0; - var anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", ref animsCount); - int animFrameCounter = 0; + var anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm"); + + // Animation playing variables + int animIndex = 0; + float animCurrentFrame = 0.0f; SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -59,17 +64,15 @@ public class AnimationDemo { // Update //---------------------------------------------------------------------------------- - UpdateCamera(ref camera, CameraMode.Free); + UpdateCamera(ref camera, CameraMode.Orbital); // Play animation when spacebar is held down - if (IsKeyDown(KeyboardKey.Space)) + animCurrentFrame += 1.0f; + UpdateModelAnimation(model, anims[0], animCurrentFrame); + + if (animCurrentFrame >= anims[0].KeyFrameCount) { - animFrameCounter++; - UpdateModelAnimation(model, anims[0], animFrameCounter); - if (animFrameCounter >= anims[0].FrameCount) - { - animFrameCounter = 0; - } + animCurrentFrame = 0; } //---------------------------------------------------------------------------------- @@ -89,17 +92,10 @@ public class AnimationDemo Color.White ); - for (int i = 0; i < model.BoneCount; i++) - { - var framePoses = anims[0].FramePoses; - DrawCube(framePoses[animFrameCounter][i].Translation, 0.2f, 0.2f, 0.2f, Color.Red); - } - DrawGrid(10, 1.0f); EndMode3D(); - - DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, Color.Maroon); + DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 10, 20, Color.Maroon); DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, Color.Gray); EndDrawing(); @@ -109,9 +105,7 @@ public class AnimationDemo // De-Initialization //-------------------------------------------------------------------------------------- UnloadTexture(texture); - - UnloadModelAnimations(anims, animsCount); - + UnloadModelAnimations(anims); UnloadModel(model); CloseWindow(); diff --git a/Examples/Program.cs b/Examples/Program.cs index ba32773..27e8996 100644 --- a/Examples/Program.cs +++ b/Examples/Program.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics; using Examples.Core; using Examples.Shapes; @@ -34,6 +33,9 @@ public class ExampleList public static ExampleInfo[] AllExamples = new[] { // Core + new ExampleInfo("DeltaTime", DeltaTime.Main), + new ExampleInfo("InputGesturesTestBed", InputGesturesTestBed.Main), + new ExampleInfo("InputVirtualControls", InputVirtualControls.Main), new ExampleInfo("Camera2dPlatformer", Camera2dPlatformer.Main), new ExampleInfo("Camera2dDemo", Camera2dDemo.Main), new ExampleInfo("Camera3dFirstPerson", Camera3dFirstPerson.Main), @@ -110,7 +112,7 @@ public class ExampleList new ExampleInfo("WritingAnim", WritingAnim.Main), // Models - new ExampleInfo("AnimationDemo", AnimationDemo.Main), + new ExampleInfo("LoadingIqm", LoadingIqm.Main), new ExampleInfo("BillboardDemo", BillboardDemo.Main), new ExampleInfo("BoxCollisions", BoxCollisions.Main), new ExampleInfo("CubicmapDemo", CubicmapDemo.Main), diff --git a/Examples/resources/symbola.png b/Examples/resources/symbola.png deleted file mode 100644 index e942606..0000000 Binary files a/Examples/resources/symbola.png and /dev/null differ diff --git a/Raylib-cs/interop/Raylib.cs b/Raylib-cs/interop/Raylib.cs index aa0f962..d9b6a1d 100644 --- a/Raylib-cs/interop/Raylib.cs +++ b/Raylib-cs/interop/Raylib.cs @@ -820,32 +820,32 @@ public static unsafe partial class Raylib /// Rename file (if exists) [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileRename(sbyte* fileName, sbyte* fileRename); + public static partial int FileRename(sbyte* fileName, sbyte* fileRename); /// Remove file (if exists) [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileRemove(sbyte* fileName); + public static partial int FileRemove(sbyte* fileName); /// Copy file from one path to another, dstPath created if it doesn't exist [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileCopy(sbyte* srcPath, sbyte* dstPath); + public static partial int FileCopy(sbyte* srcPath, sbyte* dstPath); /// Move file from one path to another, dstPath created if it doesn't exist [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileMove(sbyte* srcPath, sbyte* dstPath); + public static partial int FileMove(sbyte* srcPath, sbyte* dstPath); /// Replace text in an existing file [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileTextReplace(sbyte* fileName, sbyte* search, sbyte* replacement); + public static partial int FileTextReplace(sbyte* fileName, sbyte* search, sbyte* replacement); /// Find text in existing file [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial CBool FileTextFindIndex(sbyte* fileName, sbyte* search); + public static partial int FileTextFindIndex(sbyte* fileName, sbyte* search); /// Check if file exists [LibraryImport(NativeLibName)] @@ -962,7 +962,7 @@ public static unsafe partial class Raylib [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial FilePathList GetDirectoryFileCount(sbyte* dirPath); - /// Get the file count in a directory + /// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" [LibraryImport(NativeLibName)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial FilePathList GetDirectoryFileCountEx(sbyte* dirPath, sbyte* filter, CBool scanSubdirs); diff --git a/Raylib-cs/types/Mesh.cs b/Raylib-cs/types/Mesh.cs index 10c389c..f4bf087 100644 --- a/Raylib-cs/types/Mesh.cs +++ b/Raylib-cs/types/Mesh.cs @@ -248,4 +248,6 @@ public unsafe struct Mesh public const int VboIdIndexIndices = 6; #endregion + + } diff --git a/Raylib-cs/types/Model.cs b/Raylib-cs/types/Model.cs index 945db48..16bac95 100644 --- a/Raylib-cs/types/Model.cs +++ b/Raylib-cs/types/Model.cs @@ -19,6 +19,14 @@ public unsafe struct BoneInfo /// Bone parent /// public int Parent; + + public string NameToString() + { + fixed (sbyte* name = Name) + { + return Utf8StringUtils.GetUTF8String(name); + } + } } /// @@ -41,6 +49,16 @@ public unsafe struct ModelSkeleton /// Bones base transformation (Transform[]) /// public Transform* ModelAnimPose; + + public Span ModelAnimPoseAsSpan() + { + return new Span(ModelAnimPose, BoneCount); + } + + public Span BonesAsSpan() + { + return new Span(Bones, BoneCount); + } } // Note: @@ -84,29 +102,52 @@ public unsafe struct Model public int* MeshMaterial; /// - /// Number of bones + /// Skeleton for animation /// - public int BoneCount; + ModelSkeleton Skeleton; - //TODO: Span /// - /// Bones information (skeleton, BoneInfo *) + /// Current animation pose (Transform[]) /// - public BoneInfo* Bones; + public Transform* CurrentPose; - //TODO: Span /// - /// Bones base transformation (pose, Transform *) + /// Bones animated transformation matrices /// - public Transform* BindPose; + public Matrix4x4* BoneMatrices; + + public Span BoneMatricesAsSpan() + { + return new Span(BoneMatrices, Skeleton.BoneCount); + } + + public Span CurrentPoseAsSpan() + { + return new Span(CurrentPose, Skeleton.BoneCount); + } + + public Span MeshMaterialAsSpan() + { + return new Span(MeshMaterial, MeshCount); + } + + public Span MeshesAsSpan() + { + return new Span(Meshes, MeshCount); + } } /// -/// Model animation +/// ModelAnimation, contains a full animation sequence /// [StructLayout(LayoutKind.Sequential)] public unsafe struct ModelAnimation { + /// + /// Animation name (char[32]) + /// + public fixed sbyte Name[32]; + /// /// Number of bones /// @@ -115,61 +156,23 @@ public unsafe struct ModelAnimation /// /// Number of animation frames /// - public readonly int FrameCount; + public readonly int KeyFrameCount; /// - /// Bones information (skeleton, BoneInfo *) + /// Animation sequence keyframe poses [keyframe][pose] /// - public readonly BoneInfo* Bones; + public Transform* KeyframePoses; - /// - public readonly ReadOnlySpan BoneInfo => new ReadOnlySpan(Bones, BoneCount); - - /// - /// Poses array by frame (Transform **) - /// - public readonly Transform** FramePoses; - - /// - /// Animation name (char[32]) - /// - public fixed sbyte Name[32]; - - /// - public readonly FramePosesCollection FramePosesColl => new FramePosesCollection(FramePoses, FrameCount, BoneCount); - - public readonly struct FramePosesCollection + public Span KeyFramePosesAsSpan() { - readonly Transform** _framePoses; + return new Span(KeyframePoses, KeyFrameCount); + } - readonly int _frameCount; - - readonly int _boneCount; - - public readonly FramePoses this[int index] => new FramePoses(_framePoses[index], _boneCount); - - public readonly Transform this[int index1, int index2] => new FramePoses(_framePoses[index1], _boneCount)[index2]; - - internal FramePosesCollection(Transform** framePoses, int frameCount, int boneCount) + public string NameToString() + { + fixed (sbyte* name = Name) { - this._framePoses = framePoses; - this._frameCount = frameCount; - this._boneCount = boneCount; + return Utf8StringUtils.GetUTF8String(name); } } } - -public readonly unsafe struct FramePoses -{ - readonly Transform* _poses; - - readonly int _count; - - public readonly ref Transform this[int index] => ref _poses[index]; - - internal FramePoses(Transform* poses, int count) - { - this._poses = poses; - this._count = count; - } -} diff --git a/Raylib-cs/types/Raylib.Utils.cs b/Raylib-cs/types/Raylib.Utils.cs index eb12e24..859b85b 100644 --- a/Raylib-cs/types/Raylib.Utils.cs +++ b/Raylib-cs/types/Raylib.Utils.cs @@ -1085,6 +1085,24 @@ public static unsafe partial class Raylib } } + /// Load model animations from file + public static Span LoadModelAnimations(string fileName) + { + using AnsiBuffer str1 = fileName.ToAnsiBuffer(); + int count; + + ModelAnimation* result = LoadModelAnimations(str1.AsPointer(), &count); + return new Span(result, count); + } + + public static void UnloadModelAnimations(Span animations) + { + fixed (ModelAnimation* ptr = animations) + { + UnloadModelAnimations(ptr, animations.Length); + } + } + /// Compute mesh tangents public static void GenMeshTangents(ref Mesh mesh) { @@ -1549,6 +1567,155 @@ public static unsafe partial class Raylib SaveFileText(fileBuffer.AsPointer(), textBuffer.AsPointer()); } + /// Rename file (if exists) + public static int FileRename(string filename, string fileRename) + { + + using AnsiBuffer fileBuffer = filename.ToAnsiBuffer(); + using AnsiBuffer textBuffer = fileRename.ToAnsiBuffer(); + return FileRename(fileBuffer.AsPointer(), textBuffer.AsPointer()); + } + + /// Remove file (if exists) + public static int FileRemove(string filename) + { + using AnsiBuffer fileBuffer = filename.ToAnsiBuffer(); + return FileRemove(fileBuffer.AsPointer()); + } + + /// Copy file from one path to another, dstPath created if it doesn't exist + public static int FileCopy(string srcPath, string dstPath) + { + using AnsiBuffer srcBuffer = srcPath.ToAnsiBuffer(); + using AnsiBuffer dstBuffer = dstPath.ToAnsiBuffer(); + return FileCopy(srcBuffer.AsPointer(), dstBuffer.AsPointer()); + } + + /// Move file from one path to another, dstPath created if it doesn't exist + public static int FileMove(string srcPath, string dstPath) + { + using AnsiBuffer srcBuffer = srcPath.ToAnsiBuffer(); + using AnsiBuffer dstBuffer = dstPath.ToAnsiBuffer(); + return FileMove(srcBuffer.AsPointer(), dstBuffer.AsPointer()); + } + + /// Replace text in an existing file + public static int FileTextReplace(string fileName, string search, string replacement) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + using AnsiBuffer searchBuffer = search.ToAnsiBuffer(); + using AnsiBuffer replaceBuffer = replacement.ToAnsiBuffer(); + return FileTextReplace(fileBuffer.AsPointer(), searchBuffer.AsPointer(), replaceBuffer.AsPointer()); + } + + /// Find text in existing file + public static int FileTextFindIndex(string fileName, string search) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + using AnsiBuffer searchBuffer = search.ToAnsiBuffer(); + return FileTextFindIndex(fileBuffer.AsPointer(), searchBuffer.AsPointer()); + } + + /// Check if file exists + public static CBool FileExists(string fileName) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + return FileExists(fileBuffer.AsPointer()); + } + + /// Check if a directory path exists + public static CBool DirectoryExists(string dirPath) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + return DirectoryExists(dirBuffer.AsPointer()); + } + + /// Get file length in bytes + public static int GetFileLength(string fileName) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + return GetFileLength(fileBuffer.AsPointer()); + } + + /// Get string to extension for a filename string (includes dot: '.png') + public static string GetFileExtension(string fileName) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + return new string(GetFileExtension(fileBuffer.AsPointer())); + } + + /// Get string to filename for a path string + public static string GetFileName(string fileName) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + return new string(GetFileName(fileBuffer.AsPointer())); + } + + /// Get filename string without extension + public static string GetFileNameWithoutExt(string fileName) + { + using AnsiBuffer fileBuffer = fileName.ToAnsiBuffer(); + return new string(GetFileNameWithoutExt(fileBuffer.AsPointer())); + } + + /// Get full path for a given fileName with path + public static string GetDirectoryPath(string filePath) + { + using AnsiBuffer fileBuffer = filePath.ToAnsiBuffer(); + return new string(GetDirectoryPath(fileBuffer.AsPointer())); + } + + /// Get previous directory path for a given path + public static string GetPrevDirectoryPath(string dirPath) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + return new string(GetPrevDirectoryPath(dirBuffer.AsPointer())); + } + + /// Get current working directory + public static string GetWorkingDirectoryAsString() + { + return new string(GetWorkingDirectory()); + } + + /// Get the directory of the running application + public static string GetApplicationDirectoryAsString() + { + return new string(GetApplicationDirectory()); + } + + /// Change working directory, return true on success + public static CBool ChangeDirectory(string dirPath) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + return ChangeDirectory(dirBuffer.AsPointer()); + } + + /// Check if a given path is a file or a directory + public static CBool IsPathFile(string path) + { + using AnsiBuffer pathBuffer = path.ToAnsiBuffer(); + return IsPathFile(pathBuffer.AsPointer()); + } + + /// Load directory filepaths + public static FilePathList LoadDirectoryFiles(string dirPath, out int count) + { + using AnsiBuffer dirBuffer = dirPath.ToAnsiBuffer(); + int c = 0; + var result = LoadDirectoryFiles(dirBuffer.AsPointer(), &c); + count = c; + return result; + } + + /// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" + public static FilePathList LoadDirectoryFilesEx(string basePath, string filter, CBool scanSubDirs) + { + using AnsiBuffer baseBuffer = basePath.ToAnsiBuffer(); + using AnsiBuffer filterBuffer = filter.ToAnsiBuffer(); + return LoadDirectoryFilesEx(baseBuffer.AsPointer(), filterBuffer.AsPointer(), scanSubDirs); + } + /// /// Loads text from a file, reads it, saves it, unloads the file, and returns the loaded text. /// @@ -1569,4 +1736,5 @@ public static unsafe partial class Raylib center.Y = GetScreenHeight() / 2.0f; return center; } + } diff --git a/Raylib-cs/types/native/FilePathList.cs b/Raylib-cs/types/native/FilePathList.cs index 9c50a3b..206b9a2 100644 --- a/Raylib-cs/types/native/FilePathList.cs +++ b/Raylib-cs/types/native/FilePathList.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.InteropServices; namespace Raylib_cs; diff --git a/Raylib-cs/types/native/Utf8Buffer.cs b/Raylib-cs/types/native/Utf8Buffer.cs index 3acb824..98d9aaa 100644 --- a/Raylib-cs/types/native/Utf8Buffer.cs +++ b/Raylib-cs/types/native/Utf8Buffer.cs @@ -21,6 +21,11 @@ public readonly ref struct Utf8Buffer return (sbyte*)_data.ToPointer(); } + public unsafe byte* AsBytePointer() + { + return (byte*)_data.ToPointer(); + } + public void Dispose() { Marshal.ZeroFreeCoTaskMemUTF8(_data);