feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style
This commit is contained in:
parent
6aa91e3097
commit
f804ab7773
234 changed files with 38997 additions and 10578 deletions
263
Examples/Audio/AmpEnvelope.cs
Normal file
263
Examples/Audio/AmpEnvelope.cs
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - amp envelope
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Arbinda Rizki Muhammad (@arbipink) 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) 2026 Arbinda Rizki Muhammad (@arbipink)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public unsafe partial class AmpEnvelope : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
// Wave state
|
||||
private enum ADSRState
|
||||
{
|
||||
Idle,
|
||||
Attack,
|
||||
Decay,
|
||||
Sustain,
|
||||
Release
|
||||
}
|
||||
|
||||
// Grouping all ADSR parameters and state into a struct
|
||||
private struct Envelope
|
||||
{
|
||||
public float AttackTime;
|
||||
public float DecayTime;
|
||||
public float SustainLevel;
|
||||
public float ReleaseTime;
|
||||
public float CurrentValue;
|
||||
public ADSRState State;
|
||||
}
|
||||
|
||||
public string Name => "Audio / Amp Envelope";
|
||||
|
||||
public string Title => "raylib [audio] example - amp envelope";
|
||||
|
||||
private float[] buffer;
|
||||
private AudioStream stream;
|
||||
private float audioTime;
|
||||
private Envelope env;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
buffer = new float[BUFFER_SIZE];
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
|
||||
// Init Phase
|
||||
audioTime = 0.0f;
|
||||
|
||||
// Initialize the struct
|
||||
env = new Envelope
|
||||
{
|
||||
AttackTime = 1.0f,
|
||||
DecayTime = 1.0f,
|
||||
SustainLevel = 0.5f,
|
||||
ReleaseTime = 1.0f,
|
||||
CurrentValue = 0.0f,
|
||||
State = ADSRState.Idle
|
||||
};
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space)) env.State = ADSRState.Attack;
|
||||
|
||||
if (IsKeyReleased(KeyboardKey.Space) && (env.State != ADSRState.Idle)) env.State = ADSRState.Release;
|
||||
|
||||
if (IsAudioStreamProcessed(stream))
|
||||
{
|
||||
if ((env.State != ADSRState.Idle) || (env.CurrentValue > 0.0f))
|
||||
{
|
||||
for (int i = 0; i < BUFFER_SIZE; i++)
|
||||
{
|
||||
UpdateEnvelope(ref env);
|
||||
FillAudioBuffer(i, buffer, env.CurrentValue, ref audioTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear buffer if silent to avoid looping noise
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) buffer[i] = 0;
|
||||
audioTime = 0.0f;
|
||||
}
|
||||
|
||||
fixed (float* bufferPtr = buffer)
|
||||
{
|
||||
UpdateAudioStream(stream, bufferPtr, BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsAudioStreamPlaying(stream)) PlayAudioStream(stream);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// NOTE: raygui is not bound in raylib-cs, so the sliders below are left as reference.
|
||||
// The envelope keeps its default parameters (Attack/Decay/Release = 1.0s, Sustain = 0.5).
|
||||
//GuiSliderBar(new Rectangle( 100, 60, 400, 30 ), "Attack (s)", TextFormat("%2.2fs", env.AttackTime), ref env.AttackTime, 0.1f, 3.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 100, 400, 30 ), "Decay (s)", TextFormat("%2.2fs", env.DecayTime), ref env.DecayTime, 0.1f, 3.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 140, 400, 30 ), "Sustain", TextFormat("%2.2f", env.SustainLevel), ref env.SustainLevel, 0.0f, 1.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 180, 400, 30 ), "Release (s)", TextFormat("%2.2fs", env.ReleaseTime), ref env.ReleaseTime, 0.1f, 3.0f);
|
||||
|
||||
DrawADSRGraph(ref env, new Rectangle(100, 250, 400, 100));
|
||||
|
||||
DrawCircleV(new Vector2(520, 350 - (env.CurrentValue * 100)), 5, Color.Maroon);
|
||||
DrawText($"Current Gain: {env.CurrentValue:F2}", 535, (int)(345 - (env.CurrentValue * 100)), 10, Color.Maroon);
|
||||
|
||||
DrawText("Press SPACE to PLAY the sound!", 200, 400, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream);
|
||||
CloseAudioDevice();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
private static void FillAudioBuffer(int i, float[] buffer, float envelopeValue, ref float audioTime)
|
||||
{
|
||||
int frequency = 440;
|
||||
buffer[i] = envelopeValue * MathF.Sin(2.0f * MathF.PI * frequency * audioTime);
|
||||
audioTime += (1.0f / SAMPLE_RATE);
|
||||
}
|
||||
|
||||
private static void UpdateEnvelope(ref Envelope env)
|
||||
{
|
||||
// Calculate the time delta for ONE sample (1/44100)
|
||||
float sampleTime = 1.0f / SAMPLE_RATE;
|
||||
|
||||
switch (env.State)
|
||||
{
|
||||
case ADSRState.Attack:
|
||||
{
|
||||
env.CurrentValue += (1.0f / env.AttackTime) * sampleTime;
|
||||
if (env.CurrentValue >= 1.0f)
|
||||
{
|
||||
env.CurrentValue = 1.0f;
|
||||
env.State = ADSRState.Decay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADSRState.Decay:
|
||||
{
|
||||
env.CurrentValue -= ((1.0f - env.SustainLevel) / env.DecayTime) * sampleTime;
|
||||
if (env.CurrentValue <= env.SustainLevel)
|
||||
{
|
||||
env.CurrentValue = env.SustainLevel;
|
||||
env.State = ADSRState.Sustain;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADSRState.Sustain:
|
||||
{
|
||||
env.CurrentValue = env.SustainLevel;
|
||||
}
|
||||
break;
|
||||
case ADSRState.Release:
|
||||
{
|
||||
env.CurrentValue -= (env.SustainLevel / env.ReleaseTime) * sampleTime;
|
||||
if (env.CurrentValue <= 0.001f) // Use a small threshold to avoid infinite tail
|
||||
{
|
||||
env.CurrentValue = 0.0f;
|
||||
env.State = ADSRState.Idle;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawADSRGraph(ref Envelope env, Rectangle bounds)
|
||||
{
|
||||
DrawRectangleRec(bounds, Fade(Color.LightGray, 0.3f));
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
|
||||
// Fixed visual width for sustain stage since it's an amplitude not a time value
|
||||
float sustainWidth = 1.0f;
|
||||
|
||||
// Total time to visualize (sum of A, D, R + a padding for Sustain)
|
||||
float totalTime = env.AttackTime + env.DecayTime + sustainWidth + env.ReleaseTime;
|
||||
|
||||
float scaleX = bounds.Width / totalTime;
|
||||
float scaleY = bounds.Height;
|
||||
|
||||
Vector2 start = new Vector2(bounds.X, bounds.Y + bounds.Height);
|
||||
Vector2 peak = new Vector2(start.X + (env.AttackTime * scaleX), bounds.Y);
|
||||
Vector2 sustain = new Vector2(peak.X + (env.DecayTime * scaleX), bounds.Y + (1.0f - env.SustainLevel) * scaleY);
|
||||
Vector2 rel = new Vector2(sustain.X + (sustainWidth * scaleX), sustain.Y);
|
||||
Vector2 end = new Vector2(rel.X + (env.ReleaseTime * scaleX), bounds.Y + bounds.Height);
|
||||
|
||||
DrawLineV(start, peak, Color.SkyBlue);
|
||||
DrawLineV(peak, sustain, Color.Blue);
|
||||
DrawLineV(sustain, rel, Color.DarkBlue);
|
||||
DrawLineV(rel, end, Color.Orange);
|
||||
|
||||
DrawText("ADSR Visualizer", (int)bounds.X, (int)bounds.Y - 20, 10, Color.DarkGray);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - amp envelope");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AmpEnvelope();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
159
Examples/Audio/MixedProcessor.cs
Normal file
159
Examples/Audio/MixedProcessor.cs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - mixed processor
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by hkc (@hatkidchan) 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 hkc (@hatkidchan)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("AttachAudioMixedProcessor callback is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class MixedProcessor : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Mixed Processor";
|
||||
|
||||
public string Title => "raylib [audio] example - mixed processor";
|
||||
|
||||
private static float exponent = 1.0f; // Audio exponentiation value
|
||||
private static readonly float[] averageVolume = new float[400]; // Average volume history
|
||||
|
||||
private Music music;
|
||||
private Sound sound;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Audio processing function
|
||||
//------------------------------------------------------------------------------------
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void ProcessAudio(void* buffer, uint frames)
|
||||
{
|
||||
float* samples = (float*)buffer; // Samples internally stored as <float>s
|
||||
float average = 0.0f; // Temporary average volume
|
||||
|
||||
for (uint frame = 0; frame < frames; frame++)
|
||||
{
|
||||
float* left = &samples[frame * 2 + 0];
|
||||
float* right = &samples[frame * 2 + 1];
|
||||
|
||||
*left = MathF.Pow(MathF.Abs(*left), exponent) * ((*left < 0.0f) ? -1.0f : 1.0f);
|
||||
*right = MathF.Pow(MathF.Abs(*right), exponent) * ((*right < 0.0f) ? -1.0f : 1.0f);
|
||||
|
||||
average += MathF.Abs(*left) / frames; // accumulating average volume
|
||||
average += MathF.Abs(*right) / frames;
|
||||
}
|
||||
|
||||
// Moving history to the left
|
||||
for (int i = 0; i < 399; i++) averageVolume[i] = averageVolume[i + 1];
|
||||
|
||||
averageVolume[399] = average; // Adding last average value
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
exponent = 1.0f;
|
||||
Array.Clear(averageVolume, 0, averageVolume.Length);
|
||||
|
||||
AttachAudioMixedProcessor(&ProcessAudio);
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
sound = LoadSound("resources/audio/coin.wav");
|
||||
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Modify processing variables
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Left)) exponent -= 0.05f;
|
||||
if (IsKeyPressed(KeyboardKey.Right)) exponent += 0.05f;
|
||||
|
||||
if (exponent <= 0.5f) exponent = 0.5f;
|
||||
if (exponent >= 3.0f) exponent = 3.0f;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space)) PlaySound(sound);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawText($"EXPONENT = {exponent:F2}", 215, 180, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(199, 199, 402, 34, Color.LightGray);
|
||||
for (int i = 0; i < 400; i++)
|
||||
{
|
||||
DrawLine(201 + i, 232 - (int)(averageVolume[i] * 32), 201 + i, 232, Color.Maroon);
|
||||
}
|
||||
DrawRectangleLines(199, 199, 402, 34, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, Color.LightGray);
|
||||
DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
DetachAudioMixedProcessor(&ProcessAudio); // Disconnect audio processor
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - mixed processor");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MixedProcessor();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Module playing (streaming)
|
||||
* raylib [audio] example - module playing
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* 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 originally created with raylib 1.5, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 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) 2016-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,11 +18,20 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class ModulePlaying
|
||||
public partial class ModulePlaying : IExample
|
||||
{
|
||||
const int MaxCircles = 64;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
struct CircleWave
|
||||
private const int MaxCircles = 64;
|
||||
|
||||
public string Name => "Audio / Module Playing";
|
||||
|
||||
public string Title => "raylib [audio] example - module playing";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private struct CircleWave
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Radius;
|
||||
|
|
@ -29,20 +40,18 @@ public class ModulePlaying
|
|||
public Color Color;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
private Color[] colors;
|
||||
private CircleWave[] circles;
|
||||
private Music music;
|
||||
private float pitch;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // NOTE: Try to enable MSAA 4X
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing (streaming)");
|
||||
|
||||
InitAudioDevice();
|
||||
|
||||
Color[] colors = new Color[14] {
|
||||
colors = new Color[14] {
|
||||
Color.Orange,
|
||||
Color.Red,
|
||||
Color.Gold,
|
||||
|
|
@ -59,133 +68,163 @@ public class ModulePlaying
|
|||
Color.Beige
|
||||
};
|
||||
|
||||
// Creates ome circles for visual effect
|
||||
CircleWave[] circles = new CircleWave[MaxCircles];
|
||||
// Creates some circles for visual effect
|
||||
circles = new CircleWave[MaxCircles];
|
||||
|
||||
for (int i = MaxCircles - 1; i >= 0; i--)
|
||||
for (var i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue((int)circles[i].Radius, screenWidth - (int)circles[i].Radius);
|
||||
circles[i].Position.Y = GetRandomValue((int)circles[i].Radius, screenHeight - (int)circles[i].Radius);
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 20000.0f;
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
}
|
||||
|
||||
Music music = LoadMusicStream("resources/audio/mini1111.xm");
|
||||
music = LoadMusicStream("resources/audio/mini1111.xm");
|
||||
music.Looping = false;
|
||||
float pitch = 1.0f;
|
||||
pitch = 1.0f;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
timePlayed = 0.0f;
|
||||
pause = false;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch -= 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch += 0.01f;
|
||||
}
|
||||
|
||||
SetMusicPitch(music, pitch);
|
||||
|
||||
// Get timePlayed scaled to bar dimensions
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * (screenWidth - 40);
|
||||
|
||||
// Color circles animation
|
||||
for (var i = MaxCircles - 1; (i >= 0) && !pause; i--)
|
||||
{
|
||||
circles[i].Alpha += circles[i].Speed;
|
||||
circles[i].Radius += circles[i].Speed * 10.0f;
|
||||
|
||||
if (circles[i].Alpha > 1.0f)
|
||||
{
|
||||
circles[i].Speed *= -1;
|
||||
}
|
||||
|
||||
if (circles[i].Alpha <= 0.0f)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenWidth - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Position.Y = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenHeight - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (var i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
DrawCircleV(
|
||||
circles[i].Position,
|
||||
circles[i].Radius,
|
||||
Fade(circles[i].Color, circles[i].Alpha)
|
||||
);
|
||||
}
|
||||
|
||||
// Draw time bar
|
||||
DrawRectangle(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.LightGray);
|
||||
DrawRectangle(20, screenHeight - 20 - 12, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.Gray);
|
||||
|
||||
// Draw help instructions
|
||||
DrawRectangle(20, 20, 425, 145, Color.White);
|
||||
DrawRectangleLines(20, 20, 425, 145, Color.Gray);
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 40, 40, 20, Color.Black);
|
||||
DrawText("PRESS P TO PAUSE/RESUME", 40, 70, 20, Color.Black);
|
||||
DrawText("PRESS UP/DOWN TO CHANGE SPEED", 40, 100, 20, Color.Black);
|
||||
DrawText($"SPEED: {pitch:F6}", 40, 130, 20, Color.Maroon);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // NOTE: Try to enable MSAA 4X
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModulePlaying();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch -= 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch += 0.01f;
|
||||
}
|
||||
|
||||
SetMusicPitch(music, pitch);
|
||||
|
||||
// Get timePlayed scaled to bar dimensions
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * (screenWidth - 40);
|
||||
|
||||
// Color circles animation
|
||||
for (int i = MaxCircles - 1; (i >= 0) && !pause; i--)
|
||||
{
|
||||
circles[i].Alpha += circles[i].Speed;
|
||||
circles[i].Radius += circles[i].Speed * 10.0f;
|
||||
|
||||
if (circles[i].Alpha > 1.0f)
|
||||
{
|
||||
circles[i].Speed *= -1;
|
||||
}
|
||||
|
||||
if (circles[i].Alpha <= 0.0f)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenWidth - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Position.Y = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenHeight - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
DrawCircleV(
|
||||
circles[i].Position,
|
||||
circles[i].Radius,
|
||||
ColorAlpha(circles[i].Color, circles[i].Alpha)
|
||||
);
|
||||
}
|
||||
|
||||
// Draw time bar
|
||||
DrawRectangle(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.LightGray);
|
||||
DrawRectangle(20, screenHeight - 20 - 12, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMusicStream(music);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - IntPtr playing (streaming)
|
||||
* raylib [audio] example - music stream
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 4.2
|
||||
*
|
||||
* Copyright (c) 2015 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,90 +17,176 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class MusicStreamDemo
|
||||
public partial class MusicStreamDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Music Stream Demo";
|
||||
|
||||
public string Title => "raylib [audio] example - music stream";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private Music music;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
private float pan;
|
||||
private float volume;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
|
||||
pause = false; // Music playing paused
|
||||
|
||||
pan = 0.0f; // Default audio pan center [-1.0f..1.0f]
|
||||
SetMusicPan(music, pan);
|
||||
|
||||
volume = 0.8f; // Default audio volume [0.0f..1.0f]
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
// Set audio pan
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
pan -= 0.05f;
|
||||
if (pan < -1.0f)
|
||||
{
|
||||
pan = -1.0f;
|
||||
}
|
||||
SetMusicPan(music, pan);
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
pan += 0.05f;
|
||||
if (pan > 1.0f)
|
||||
{
|
||||
pan = 1.0f;
|
||||
}
|
||||
SetMusicPan(music, pan);
|
||||
}
|
||||
|
||||
// Set audio volume
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
volume -= 0.05f;
|
||||
if (volume < 0.0f)
|
||||
{
|
||||
volume = 0.0f;
|
||||
}
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
volume += 0.05f;
|
||||
if (volume > 1.0f)
|
||||
{
|
||||
volume = 1.0f;
|
||||
}
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
|
||||
// Get normalized time played for current music stream
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music);
|
||||
|
||||
if (timePlayed > 1.0f)
|
||||
{
|
||||
timePlayed = 1.0f; // Make sure time played is no longer than music
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawText("LEFT-RIGHT for PAN CONTROL", 320, 74, 10, Color.DarkBlue);
|
||||
DrawRectangle(300, 100, 200, 12, Color.LightGray);
|
||||
DrawRectangleLines(300, 100, 200, 12, Color.Gray);
|
||||
DrawRectangle((int)(300 + (pan + 1.0f) / 2.0f * 200 - 5), 92, 10, 28, Color.DarkGray);
|
||||
|
||||
DrawRectangle(200, 200, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 200, (int)(timePlayed * 400.0f), 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 200, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, Color.LightGray);
|
||||
|
||||
DrawText("UP-DOWN for VOLUME CONTROL", 320, 334, 10, Color.DarkGreen);
|
||||
DrawRectangle(300, 360, 200, 12, Color.LightGray);
|
||||
DrawRectangleLines(300, 360, 200, 12, Color.Gray);
|
||||
DrawRectangle((int)(300 + volume * 200 - 5), 352, 10, 28, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - music stream");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - music playing (streaming)");
|
||||
InitAudioDevice();
|
||||
|
||||
Music music = LoadMusicStream("resources/audio/country.mp3");
|
||||
PlayMusicStream(music);
|
||||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(30); // Set our game to run at 30 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MusicStreamDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
// Get timePlayed scaled to bar dimensions (400 pixels)
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * 400;
|
||||
|
||||
if (timePlayed > 400)
|
||||
{
|
||||
StopMusicStream(music);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(200, 200, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 200, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 200, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMusicStream(music);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
182
Examples/Audio/RawStream.cs
Normal file
182
Examples/Audio/RawStream.cs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - raw stream
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 1.6, last time updated with raylib 6.0
|
||||
*
|
||||
* Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
|
||||
*
|
||||
* 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) 2015-2026 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public unsafe partial class RawStream : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
public string Name => "Audio / Raw Stream";
|
||||
|
||||
public string Title => "raylib [audio] example - raw stream";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private float[] buffer;
|
||||
private AudioStream stream;
|
||||
private float pan;
|
||||
private int sineFrequency;
|
||||
private int newSineFrequency;
|
||||
private int sineIndex;
|
||||
private double sineStartTime;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
buffer = new float[BUFFER_SIZE];
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
pan = 0.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
PlayAudioStream(stream);
|
||||
|
||||
sineFrequency = 440;
|
||||
newSineFrequency = 440;
|
||||
sineIndex = 0;
|
||||
sineStartTime = 0.0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
newSineFrequency += 10;
|
||||
if (newSineFrequency > 12500) newSineFrequency = 12500;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
newSineFrequency -= 10;
|
||||
if (newSineFrequency < 20) newSineFrequency = 20;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
pan -= 0.01f;
|
||||
if (pan < -1.0f) pan = -1.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
pan += 0.01f;
|
||||
if (pan > 1.0f) pan = 1.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
}
|
||||
|
||||
if (IsAudioStreamProcessed(stream))
|
||||
{
|
||||
for (int i = 0; i < BUFFER_SIZE; i++)
|
||||
{
|
||||
int wl = SAMPLE_RATE / sineFrequency;
|
||||
buffer[i] = MathF.Sin(2 * MathF.PI * sineIndex / wl);
|
||||
sineIndex++;
|
||||
|
||||
if (sineIndex >= wl)
|
||||
{
|
||||
sineFrequency = newSineFrequency;
|
||||
sineIndex = 0;
|
||||
sineStartTime = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
fixed (float* bufferPtr = buffer)
|
||||
{
|
||||
UpdateAudioStream(stream, bufferPtr, BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText($"sine frequency: {sineFrequency}", screenWidth - 220, 10, 20, Color.Red);
|
||||
DrawText($"pan: {pan:F2}", screenWidth - 220, 30, 20, Color.Red);
|
||||
DrawText("Up/down to change frequency", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("Left/right to pan", 10, 30, 20, Color.DarkGray);
|
||||
|
||||
int windowStart = (int)((GetTime() - sineStartTime) * SAMPLE_RATE);
|
||||
int windowSize = (int)(0.1f * SAMPLE_RATE);
|
||||
int wavelength = SAMPLE_RATE / sineFrequency;
|
||||
|
||||
// Draw a sine wave with the same frequency as the one being sent to the audio stream
|
||||
for (int i = 0; i < screenWidth; i++)
|
||||
{
|
||||
int t0 = windowStart + i * windowSize / screenWidth;
|
||||
int t1 = windowStart + (i + 1) * windowSize / screenWidth;
|
||||
Vector2 startPos = new Vector2(i, 250 + 50 * MathF.Sin(2 * MathF.PI * t0 / wavelength));
|
||||
Vector2 endPos = new Vector2(i + 1, 250 + 50 * MathF.Sin(2 * MathF.PI * t1 / wavelength));
|
||||
DrawLineV(startPos, endPos, Color.Red);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw stream");
|
||||
|
||||
SetTargetFPS(30);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new RawStream();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Sound loading and playing
|
||||
* raylib [audio] example - sound loading
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* 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.1, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 2014 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) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,60 +17,84 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class SoundLoading
|
||||
public partial class SoundLoading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Sound Loading";
|
||||
|
||||
public string Title => "raylib [audio] example - sound loading";
|
||||
|
||||
private Sound fxWav;
|
||||
private Sound fxOgg;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
fxWav = LoadSound("resources/audio/sound.wav"); // Load WAV audio file
|
||||
fxOgg = LoadSound("resources/audio/target.ogg"); // Load OGG audio file
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(fxWav); // Play WAV sound
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
PlaySound(fxOgg); // Play OGG sound
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadSound(fxWav); // Unload sound data
|
||||
UnloadSound(fxOgg); // Unload sound data
|
||||
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading and playing");
|
||||
InitAudioDevice();
|
||||
|
||||
Sound fxWav = LoadSound("resources/audio/sound.wav");
|
||||
Sound fxOgg = LoadSound("resources/audio/target.ogg");
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundLoading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(fxWav);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
PlaySound(fxOgg);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadSound(fxWav);
|
||||
UnloadSound(fxOgg);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
114
Examples/Audio/SoundMulti.cs
Normal file
114
Examples/Audio/SoundMulti.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - sound multi
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example contributed by Jeffery Myers (@JeffM2501) 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 Jeffery Myers (@JeffM2501)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public partial class SoundMulti : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MAX_SOUNDS = 10;
|
||||
|
||||
public string Name => "Audio / Sound Multi";
|
||||
|
||||
public string Title => "raylib [audio] example - sound multi";
|
||||
|
||||
private Sound[] soundArray = new Sound[MAX_SOUNDS];
|
||||
private int currentSound;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
// Load audio file into the first slot as the 'source' sound,
|
||||
// this sound owns the sample data
|
||||
soundArray[0] = LoadSound("resources/audio/sound.wav");
|
||||
|
||||
// Load an alias of the sound into slots 1-9. These do not own the sound data, but can be played
|
||||
for (int i = 1; i < MAX_SOUNDS; i++) soundArray[i] = LoadSoundAlias(soundArray[0]);
|
||||
|
||||
currentSound = 0; // Set the sound list to the start
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(soundArray[currentSound]); // Play the next open sound slot
|
||||
currentSound++; // Increment the sound slot
|
||||
|
||||
// If the sound slot is out of bounds, go back to 0
|
||||
if (currentSound >= MAX_SOUNDS) currentSound = 0;
|
||||
|
||||
// NOTE: Another approach would be to look at the list for the first sound
|
||||
// that is not playing and use that slot
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY a WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
for (int i = 1; i < MAX_SOUNDS; i++) UnloadSoundAlias(soundArray[i]); // Unload sound aliases
|
||||
UnloadSound(soundArray[0]); // Unload source sound data
|
||||
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound multi");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundMulti();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
154
Examples/Audio/SoundPositioning.cs
Normal file
154
Examples/Audio/SoundPositioning.cs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - sound positioning
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Le Juez Victor (@Bigfoot71) 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 Le Juez Victor (@Bigfoot71)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public partial class SoundPositioning : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Sound Positioning";
|
||||
|
||||
public string Title => "raylib [audio] example - sound positioning";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Sound sound;
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
sound = LoadSound("resources/audio/coin.wav");
|
||||
|
||||
camera = new Camera3D
|
||||
{
|
||||
Position = new Vector3(0, 5, 5),
|
||||
Target = new Vector3(0, 0, 0),
|
||||
Up = new Vector3(0, 1, 0),
|
||||
FovY = 60,
|
||||
Projection = CameraProjection.Perspective
|
||||
};
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
float th = (float)GetTime();
|
||||
|
||||
Vector3 spherePos = new Vector3(
|
||||
5.0f * MathF.Cos(th),
|
||||
0.0f,
|
||||
5.0f * MathF.Sin(th)
|
||||
);
|
||||
|
||||
SetSoundPosition(camera, sound, spherePos, 1.0f);
|
||||
|
||||
if (!IsSoundPlaying(sound)) PlaySound(sound);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawGrid(10, 2);
|
||||
DrawSphere(spherePos, 0.5f, Color.Red);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadSound(sound);
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Set sound 3d position
|
||||
private static void SetSoundPosition(Camera3D listener, Sound sound, Vector3 position, float maxDist)
|
||||
{
|
||||
// Calculate direction vector and distance between listener and sound source
|
||||
Vector3 direction = Vector3.Subtract(position, listener.Position);
|
||||
float distance = direction.Length();
|
||||
|
||||
// Apply logarithmic distance attenuation and clamp between 0-1
|
||||
float attenuation = 1.0f / (1.0f + (distance / maxDist));
|
||||
attenuation = Math.Clamp(attenuation, 0.0f, 1.0f);
|
||||
|
||||
// Calculate normalized vectors for spatial positioning
|
||||
Vector3 normalizedDirection = Vector3.Normalize(direction);
|
||||
Vector3 forward = Vector3.Normalize(Vector3.Subtract(listener.Target, listener.Position));
|
||||
Vector3 right = Vector3.Normalize(Vector3.Cross(listener.Up, forward));
|
||||
|
||||
// Reduce volume for sounds behind the listener
|
||||
float dotProduct = Vector3.Dot(forward, normalizedDirection);
|
||||
if (dotProduct < 0.0f) attenuation *= (1.0f + dotProduct * 0.5f);
|
||||
|
||||
// Set stereo panning based on sound position relative to listener
|
||||
float pan = 0.5f + 0.5f * Vector3.Dot(normalizedDirection, right);
|
||||
|
||||
// Apply final sound properties
|
||||
SetSoundVolume(sound, attenuation);
|
||||
SetSoundPan(sound, pan);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound positioning");
|
||||
|
||||
DisableCursor();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundPositioning();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
306
Examples/Audio/StreamCallback.cs
Normal file
306
Examples/Audio/StreamCallback.cs
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - stream callback
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example created by Dan Hoang (@dan-hoang) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* NOTE: Example sends a wave to the audio device,
|
||||
* user gets the choice of four waves: sine, square, triangle, and sawtooth
|
||||
* A stream is set up to play to the audio device; stream is hooked to a callback that
|
||||
* generates a wave, that is determined by user choice
|
||||
*
|
||||
* 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) 2026 Dan Hoang (@dan-hoang)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("SetAudioStreamCallback is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class StreamCallback : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
// Wave type
|
||||
private enum WaveType
|
||||
{
|
||||
Sine,
|
||||
Square,
|
||||
Triangle,
|
||||
Sawtooth
|
||||
}
|
||||
|
||||
public string Name => "Audio / Stream Callback";
|
||||
|
||||
public string Title => "raylib [audio] example - stream callback";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private static int waveFrequency = 440;
|
||||
private static int newWaveFrequency = 440;
|
||||
private static int waveIndex = 0;
|
||||
|
||||
// Buffer to keep the last second of uploaded audio,
|
||||
// part of which will be drawn on the screen
|
||||
private static readonly float[] buffer = new float[SAMPLE_RATE];
|
||||
|
||||
private static readonly string[] waveTypesAsString = { "sine", "square", "triangle", "sawtooth" };
|
||||
|
||||
private AudioStream stream;
|
||||
private WaveType waveType;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
waveFrequency = 440;
|
||||
newWaveFrequency = 440;
|
||||
waveIndex = 0;
|
||||
Array.Clear(buffer, 0, buffer.Length);
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
PlayAudioStream(stream);
|
||||
|
||||
// Configure it so that the callback for waveType is called whenever stream is out of samples
|
||||
waveType = WaveType.Sine;
|
||||
SetWaveCallback();
|
||||
}
|
||||
|
||||
// Attach the callback matching the current waveType to the stream
|
||||
private void SetWaveCallback()
|
||||
{
|
||||
switch (waveType)
|
||||
{
|
||||
case WaveType.Sine: SetAudioStreamCallback(stream, &SineCallback); break;
|
||||
case WaveType.Square: SetAudioStreamCallback(stream, &SquareCallback); break;
|
||||
case WaveType.Triangle: SetAudioStreamCallback(stream, &TriangleCallback); break;
|
||||
case WaveType.Sawtooth: SetAudioStreamCallback(stream, &SawtoothCallback); break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
newWaveFrequency += 10;
|
||||
if (newWaveFrequency > 12500) newWaveFrequency = 12500;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
newWaveFrequency -= 10;
|
||||
if (newWaveFrequency < 20) newWaveFrequency = 20;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
if (waveType == WaveType.Sine) waveType = WaveType.Sawtooth;
|
||||
else if (waveType == WaveType.Square) waveType = WaveType.Sine;
|
||||
else if (waveType == WaveType.Triangle) waveType = WaveType.Square;
|
||||
else waveType = WaveType.Triangle;
|
||||
|
||||
SetWaveCallback();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
if (waveType == WaveType.Sine) waveType = WaveType.Square;
|
||||
else if (waveType == WaveType.Square) waveType = WaveType.Triangle;
|
||||
else if (waveType == WaveType.Triangle) waveType = WaveType.Sawtooth;
|
||||
else waveType = WaveType.Sine;
|
||||
|
||||
SetWaveCallback();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
DrawText($"frequency: {newWaveFrequency}", screenWidth - 220, 10, 20, Color.Red);
|
||||
DrawText($"wave type: {waveTypesAsString[(int)waveType]}", screenWidth - 220, 30, 20, Color.Red);
|
||||
DrawText("Up/down to change frequency", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("Left/right to change wave type", 10, 30, 20, Color.DarkGray);
|
||||
|
||||
// Draw the last 10 ms of uploaded audio
|
||||
for (int i = 0; i < screenWidth; i++)
|
||||
{
|
||||
Vector2 startPos = new Vector2(i, 250 - 50 * buffer[WaveSampleIndex(i)]);
|
||||
Vector2 endPos = new Vector2(i + 1, 250 - 50 * buffer[WaveSampleIndex(i + 1)]);
|
||||
DrawLineV(startPos, endPos, Color.Red);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
// Maps a screen column to a sample index in the last 10 ms of the buffer. The final column
|
||||
// maps one sample past the end of the buffer; upstream C reads out of bounds there, so we
|
||||
// clamp to the last valid sample (visually identical, but safe under C# bounds checking).
|
||||
private static int WaveSampleIndex(int column)
|
||||
{
|
||||
int index = SAMPLE_RATE - SAMPLE_RATE / 100 + column * SAMPLE_RATE / 100 / screenWidth;
|
||||
return index < SAMPLE_RATE ? index : SAMPLE_RATE - 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SineCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the sine wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = MathF.Sin(2 * MathF.PI * waveIndex / wavelength);
|
||||
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SquareCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the square wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = (waveIndex < wavelength / 2) ? 1 : -1;
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void TriangleCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the triangle wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = (waveIndex < wavelength / 2) ? (-1 + 2.0f * waveIndex / (wavelength / 2)) : (1 - 2.0f * (waveIndex - wavelength / 2) / (wavelength / 2));
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SawtoothCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the sawtooth wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = -1 + 2.0f * waveIndex / wavelength;
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream callback");
|
||||
|
||||
SetTargetFPS(30);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StreamCallback();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
222
Examples/Audio/StreamEffects.cs
Normal file
222
Examples/Audio/StreamEffects.cs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - stream effects
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 5.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) 2022-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("AttachAudioStreamProcessor is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class StreamEffects : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Stream Effects";
|
||||
|
||||
public string Title => "raylib [audio] example - stream effects";
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
private static float[] delayBuffer = null;
|
||||
private static uint delayBufferSize = 0;
|
||||
private static uint delayReadIndex = 2;
|
||||
private static uint delayWriteIndex = 0;
|
||||
|
||||
// Low-pass filter state (was a function-local static in the C example)
|
||||
private static readonly float[] low = { 0.0f, 0.0f };
|
||||
|
||||
private Music music;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
private bool enableEffectLPF;
|
||||
private bool enableEffectDelay;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
|
||||
// Allocate buffer for the delay effect
|
||||
delayBufferSize = 48000 * 2; // 1 second delay (device sampleRate*channels)
|
||||
delayBuffer = new float[delayBufferSize];
|
||||
delayReadIndex = 2;
|
||||
delayWriteIndex = 0;
|
||||
low[0] = 0.0f;
|
||||
low[1] = 0.0f;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
|
||||
pause = false; // Music playing paused
|
||||
|
||||
enableEffectLPF = false; // Enable effect low-pass-filter
|
||||
enableEffectDelay = false; // Enable effect delay (1 second)
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause) PauseMusicStream(music);
|
||||
else ResumeMusicStream(music);
|
||||
}
|
||||
|
||||
// Add/Remove effect: lowpass filter
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
enableEffectLPF = !enableEffectLPF;
|
||||
if (enableEffectLPF) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
}
|
||||
|
||||
// Add/Remove effect: delay
|
||||
if (IsKeyPressed(KeyboardKey.D))
|
||||
{
|
||||
enableEffectDelay = !enableEffectDelay;
|
||||
if (enableEffectDelay) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
}
|
||||
|
||||
// Get normalized time played for current music stream
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music);
|
||||
|
||||
if (timePlayed > 1.0f) timePlayed = 1.0f; // Make sure time played is no longer than music
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 245, 150, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(200, 180, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 180, (int)(timePlayed * 400.0f), 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 180, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 230, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 260, 20, Color.LightGray);
|
||||
|
||||
DrawText($"PRESS F TO TOGGLE LPF EFFECT: {(enableEffectLPF ? "ON" : "OFF")}", 200, 320, 20, Color.Gray);
|
||||
DrawText($"PRESS D TO TOGGLE DELAY EFFECT: {(enableEffectDelay ? "ON" : "OFF")}", 180, 350, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
delayBuffer = null; // Free delay buffer
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Audio effect: lowpass filter
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectLPF(void* buffer, uint frames)
|
||||
{
|
||||
const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
|
||||
const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
|
||||
|
||||
// Converts the buffer data before using it
|
||||
float* bufferData = (float*)buffer;
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float l = bufferData[i];
|
||||
float r = bufferData[i + 1];
|
||||
|
||||
low[0] += k * (l - low[0]);
|
||||
low[1] += k * (r - low[1]);
|
||||
bufferData[i] = low[0];
|
||||
bufferData[i + 1] = low[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Audio effect: delay
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectDelay(void* buffer, uint frames)
|
||||
{
|
||||
float* bufferData = (float*)buffer;
|
||||
fixed (float* delay = delayBuffer)
|
||||
{
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float leftDelay = delay[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related???
|
||||
float rightDelay = delay[delayReadIndex++];
|
||||
|
||||
if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
|
||||
|
||||
bufferData[i] = 0.5f * bufferData[i] + 0.5f * leftDelay;
|
||||
bufferData[i + 1] = 0.5f * bufferData[i + 1] + 0.5f * rightDelay;
|
||||
|
||||
delay[delayWriteIndex++] = bufferData[i];
|
||||
delay[delayWriteIndex++] = bufferData[i + 1];
|
||||
if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream effects");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StreamEffects();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
379
Examples/Core/AutomationEvents.cs
Normal file
379
Examples/Core/AutomationEvents.cs
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - automation events
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example based on 2d_camera_platformer example by arvyy (@arvyy)
|
||||
*
|
||||
* 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 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class AutomationEvents : IExample
|
||||
{
|
||||
private const int GRAVITY = 400;
|
||||
private const float PLAYER_JUMP_SPD = 350.0f;
|
||||
private const float PLAYER_HOR_SPD = 200.0f;
|
||||
|
||||
private const int MAX_ENVIRONMENT_ELEMENTS = 5;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Automation Events";
|
||||
|
||||
public string Title => "raylib [core] example - automation events";
|
||||
|
||||
private struct Player
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Speed;
|
||||
public bool CanJump;
|
||||
}
|
||||
|
||||
private struct EnvElement
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Blocking;
|
||||
public Color Color;
|
||||
}
|
||||
|
||||
private Player player;
|
||||
private EnvElement[] envElements;
|
||||
private Camera2D camera;
|
||||
|
||||
private AutomationEventList aelist;
|
||||
private bool eventRecording;
|
||||
private bool eventPlaying;
|
||||
|
||||
private uint frameCounter;
|
||||
private uint playFrameCounter;
|
||||
private uint currentPlayFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define player
|
||||
player = new Player();
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
// Define environment elements (platforms)
|
||||
envElements = new EnvElement[MAX_ENVIRONMENT_ELEMENTS]
|
||||
{
|
||||
new EnvElement { Rect = new Rectangle(0, 0, 1000, 400), Blocking = 0, Color = Color.LightGray },
|
||||
new EnvElement { Rect = new Rectangle(0, 400, 1000, 200), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(300, 200, 400, 10), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(250, 300, 100, 10), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(650, 300, 100, 10), Blocking = 1, Color = Color.Gray }
|
||||
};
|
||||
|
||||
// Define camera
|
||||
camera = new Camera2D();
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
// Automation events
|
||||
aelist = LoadAutomationEventList((sbyte*)null); // Initialize list of automation events to record new events
|
||||
SetAutomationEventList(ref aelist);
|
||||
eventRecording = false;
|
||||
eventPlaying = false;
|
||||
|
||||
frameCounter = 0;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float deltaTime = 0.015f;//GetFrameTime();
|
||||
|
||||
// Dropped files logic
|
||||
//----------------------------------------------------------------------------------
|
||||
#if BROWSER
|
||||
// NOTE: drag-and-drop event-list loading (.txt/.rae) is not supported in the browser host.
|
||||
#else
|
||||
if (IsFileDropped())
|
||||
{
|
||||
FilePathList droppedFiles = LoadDroppedFiles();
|
||||
|
||||
// Supports loading .rgs style files (text or binary) and .png style palette images
|
||||
if (IsFileExtension(droppedFiles[0], ".txt;.rae"))
|
||||
{
|
||||
UnloadAutomationEventList(aelist);
|
||||
aelist = LoadAutomationEventList(droppedFiles[0]);
|
||||
|
||||
eventRecording = false;
|
||||
|
||||
// Reset scene state to play
|
||||
eventPlaying = true;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
|
||||
UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Update player
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Left)) player.Position.X -= PLAYER_HOR_SPD * deltaTime;
|
||||
if (IsKeyDown(KeyboardKey.Right)) player.Position.X += PLAYER_HOR_SPD * deltaTime;
|
||||
if (IsKeyDown(KeyboardKey.Space) && player.CanJump)
|
||||
{
|
||||
player.Speed = -PLAYER_JUMP_SPD;
|
||||
player.CanJump = false;
|
||||
}
|
||||
|
||||
int hitObstacle = 0;
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
EnvElement element = envElements[i];
|
||||
if (element.Blocking != 0 &&
|
||||
element.Rect.X <= player.Position.X &&
|
||||
element.Rect.X + element.Rect.Width >= player.Position.X &&
|
||||
element.Rect.Y >= player.Position.Y &&
|
||||
element.Rect.Y <= player.Position.Y + player.Speed * deltaTime)
|
||||
{
|
||||
hitObstacle = 1;
|
||||
player.Speed = 0.0f;
|
||||
player.Position.Y = element.Rect.Y;
|
||||
}
|
||||
}
|
||||
|
||||
if (hitObstacle == 0)
|
||||
{
|
||||
player.Position.Y += player.Speed * deltaTime;
|
||||
player.Speed += GRAVITY * deltaTime;
|
||||
player.CanJump = false;
|
||||
}
|
||||
else player.CanJump = true;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
// Reset game state
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Events playing
|
||||
// NOTE: Logic must be before Camera update because it depends on mouse-wheel value,
|
||||
// that can be set by the played event... but some other inputs could be affected
|
||||
//----------------------------------------------------------------------------------
|
||||
if (eventPlaying)
|
||||
{
|
||||
// NOTE: Multiple events could be executed in a single frame
|
||||
while (playFrameCounter == aelist.Events[currentPlayFrame].Frame)
|
||||
{
|
||||
PlayAutomationEvent(aelist.Events[currentPlayFrame]);
|
||||
currentPlayFrame++;
|
||||
|
||||
if (currentPlayFrame == aelist.Count)
|
||||
{
|
||||
eventPlaying = false;
|
||||
currentPlayFrame = 0;
|
||||
playFrameCounter = 0;
|
||||
|
||||
TraceLog(TraceLogLevel.Info, "FINISH PLAYING!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
playFrameCounter++;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Update camera
|
||||
//----------------------------------------------------------------------------------
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
|
||||
|
||||
// WARNING: On event replay, mouse-wheel internal value is set
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
if (camera.Zoom > 3.0f) camera.Zoom = 3.0f;
|
||||
else if (camera.Zoom < 0.25f) camera.Zoom = 0.25f;
|
||||
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
EnvElement element = envElements[i];
|
||||
minX = MathF.Min(element.Rect.X, minX);
|
||||
maxX = MathF.Max(element.Rect.X + element.Rect.Width, maxX);
|
||||
minY = MathF.Min(element.Rect.Y, minY);
|
||||
maxY = MathF.Max(element.Rect.Y + element.Rect.Height, maxY);
|
||||
}
|
||||
|
||||
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
|
||||
if (max.X < screenWidth) camera.Offset.X = screenWidth - (max.X - (float)screenWidth / 2);
|
||||
if (max.Y < screenHeight) camera.Offset.Y = screenHeight - (max.Y - (float)screenHeight / 2);
|
||||
if (min.X > 0) camera.Offset.X = (float)screenWidth / 2 - min.X;
|
||||
if (min.Y > 0) camera.Offset.Y = (float)screenHeight / 2 - min.Y;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Events management
|
||||
if (IsKeyPressed(KeyboardKey.S)) // Toggle events recording
|
||||
{
|
||||
if (!eventPlaying)
|
||||
{
|
||||
if (eventRecording)
|
||||
{
|
||||
StopAutomationEventRecording();
|
||||
eventRecording = false;
|
||||
|
||||
ExportAutomationEventList(aelist, "automation.rae");
|
||||
|
||||
TraceLog(TraceLogLevel.Info, $"RECORDED FRAMES: {aelist.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAutomationEventBaseFrame(180);
|
||||
StartAutomationEventRecording();
|
||||
eventRecording = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.A)) // Toggle events playing (WARNING: Starts next frame)
|
||||
{
|
||||
if (!eventRecording && (aelist.Count > 0))
|
||||
{
|
||||
// Reset scene state to play
|
||||
eventPlaying = true;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventRecording || eventPlaying) frameCounter++;
|
||||
else frameCounter = 0;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
// Draw environment elements
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
DrawRectangleRec(envElements[i].Rect, envElements[i].Color);
|
||||
}
|
||||
|
||||
// Draw player rectangle
|
||||
DrawRectangleRec(new Rectangle(player.Position.X - 20, player.Position.Y - 40, 40, 40), Color.Red);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
// Draw game controls
|
||||
DrawRectangle(10, 10, 290, 145, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 290, 145, Fade(Color.Blue, 0.8f));
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- RIGHT | LEFT: Player movement", 30, 40, 10, Color.DarkGray);
|
||||
DrawText("- SPACE: Player jump", 30, 60, 10, Color.DarkGray);
|
||||
DrawText("- R: Reset game state", 30, 80, 10, Color.DarkGray);
|
||||
|
||||
DrawText("- S: START/STOP RECORDING INPUT EVENTS", 30, 110, 10, Color.Black);
|
||||
DrawText("- A: REPLAY LAST RECORDED INPUT EVENTS", 30, 130, 10, Color.Black);
|
||||
|
||||
// Draw automation events recording indicator
|
||||
if (eventRecording)
|
||||
{
|
||||
DrawRectangle(10, 160, 290, 30, Fade(Color.Red, 0.3f));
|
||||
DrawRectangleLines(10, 160, 290, 30, Fade(Color.Maroon, 0.8f));
|
||||
DrawCircle(30, 175, 10, Color.Maroon);
|
||||
|
||||
if (((frameCounter / 15) % 2) == 1) DrawText($"RECORDING EVENTS... [{aelist.Count}]", 50, 170, 10, Color.Maroon);
|
||||
}
|
||||
else if (eventPlaying)
|
||||
{
|
||||
DrawRectangle(10, 160, 290, 30, Fade(Color.Lime, 0.3f));
|
||||
DrawRectangleLines(10, 160, 290, 30, Fade(Color.DarkGreen, 0.8f));
|
||||
DrawTriangle(new Vector2(20, 155 + 10), new Vector2(20, 155 + 30), new Vector2(40, 155 + 20), Color.DarkGreen);
|
||||
|
||||
if (((frameCounter / 15) % 2) == 1) DrawText($"PLAYING RECORDED EVENTS... [{currentPlayFrame}]", 50, 170, 10, Color.DarkGreen);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAutomationEventList(aelist);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - automation events");
|
||||
|
||||
var game = new AutomationEvents();
|
||||
game.Init();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Basic window
|
||||
* raylib [core] example - basic screen manager
|
||||
*
|
||||
* Welcome to raylib!
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* 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
|
||||
* NOTE: This example illustrates a very simple screen manager based on a states machines
|
||||
*
|
||||
* You can find all basic examples on C:\raylib\raylib\examples folder or
|
||||
* raylib official webpage: www.raylib.com
|
||||
* Example originally created with raylib 4.0, last time updated with raylib 4.0
|
||||
*
|
||||
* Enjoy using raylib. :)
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -23,7 +19,7 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
enum GameScreen
|
||||
internal enum GameScreen
|
||||
{
|
||||
Logo = 0,
|
||||
Title,
|
||||
|
|
@ -31,143 +27,160 @@ enum GameScreen
|
|||
Ending
|
||||
}
|
||||
|
||||
public class BasicScreenManager
|
||||
public partial class BasicScreenManager : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Basic Screen Manager";
|
||||
|
||||
public string Title => "raylib [core] example - basic screen manager";
|
||||
|
||||
private GameScreen currentScreen;
|
||||
private int framesCounter;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
currentScreen = GameScreen.Logo;
|
||||
|
||||
// TODO: Initialize all required variables and load all required data here!
|
||||
|
||||
framesCounter = 0; // Useful to count frames
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Update LOGO screen variables here!
|
||||
|
||||
framesCounter++; // Count frames
|
||||
|
||||
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
|
||||
if (framesCounter > 120)
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Update TITLE screen variables here!
|
||||
|
||||
// Press enter to change to GAMEPLAY screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Gameplay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Update GAMEPLAY screen variables here!
|
||||
|
||||
// Press enter to change to ENDING screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Ending;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Update ENDING screen variables here!
|
||||
|
||||
// Press enter to return to TITLE screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Draw LOGO screen here!
|
||||
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
|
||||
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Draw TITLE screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
|
||||
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Draw GAMEPLAY screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
|
||||
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Draw ENDING screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
|
||||
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
|
||||
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// TODO: Unload all loaded data (textures, fonts, audio) here!
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic screen manager");
|
||||
|
||||
GameScreen currentScreen = GameScreen.Logo;
|
||||
|
||||
// TODO: Initialize all required variables and load all required data here!
|
||||
|
||||
// Useful to count frames
|
||||
int framesCounter = 0;
|
||||
|
||||
SetTargetFPS(60); // Set desired framerate (frames-per-second)
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicScreenManager();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Update LOGO screen variables here!
|
||||
|
||||
// Count frames
|
||||
framesCounter++;
|
||||
|
||||
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
|
||||
if (framesCounter > 120)
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Update TITLE screen variables here!
|
||||
|
||||
// Press enter to change to GAMEPLAY screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Gameplay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Update GAMEPLAY screen variables here!
|
||||
|
||||
// Press enter to change to ENDING screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Ending;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Update ENDING screen variables here!
|
||||
|
||||
// Press enter to return to TITLE screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Draw LOGO screen here!
|
||||
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
|
||||
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Draw TITLE screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
|
||||
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Draw GAMEPLAY screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
|
||||
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Draw ENDING screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
|
||||
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
|
||||
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// TODO: Unload all loaded data (textures, fonts, audio) here!
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -33,43 +33,56 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class BasicWindow
|
||||
public partial class BasicWindow : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Basic Window";
|
||||
|
||||
public string Title => "raylib [core] example - basic window";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
|
||||
var game = new BasicWindow();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,31 +13,37 @@
|
|||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera2dDemo
|
||||
public partial class Camera2dDemo : IExample
|
||||
{
|
||||
public const int MaxBuildings = 100;
|
||||
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 2D Demo";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera";
|
||||
|
||||
private Rectangle player;
|
||||
private Rectangle[] buildings;
|
||||
private Color[] buildColors;
|
||||
private Camera2D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
player = new(400, 280, 40, 40);
|
||||
buildings = new Rectangle[MaxBuildings];
|
||||
buildColors = new Color[MaxBuildings];
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
var spacing = 0;
|
||||
|
||||
Rectangle player = new(400, 280, 40, 40);
|
||||
Rectangle[] buildings = new Rectangle[MaxBuildings];
|
||||
Color[] buildColors = new Color[MaxBuildings];
|
||||
|
||||
int spacing = 0;
|
||||
|
||||
for (int i = 0; i < MaxBuildings; i++)
|
||||
for (var i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
buildings[i].Width = GetRandomValue(50, 200);
|
||||
buildings[i].Height = GetRandomValue(100, 800);
|
||||
|
|
@ -54,124 +60,139 @@ public class Camera2dDemo
|
|||
);
|
||||
}
|
||||
|
||||
Camera2D camera = new();
|
||||
camera = new();
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Player movement
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
player.X += 2;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
player.X -= 2;
|
||||
}
|
||||
|
||||
// Camera target follows player
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
|
||||
// Camera rotation controls
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
camera.Rotation--;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
camera.Rotation++;
|
||||
}
|
||||
|
||||
// Limit camera rotation to 80 degrees (-40 to 40)
|
||||
if (camera.Rotation > 40)
|
||||
{
|
||||
camera.Rotation = 40;
|
||||
}
|
||||
else if (camera.Rotation < -40)
|
||||
{
|
||||
camera.Rotation = -40;
|
||||
}
|
||||
|
||||
// Camera zoom controls
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
camera.Zoom = MathF.Exp(MathF.Log(camera.Zoom) + ((float)GetMouseWheelMove() * 0.1f));
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.1f)
|
||||
{
|
||||
camera.Zoom = 0.1f;
|
||||
}
|
||||
|
||||
// Camera reset (zoom and rotation)
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
camera.Rotation = 0.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
|
||||
|
||||
for (var i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
DrawRectangleRec(buildings[i], buildColors[i]);
|
||||
}
|
||||
|
||||
DrawRectangleRec(player, Color.Red);
|
||||
|
||||
DrawLine((int)camera.Target.X, -screenHeight * 10, (int)camera.Target.X, screenHeight * 10, Color.Green);
|
||||
DrawLine(-screenWidth * 10, (int)camera.Target.Y, screenWidth * 10, (int)camera.Target.Y, Color.Green);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 5, Color.Red);
|
||||
DrawRectangle(0, 5, 5, screenHeight - 10, Color.Red);
|
||||
DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, Color.Red);
|
||||
DrawRectangle(0, screenHeight - 5, screenWidth, 5, Color.Red);
|
||||
|
||||
DrawRectangle(10, 10, 250, 113, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
|
||||
|
||||
DrawText("Free 2D camera controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move player", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Player movement
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
player.X += 2;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
player.X -= 2;
|
||||
}
|
||||
|
||||
// Camera3D target follows player
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
|
||||
// Camera3D rotation controls
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
camera.Rotation--;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
camera.Rotation++;
|
||||
}
|
||||
|
||||
// Limit camera rotation to 80 degrees (-40 to 40)
|
||||
if (camera.Rotation > 40)
|
||||
{
|
||||
camera.Rotation = 40;
|
||||
}
|
||||
else if (camera.Rotation < -40)
|
||||
{
|
||||
camera.Rotation = -40;
|
||||
}
|
||||
|
||||
// Camera3D zoom controls
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.1f)
|
||||
{
|
||||
camera.Zoom = 0.1f;
|
||||
}
|
||||
|
||||
// Camera3D reset (zoom and rotation)
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
camera.Rotation = 0.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
|
||||
|
||||
for (int i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
DrawRectangleRec(buildings[i], buildColors[i]);
|
||||
}
|
||||
|
||||
DrawRectangleRec(player, Color.Red);
|
||||
|
||||
DrawRectangle((int)camera.Target.X, -500, 1, (int)(screenHeight * 4), Color.Green);
|
||||
DrawLine(
|
||||
(int)(-screenWidth * 10),
|
||||
(int)camera.Target.Y,
|
||||
(int)(screenWidth * 10),
|
||||
(int)camera.Target.Y,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
|
||||
|
||||
DrawRectangle(0, 0, (int)screenWidth, 5, Color.Red);
|
||||
DrawRectangle(0, 5, 5, (int)screenHeight - 10, Color.Red);
|
||||
DrawRectangle((int)screenWidth - 5, 5, 5, (int)screenHeight - 10, Color.Red);
|
||||
DrawRectangle(0, (int)screenHeight - 5, (int)screenWidth, 5, Color.Red);
|
||||
|
||||
DrawRectangle(10, 10, 250, 113, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
|
||||
|
||||
DrawText("Free 2d camera controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move Offset", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
184
Examples/Core/Camera2dMouseZoom.cs
Normal file
184
Examples/Core/Camera2dMouseZoom.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - 2d camera mouse zoom
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by Jeffery Myers (@JeffM2501) 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) 2022-2025 Jeffery Myers (@JeffM2501)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class Camera2dMouseZoom : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 2D Mouse Zoom";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera mouse zoom";
|
||||
|
||||
private Camera2D camera;
|
||||
private int zoomMode; // 0-Mouse Wheel, 1-Mouse Move
|
||||
|
||||
public void Init()
|
||||
{
|
||||
camera = new Camera2D();
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
zoomMode = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
zoomMode = 0;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
zoomMode = 1;
|
||||
}
|
||||
|
||||
// Translate based on mouse right click
|
||||
if (IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
Vector2 delta = GetMouseDelta();
|
||||
delta = Vector2Scale(delta, -1.0f / camera.Zoom);
|
||||
camera.Target = Vector2Add(camera.Target, delta);
|
||||
}
|
||||
|
||||
if (zoomMode == 0)
|
||||
{
|
||||
// Zoom based on mouse wheel
|
||||
float wheel = GetMouseWheelMove();
|
||||
if (wheel != 0)
|
||||
{
|
||||
// Get the world point that is under the mouse
|
||||
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
|
||||
// Set the offset to where the mouse is
|
||||
camera.Offset = GetMousePosition();
|
||||
|
||||
// Set the target to match, so that the camera maps the world space point
|
||||
// under the cursor to the screen space point under the cursor at any zoom
|
||||
camera.Target = mouseWorldPos;
|
||||
|
||||
// Zoom increment
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
float scale = 0.2f * wheel;
|
||||
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zoom based on mouse right click
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
// Get the world point that is under the mouse
|
||||
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
|
||||
// Set the offset to where the mouse is
|
||||
camera.Offset = GetMousePosition();
|
||||
|
||||
// Set the target to match, so that the camera maps the world space point
|
||||
// under the cursor to the screen space point under the cursor at any zoom
|
||||
camera.Target = mouseWorldPos;
|
||||
}
|
||||
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
// Zoom increment
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
float deltaX = GetMouseDelta().X;
|
||||
float scale = 0.005f * deltaX;
|
||||
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
|
||||
// just so we have something in the XY plane
|
||||
Rlgl.PushMatrix();
|
||||
Rlgl.Translatef(0, 25 * 50, 0);
|
||||
Rlgl.Rotatef(90, 1, 0, 0);
|
||||
DrawGrid(100, 50);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw a reference circle
|
||||
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 50, Color.Maroon);
|
||||
EndMode2D();
|
||||
|
||||
// Draw mouse reference
|
||||
//Vector2 mousePos = GetWorldToScreen2D(GetMousePosition(), camera)
|
||||
DrawCircleV(GetMousePosition(), 4, Color.DarkGray);
|
||||
DrawTextEx(GetFontDefault(), $"[{GetMouseX()}, {GetMouseY()}]",
|
||||
Vector2Add(GetMousePosition(), new Vector2(-44, -24)), 20, 2, Color.Black);
|
||||
|
||||
DrawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, Color.DarkGray);
|
||||
if (zoomMode == 0)
|
||||
{
|
||||
DrawText("Mouse left button drag to move, mouse wheel to zoom", 20, 50, 20, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Mouse left button drag to move, mouse press and move to zoom", 20, 50, 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera mouse zoom");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dMouseZoom();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,16 @@
|
|||
*
|
||||
* raylib [core] example - 2d camera platformer
|
||||
*
|
||||
* 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: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.0
|
||||
*
|
||||
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 arvyy (@arvyy)
|
||||
* 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 arvyy (@arvyy)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -18,20 +22,27 @@ using static Raylib_cs.Raymath;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera2dPlatformer
|
||||
public partial class Camera2dPlatformer : IExample
|
||||
{
|
||||
const int G = 400;
|
||||
const float PlayerJumpSpeed = 350.0f;
|
||||
const float PlayerHorSpeed = 200.0f;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
struct Player
|
||||
private const int G = 400;
|
||||
private const float PlayerJumpSpeed = 350.0f;
|
||||
private const float PlayerHorSpeed = 200.0f;
|
||||
|
||||
public string Name => "Core / 2D Camera Platformer";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera platformer";
|
||||
|
||||
private struct Player
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Speed;
|
||||
public bool CanJump;
|
||||
}
|
||||
|
||||
struct EnvItem
|
||||
private struct EnvItem
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Blocking;
|
||||
|
|
@ -45,7 +56,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
delegate void CameraUpdaterCallback(
|
||||
private delegate void CameraUpdaterCallback(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -54,21 +65,22 @@ public class Camera2dPlatformer
|
|||
int height
|
||||
);
|
||||
|
||||
public static int Main()
|
||||
private Player player;
|
||||
private EnvItem[] envItems;
|
||||
private Camera2D camera;
|
||||
private CameraUpdaterCallback[] cameraUpdaters;
|
||||
private int cameraOption;
|
||||
private int cameraUpdatersLength;
|
||||
private string[] cameraDescriptions;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
|
||||
Player player = new();
|
||||
player = new();
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
EnvItem[] envItems = new EnvItem[]
|
||||
envItems = new EnvItem[]
|
||||
{
|
||||
new EnvItem(new Rectangle(0, 0, 1000, 400), 0, Color.LightGray),
|
||||
new EnvItem(new Rectangle(0, 400, 1000, 200), 1, Color.Gray),
|
||||
|
|
@ -77,14 +89,14 @@ public class Camera2dPlatformer
|
|||
new EnvItem(new Rectangle(650, 300, 100, 10), 1, Color.Gray)
|
||||
};
|
||||
|
||||
Camera2D camera = new();
|
||||
camera = new();
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
// Store callbacks to the multiple update camera functions
|
||||
CameraUpdaterCallback[] cameraUpdaters = new CameraUpdaterCallback[]
|
||||
// Store pointers to the multiple update camera functions
|
||||
cameraUpdaters = new CameraUpdaterCallback[]
|
||||
{
|
||||
UpdateCameraCenter,
|
||||
UpdateCameraCenterInsideMap,
|
||||
|
|
@ -93,93 +105,89 @@ public class Camera2dPlatformer
|
|||
UpdateCameraPlayerBoundsPush
|
||||
};
|
||||
|
||||
int cameraOption = 0;
|
||||
int cameraUpdatersLength = cameraUpdaters.Length;
|
||||
cameraOption = 0;
|
||||
cameraUpdatersLength = cameraUpdaters.Length;
|
||||
|
||||
string[] cameraDescriptions = new string[]{
|
||||
cameraDescriptions = new string[]{
|
||||
"Follow player center",
|
||||
"Follow player center, but clamp to map edges",
|
||||
"Follow player center; smoothed",
|
||||
"Follow player center horizontally; update player center vertically after landing",
|
||||
"Player push camera on getting too close to screen edge"
|
||||
};
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float deltaTime = GetFrameTime();
|
||||
|
||||
UpdatePlayer(ref player, envItems, deltaTime);
|
||||
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.25f)
|
||||
{
|
||||
camera.Zoom = 0.25f;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
player.Position = new Vector2(400, 280);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
|
||||
}
|
||||
|
||||
// Call update camera function by its pointer
|
||||
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
|
||||
}
|
||||
|
||||
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40, 40);
|
||||
DrawRectangleRec(playerRect, Color.Red);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- C to change camera mode", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("Current camera mode:", 20, 120, 10, Color.Black);
|
||||
DrawText(cameraDescriptions[cameraOption], 40, 140, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var deltaTime = GetFrameTime();
|
||||
|
||||
UpdatePlayer(ref player, envItems, deltaTime);
|
||||
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.25f)
|
||||
{
|
||||
camera.Zoom = 0.25f;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
player.Position = new Vector2(400, 280);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
|
||||
}
|
||||
|
||||
// Call update camera function by its pointer
|
||||
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
|
||||
}
|
||||
|
||||
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40.0f, 40.0f);
|
||||
DrawRectangleRec(playerRect, Color.Red);
|
||||
|
||||
DrawCircleV(player.Position, 5.0f, Color.Gold);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset position + zoom", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("- C to change camera mode", 40, 120, 10, Color.DarkGray);
|
||||
DrawText("Current camera mode:", 20, 140, 10, Color.Black);
|
||||
DrawText(cameraDescriptions[cameraOption], 40, 160, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
private static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
|
||||
{
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
|
|
@ -197,11 +205,11 @@ public class Camera2dPlatformer
|
|||
player.CanJump = false;
|
||||
}
|
||||
|
||||
int hitObstacle = 0;
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
var hitObstacle = 0;
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
EnvItem ei = envItems[i];
|
||||
Vector2 p = player.Position;
|
||||
var ei = envItems[i];
|
||||
var p = player.Position;
|
||||
if (ei.Blocking != 0 &&
|
||||
ei.Rect.X <= p.X &&
|
||||
ei.Rect.X + ei.Rect.Width >= p.X &&
|
||||
|
|
@ -211,6 +219,7 @@ public class Camera2dPlatformer
|
|||
hitObstacle = 1;
|
||||
player.Speed = 0.0f;
|
||||
player.Position.Y = ei.Rect.Y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +235,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraCenter(
|
||||
private static void UpdateCameraCenter(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -235,11 +244,11 @@ public class Camera2dPlatformer
|
|||
int height
|
||||
)
|
||||
{
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
camera.Target = player.Position;
|
||||
}
|
||||
|
||||
static void UpdateCameraCenterInsideMap(
|
||||
private static void UpdateCameraCenterInsideMap(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -248,43 +257,43 @@ public class Camera2dPlatformer
|
|||
int height)
|
||||
{
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
|
||||
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
EnvItem ei = envItems[i];
|
||||
var ei = envItems[i];
|
||||
minX = Math.Min(ei.Rect.X, minX);
|
||||
maxX = Math.Max(ei.Rect.X + ei.Rect.Width, maxX);
|
||||
minY = Math.Min(ei.Rect.Y, minY);
|
||||
maxY = Math.Max(ei.Rect.Y + ei.Rect.Height, maxY);
|
||||
}
|
||||
|
||||
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
var max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
var min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
|
||||
if (max.X < width)
|
||||
{
|
||||
camera.Offset.X = width - (max.X - width / 2);
|
||||
camera.Offset.X = width - (max.X - width / 2.0f);
|
||||
}
|
||||
|
||||
if (max.Y < height)
|
||||
{
|
||||
camera.Offset.Y = height - (max.Y - height / 2);
|
||||
camera.Offset.Y = height - (max.Y - height / 2.0f);
|
||||
}
|
||||
|
||||
if (min.X > 0)
|
||||
{
|
||||
camera.Offset.X = width / 2 - min.X;
|
||||
camera.Offset.X = width / 2.0f - min.X;
|
||||
}
|
||||
|
||||
if (min.Y > 0)
|
||||
{
|
||||
camera.Offset.Y = height / 2 - min.Y;
|
||||
camera.Offset.Y = height / 2.0f - min.Y;
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraCenterSmoothFollow(
|
||||
private static void UpdateCameraCenterSmoothFollow(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -297,18 +306,18 @@ public class Camera2dPlatformer
|
|||
const float minEffectLength = 10;
|
||||
const float fractionSpeed = 0.8f;
|
||||
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
Vector2 diff = Vector2Subtract(player.Position, camera.Target);
|
||||
float length = Vector2Length(diff);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
var diff = Vector2Subtract(player.Position, camera.Target);
|
||||
var length = Vector2Length(diff);
|
||||
|
||||
if (length > minEffectLength)
|
||||
{
|
||||
float speed = Math.Max(fractionSpeed * length, minSpeed);
|
||||
var speed = Math.Max(fractionSpeed * length, minSpeed);
|
||||
camera.Target = Vector2Add(camera.Target, Vector2Scale(diff, speed * delta / length));
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraEvenOutOnLanding(
|
||||
private static void UpdateCameraEvenOutOnLanding(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -318,10 +327,10 @@ public class Camera2dPlatformer
|
|||
)
|
||||
{
|
||||
float evenOutSpeed = 700;
|
||||
int eveningOut = 0;
|
||||
float evenOutTarget = 0.0f;
|
||||
var eveningOut = 0;
|
||||
var evenOutTarget = 0.0f;
|
||||
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
camera.Target.X = player.Position.X;
|
||||
|
||||
if (eveningOut != 0)
|
||||
|
|
@ -357,7 +366,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraPlayerBoundsPush(
|
||||
private static void UpdateCameraPlayerBoundsPush(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -368,11 +377,11 @@ public class Camera2dPlatformer
|
|||
{
|
||||
Vector2 bbox = new(0.2f, 0.2f);
|
||||
|
||||
Vector2 bboxWorldMin = GetScreenToWorld2D(
|
||||
var bboxWorldMin = GetScreenToWorld2D(
|
||||
new Vector2((1 - bbox.X) * 0.5f * width, (1 - bbox.Y) * 0.5f * height),
|
||||
camera
|
||||
);
|
||||
Vector2 bboxWorldMax = GetScreenToWorld2D(
|
||||
var bboxWorldMax = GetScreenToWorld2D(
|
||||
new Vector2((1 + bbox.X) * 0.5f * width,
|
||||
(1 + bbox.Y) * 0.5f * height),
|
||||
camera
|
||||
|
|
@ -399,4 +408,32 @@ public class Camera2dPlatformer
|
|||
camera.Target.Y = bboxWorldMin.Y + (player.Position.Y - bboxWorldMax.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera platformer");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dPlatformer();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
*
|
||||
* raylib [core] example - 3d camera first person
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,171 +18,202 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dFirstPerson
|
||||
public partial class Camera3dFirstPerson : IExample
|
||||
{
|
||||
public const int MaxColumns = 20;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 3D First Person";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera first person";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private CameraMode cameraMode;
|
||||
private float[] heights;
|
||||
private Vector3[] positions;
|
||||
private Color[] colors;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world (position, target, up vector)
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 60.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
|
||||
// Generates some random columns
|
||||
heights = new float[MaxColumns];
|
||||
positions = new Vector3[MaxColumns];
|
||||
colors = new Color[MaxColumns];
|
||||
|
||||
for (var i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
heights[i] = (float)GetRandomValue(1, 12);
|
||||
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2.0f, GetRandomValue(-15, 15));
|
||||
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Switch camera mode
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
cameraMode = CameraMode.Free;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
cameraMode = CameraMode.Orbital;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Switch camera projection
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
// Create isometric view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
// Note: The target distance is related to the render distance in the orthographic projection
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
|
||||
// CameraYaw(&camera, -135 * DEG2RAD, true);
|
||||
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
// Reset to default view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.FovY = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera computes movement internally depending on the camera mode
|
||||
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
|
||||
// For advanced camera controls, it's recommended to compute camera movement manually
|
||||
UpdateCamera(ref camera, cameraMode); // Update camera
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw ground
|
||||
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
|
||||
|
||||
// Draw a blue wall
|
||||
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
|
||||
|
||||
// Draw a green wall
|
||||
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
|
||||
|
||||
// Draw a yellow wall
|
||||
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
|
||||
|
||||
// Draw some cubes around
|
||||
for (var i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
|
||||
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
|
||||
}
|
||||
|
||||
// Draw player cube
|
||||
if (cameraMode == CameraMode.ThirdPerson)
|
||||
{
|
||||
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
|
||||
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw info boxes
|
||||
DrawRectangle(5, 5, 330, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(5, 5, 330, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
|
||||
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
|
||||
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
|
||||
|
||||
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera status:", 610, 15, 10, Color.Black);
|
||||
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
|
||||
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
|
||||
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
|
||||
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
|
||||
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person");
|
||||
|
||||
// Define the camera to look into our 3d world (position, target, up vector)
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(4.0f, 2.0f, 4.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.8f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 60.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
// Generates some random columns
|
||||
float[] heights = new float[MaxColumns];
|
||||
Vector3[] positions = new Vector3[MaxColumns];
|
||||
Color[] colors = new Color[MaxColumns];
|
||||
|
||||
for (int i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
heights[i] = (float)GetRandomValue(1, 12);
|
||||
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2, GetRandomValue(-15, 15));
|
||||
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
|
||||
}
|
||||
|
||||
CameraMode cameraMode = CameraMode.FirstPerson;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFirstPerson();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Switch camera mode
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
cameraMode = CameraMode.Free;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
cameraMode = CameraMode.Orbital;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Switch camera projection
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
// Create isometric view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
// Note: The target distance is related to the render distance in the orthographic projection
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
|
||||
// CameraYaw(&camera, -135 * DEG2RAD, true);
|
||||
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
// Reset to default view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.FovY = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera computes movement internally depending on the camera mode
|
||||
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
|
||||
// For advance camera controls, it's reecommended to compute camera movement manually
|
||||
UpdateCamera(ref camera, cameraMode);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw ground
|
||||
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
|
||||
|
||||
// Draw a blue wall
|
||||
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
|
||||
|
||||
// Draw a green wall
|
||||
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
|
||||
|
||||
// Draw a yellow wall
|
||||
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
|
||||
|
||||
// Draw some cubes around
|
||||
for (int i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
|
||||
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
|
||||
}
|
||||
|
||||
// Draw player cube
|
||||
if (cameraMode == CameraMode.ThirdPerson)
|
||||
{
|
||||
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
|
||||
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw info boxes
|
||||
DrawRectangle(5, 5, 330, 100, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 330, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
|
||||
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
|
||||
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
|
||||
|
||||
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera status:", 610, 15, 10, Color.Black);
|
||||
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
|
||||
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
|
||||
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
|
||||
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
|
||||
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
348
Examples/Core/Camera3dFps.cs
Normal file
348
Examples/Core/Camera3dFps.cs
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - 3d camera fps
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class Camera3dFps : IExample
|
||||
{
|
||||
// Movement constants
|
||||
private const float GRAVITY = 32.0f;
|
||||
private const float MAX_SPEED = 20.0f;
|
||||
private const float CROUCH_SPEED = 5.0f;
|
||||
private const float JUMP_FORCE = 12.0f;
|
||||
private const float MAX_ACCEL = 150.0f;
|
||||
// Grounded drag
|
||||
private const float FRICTION = 0.86f;
|
||||
// Increasing air drag, increases strafing speed
|
||||
private const float AIR_DRAG = 0.98f;
|
||||
// Responsiveness for turning movement direction to looked direction
|
||||
private const float CONTROL = 15.0f;
|
||||
private const float CROUCH_HEIGHT = 0.0f;
|
||||
private const float STAND_HEIGHT = 1.0f;
|
||||
private const float BOTTOM_HEIGHT = 0.5f;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / 3D Camera FPS";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera fps";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
// Body structure
|
||||
private struct Body
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector3 Velocity;
|
||||
public Vector3 Dir;
|
||||
public bool IsGrounded;
|
||||
}
|
||||
|
||||
// State that was global in the C example
|
||||
private readonly Vector2 sensitivity = new Vector2(0.001f, 0.001f);
|
||||
|
||||
private Body player;
|
||||
private Vector2 lookRotation;
|
||||
private float headTimer;
|
||||
private float walkLerp;
|
||||
private float headLerp;
|
||||
private Vector2 lean;
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
player = new Body();
|
||||
lookRotation = new Vector2(0, 0);
|
||||
headTimer = 0.0f;
|
||||
walkLerp = 0.0f;
|
||||
headLerp = STAND_HEIGHT;
|
||||
lean = new Vector2(0, 0);
|
||||
|
||||
// Initialize camera variables
|
||||
// NOTE: UpdateCameraFPS() takes care of the rest
|
||||
camera = new Camera3D();
|
||||
camera.FovY = 60.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.Position = new Vector3(
|
||||
player.Position.X,
|
||||
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
|
||||
player.Position.Z);
|
||||
|
||||
UpdateCameraFPS(ref camera); // Update camera parameters
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
Vector2 mouseDelta = GetMouseDelta();
|
||||
lookRotation.X -= mouseDelta.X * sensitivity.X;
|
||||
lookRotation.Y += mouseDelta.Y * sensitivity.Y;
|
||||
|
||||
int sideway = (IsKeyDown(KeyboardKey.D) ? 1 : 0) - (IsKeyDown(KeyboardKey.A) ? 1 : 0);
|
||||
int forward = (IsKeyDown(KeyboardKey.W) ? 1 : 0) - (IsKeyDown(KeyboardKey.S) ? 1 : 0);
|
||||
bool crouching = IsKeyDown(KeyboardKey.LeftControl);
|
||||
UpdateBody(ref player, lookRotation.X, sideway, forward, IsKeyPressed(KeyboardKey.Space), crouching);
|
||||
|
||||
float delta = GetFrameTime();
|
||||
headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f * delta);
|
||||
camera.Position = new Vector3(
|
||||
player.Position.X,
|
||||
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
|
||||
player.Position.Z);
|
||||
|
||||
if (player.IsGrounded && ((forward != 0) || (sideway != 0)))
|
||||
{
|
||||
headTimer += delta * 3.0f;
|
||||
walkLerp = Lerp(walkLerp, 1.0f, 10.0f * delta);
|
||||
camera.FovY = Lerp(camera.FovY, 55.0f, 5.0f * delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
walkLerp = Lerp(walkLerp, 0.0f, 10.0f * delta);
|
||||
camera.FovY = Lerp(camera.FovY, 60.0f, 5.0f * delta);
|
||||
}
|
||||
|
||||
lean.X = Lerp(lean.X, sideway * 0.02f, 10.0f * delta);
|
||||
lean.Y = Lerp(lean.Y, forward * 0.015f, 10.0f * delta);
|
||||
|
||||
UpdateCameraFPS(ref camera);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawLevel();
|
||||
EndMode3D();
|
||||
|
||||
// Draw info box
|
||||
DrawRectangle(5, 5, 330, 75, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(5, 5, 330, 75, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
float velLen = Vector2Length(new Vector2(player.Velocity.X, player.Velocity.Z));
|
||||
DrawText($"- Velocity Len: ({velLen:00.000})", 15, 60, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Update body considering current world state
|
||||
private void UpdateBody(ref Body body, float rot, int side, int forward, bool jumpPressed, bool crouchHold)
|
||||
{
|
||||
Vector2 input = new Vector2((float)side, (float)-forward);
|
||||
|
||||
// Upstream guards this with `#if defined(NORMALIZE_INPUT)`, which is always true given the
|
||||
// `#define NORMALIZE_INPUT 0` above it (defined() tests definedness, not the value), so the
|
||||
// diagonal-movement normalization is active.
|
||||
// Slow down diagonal movement
|
||||
if ((side != 0) && (forward != 0)) input = Vector2Normalize(input);
|
||||
|
||||
float delta = GetFrameTime();
|
||||
|
||||
if (!body.IsGrounded) body.Velocity.Y -= GRAVITY * delta;
|
||||
|
||||
if (body.IsGrounded && jumpPressed)
|
||||
{
|
||||
body.Velocity.Y = JUMP_FORCE;
|
||||
body.IsGrounded = false;
|
||||
|
||||
// Sound can be played at this moment
|
||||
//SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001));
|
||||
//PlaySound(fxJump);
|
||||
}
|
||||
|
||||
Vector3 front = new Vector3(MathF.Sin(rot), 0.0f, MathF.Cos(rot));
|
||||
Vector3 right = new Vector3(MathF.Cos(-rot), 0.0f, MathF.Sin(-rot));
|
||||
|
||||
Vector3 desiredDir = new Vector3(
|
||||
input.X * right.X + input.Y * front.X,
|
||||
0.0f,
|
||||
input.X * right.Z + input.Y * front.Z);
|
||||
body.Dir = Vector3Lerp(body.Dir, desiredDir, CONTROL * delta);
|
||||
|
||||
float decel = (body.IsGrounded ? FRICTION : AIR_DRAG);
|
||||
Vector3 hvel = new Vector3(body.Velocity.X * decel, 0.0f, body.Velocity.Z * decel);
|
||||
|
||||
float hvelLength = Vector3Length(hvel); // Magnitude
|
||||
if (hvelLength < (MAX_SPEED * 0.01f)) hvel = new Vector3(0, 0, 0);
|
||||
|
||||
// This is what creates strafing
|
||||
float speed = Vector3DotProduct(hvel, body.Dir);
|
||||
|
||||
// Whenever the amount of acceleration to add is clamped by the maximum acceleration constant,
|
||||
// a Player can make the speed faster by bringing the direction closer to horizontal velocity angle
|
||||
// More info here: https://youtu.be/v3zT3Z5apaM?t=165
|
||||
float maxSpeed = (crouchHold ? CROUCH_SPEED : MAX_SPEED);
|
||||
float accel = Clamp(maxSpeed - speed, 0.0f, MAX_ACCEL * delta);
|
||||
hvel.X += body.Dir.X * accel;
|
||||
hvel.Z += body.Dir.Z * accel;
|
||||
|
||||
body.Velocity.X = hvel.X;
|
||||
body.Velocity.Z = hvel.Z;
|
||||
|
||||
body.Position.X += body.Velocity.X * delta;
|
||||
body.Position.Y += body.Velocity.Y * delta;
|
||||
body.Position.Z += body.Velocity.Z * delta;
|
||||
|
||||
// Fancy collision system against the floor
|
||||
if (body.Position.Y <= 0.0f)
|
||||
{
|
||||
body.Position.Y = 0.0f;
|
||||
body.Velocity.Y = 0.0f;
|
||||
body.IsGrounded = true; // Enable jumping
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera for FPS behaviour
|
||||
private void UpdateCameraFPS(ref Camera3D camera)
|
||||
{
|
||||
Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
Vector3 targetOffset = new Vector3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
// Left and right
|
||||
Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.X);
|
||||
|
||||
// Clamp view up
|
||||
float maxAngleUp = Vector3Angle(up, yaw);
|
||||
maxAngleUp -= 0.001f; // Avoid numerical errors
|
||||
if (-(lookRotation.Y) > maxAngleUp) { lookRotation.Y = -maxAngleUp; }
|
||||
|
||||
// Clamp view down
|
||||
float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw);
|
||||
maxAngleDown *= -1.0f; // Downwards angle is negative
|
||||
maxAngleDown += 0.001f; // Avoid numerical errors
|
||||
if (-(lookRotation.Y) < maxAngleDown) { lookRotation.Y = -maxAngleDown; }
|
||||
|
||||
// Up and down
|
||||
Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up));
|
||||
|
||||
// Rotate view vector around right axis
|
||||
float pitchAngle = -lookRotation.Y - lean.Y;
|
||||
pitchAngle = Clamp(pitchAngle, -MathF.PI / 2 + 0.0001f, MathF.PI / 2 - 0.0001f); // Clamp angle so it doesn't go past straight up or straight down
|
||||
Vector3 pitch = Vector3RotateByAxisAngle(yaw, right, pitchAngle);
|
||||
|
||||
// Head animation
|
||||
// Rotate up direction around forward axis
|
||||
float headSin = MathF.Sin(headTimer * MathF.PI);
|
||||
float headCos = MathF.Cos(headTimer * MathF.PI);
|
||||
const float stepRotation = 0.01f;
|
||||
camera.Up = Vector3RotateByAxisAngle(up, pitch, headSin * stepRotation + lean.X);
|
||||
|
||||
// Camera BOB
|
||||
const float bobSide = 0.1f;
|
||||
const float bobUp = 0.15f;
|
||||
Vector3 bobbing = Vector3Scale(right, headSin * bobSide);
|
||||
bobbing.Y = MathF.Abs(headCos * bobUp);
|
||||
|
||||
camera.Position = Vector3Add(camera.Position, Vector3Scale(bobbing, walkLerp));
|
||||
camera.Target = Vector3Add(camera.Position, pitch);
|
||||
}
|
||||
|
||||
// Draw game level
|
||||
private void DrawLevel()
|
||||
{
|
||||
const int floorExtent = 25;
|
||||
const float tileSize = 5.0f;
|
||||
Color tileColor1 = new Color(150, 200, 200, 255);
|
||||
|
||||
// Floor tiles
|
||||
for (int y = -floorExtent; y < floorExtent; y++)
|
||||
{
|
||||
for (int x = -floorExtent; x < floorExtent; x++)
|
||||
{
|
||||
if ((y & 1) != 0 && (x & 1) != 0)
|
||||
{
|
||||
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), tileColor1);
|
||||
}
|
||||
else if ((y & 1) == 0 && (x & 1) == 0)
|
||||
{
|
||||
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), Color.LightGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 towerSize = new Vector3(16.0f, 32.0f, 16.0f);
|
||||
Color towerColor = new Color(150, 200, 200, 255);
|
||||
|
||||
Vector3 towerPos = new Vector3(16.0f, 16.0f, 16.0f);
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.X *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.Z *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.X *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
// Red sun
|
||||
DrawSphere(new Vector3(300.0f, 300.0f, 0.0f), 100.0f, new Color(255, 0, 0, 255));
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera fps");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFps();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Initialize 3d camera free
|
||||
* raylib [core] example - 3d camera free
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,74 +18,100 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dFree
|
||||
public partial class Camera3dFree : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 3D Free";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera free";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(10, 10, 320, 93, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 93, Color.Blue);
|
||||
|
||||
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFree();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Z))
|
||||
{
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(10, 10, 320, 133, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 133, Color.Blue);
|
||||
|
||||
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Initialize 3d camera mode
|
||||
* raylib [core] example - 3d camera mode
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,63 +18,82 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dMode
|
||||
public partial class Camera3dMode : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
|
||||
public string Name => "Core / Camera 3D Mode";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera mode";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera mode");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dMode();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
286
Examples/Core/ClipboardText.cs
Normal file
286
Examples/Core/ClipboardText.cs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - clipboard text
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Ananth S (@Ananth1839) 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 Ananth S (@Ananth1839)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream C example uses raygui (GuiTextBox/GuiButton/GuiLabel) for its UI.
|
||||
// raygui is not bound in raylib-cs, so the widgets below are minimal re-implementations
|
||||
// using plain raylib drawing/input. Clipboard behaviour (cut/copy/paste and CTRL+X/C/V
|
||||
// shortcuts) matches the original.
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class ClipboardText : IExample
|
||||
{
|
||||
private const int MaxTextSamples = 5;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Clipboard Text";
|
||||
|
||||
public string Title => "raylib [core] example - clipboard text";
|
||||
|
||||
private string[] sampleTexts;
|
||||
private string clipboardText;
|
||||
private StringBuilder inputBuffer;
|
||||
|
||||
// UI required variables
|
||||
private bool textBoxEditMode;
|
||||
|
||||
private bool btnCutPressed;
|
||||
private bool btnCopyPressed;
|
||||
private bool btnPastePressed;
|
||||
private bool btnClearPressed;
|
||||
private bool btnRandomPressed;
|
||||
|
||||
private int framesCounter;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define some sample texts
|
||||
sampleTexts = new string[]
|
||||
{
|
||||
"Hello from raylib!",
|
||||
"The quick brown fox jumps over the lazy dog",
|
||||
"Clipboard operations are useful!",
|
||||
"raylib is a simple and easy-to-use library",
|
||||
"Copy and paste me!"
|
||||
};
|
||||
|
||||
clipboardText = null;
|
||||
inputBuffer = new StringBuilder("Hello from raylib!"); // Random initial string
|
||||
|
||||
// UI required variables
|
||||
textBoxEditMode = false;
|
||||
|
||||
btnCutPressed = false;
|
||||
btnCopyPressed = false;
|
||||
btnPastePressed = false;
|
||||
btnClearPressed = false;
|
||||
btnRandomPressed = false;
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
framesCounter++;
|
||||
|
||||
// Handle button interactions
|
||||
if (btnCutPressed)
|
||||
{
|
||||
SetClipboardText(inputBuffer.ToString());
|
||||
clipboardText = GetClipboardText_();
|
||||
inputBuffer.Clear(); // Quick solution to clear text
|
||||
}
|
||||
|
||||
if (btnCopyPressed)
|
||||
{
|
||||
SetClipboardText(inputBuffer.ToString()); // Copy text to clipboard
|
||||
clipboardText = GetClipboardText_(); // Get text from clipboard
|
||||
}
|
||||
|
||||
if (btnPastePressed)
|
||||
{
|
||||
// Paste text from clipboard
|
||||
clipboardText = GetClipboardText_();
|
||||
if (clipboardText != null) SetInputBuffer(clipboardText);
|
||||
}
|
||||
|
||||
if (btnClearPressed)
|
||||
{
|
||||
inputBuffer.Clear(); // Quick solution to clear text
|
||||
}
|
||||
|
||||
if (btnRandomPressed)
|
||||
{
|
||||
// Get random text from sample list
|
||||
SetInputBuffer(sampleTexts[GetRandomValue(0, MaxTextSamples - 1)]);
|
||||
}
|
||||
|
||||
// Quick cut/copy/paste with keyboard shortcuts
|
||||
if (IsKeyDown(KeyboardKey.LeftControl) || IsKeyDown(KeyboardKey.RightControl))
|
||||
{
|
||||
if (IsKeyPressed(KeyboardKey.X))
|
||||
{
|
||||
SetClipboardText(inputBuffer.ToString());
|
||||
inputBuffer.Clear(); // Quick solution to clear text
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.C)) SetClipboardText(inputBuffer.ToString());
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.V))
|
||||
{
|
||||
clipboardText = GetClipboardText_();
|
||||
if (clipboardText != null) SetInputBuffer(clipboardText);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw instructions
|
||||
GuiLabel(new Rectangle(50, 20, 700, 36), "Use the BUTTONS or KEY SHORTCUTS:");
|
||||
DrawText("[CTRL+X] - CUT | [CTRL+C] COPY | [CTRL+V] | PASTE", 50, 60, 20, Color.Maroon);
|
||||
|
||||
// Draw text box
|
||||
if (GuiTextBox(new Rectangle(50, 120, 652, 40), inputBuffer, 256, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
|
||||
|
||||
// Random text button
|
||||
btnRandomPressed = GuiButton(new Rectangle(50 + 652 + 8, 120, 40, 40), "RND");
|
||||
|
||||
// Draw buttons
|
||||
btnCutPressed = GuiButton(new Rectangle(50, 180, 158, 40), "CUT");
|
||||
btnCopyPressed = GuiButton(new Rectangle(50 + 165, 180, 158, 40), "COPY");
|
||||
btnPastePressed = GuiButton(new Rectangle(50 + 165 * 2, 180, 158, 40), "PASTE");
|
||||
btnClearPressed = GuiButton(new Rectangle(50 + 165 * 3, 180, 158, 40), "CLEAR");
|
||||
|
||||
// Draw clipboard status
|
||||
GuiLabel(new Rectangle(50, 260, 700, 40), "Clipboard current text data:");
|
||||
GuiTextBoxReadOnly(new Rectangle(50, 300, 700, 40), clipboardText);
|
||||
GuiLabel(new Rectangle(50, 360, 700, 40), "Try copying text from other applications and pasting here!");
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Replace input buffer contents (equivalent to raylib TextCopy into a fixed buffer)
|
||||
private void SetInputBuffer(string text)
|
||||
{
|
||||
inputBuffer.Clear();
|
||||
if (text != null)
|
||||
{
|
||||
if (text.Length > 255) text = text.Substring(0, 255);
|
||||
inputBuffer.Append(text);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Minimal raygui-like widgets (plain raylib re-implementation)
|
||||
//----------------------------------------------------------------------------------
|
||||
private static void GuiLabel(Rectangle bounds, string text)
|
||||
{
|
||||
DrawText(text, (int)bounds.X, (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
private static bool GuiButton(Rectangle bounds, string text)
|
||||
{
|
||||
bool pressed = false;
|
||||
Vector2 mouse = GetMousePosition();
|
||||
bool hover = CheckCollisionPointRec(mouse, bounds);
|
||||
|
||||
Color fill = hover ? (IsMouseButtonDown(MouseButton.Left) ? Color.SkyBlue : Color.LightGray) : Color.RayWhite;
|
||||
DrawRectangleRec(bounds, fill);
|
||||
DrawRectangleLinesEx(bounds, 1, hover ? Color.Blue : Color.Gray);
|
||||
|
||||
int textWidth = MeasureText(text, 20);
|
||||
DrawText(text, (int)(bounds.X + (bounds.Width - textWidth) / 2), (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
|
||||
|
||||
if (hover && IsMouseButtonReleased(MouseButton.Left)) pressed = true;
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
private bool GuiTextBox(Rectangle bounds, StringBuilder text, int maxChars, bool editMode)
|
||||
{
|
||||
bool pressed = false;
|
||||
Vector2 mouse = GetMousePosition();
|
||||
bool hover = CheckCollisionPointRec(mouse, bounds);
|
||||
|
||||
if (editMode)
|
||||
{
|
||||
// Get char pressed (unicode character) on the queue
|
||||
int key = GetCharPressed();
|
||||
while (key > 0)
|
||||
{
|
||||
if ((key >= 32) && (key <= 125) && (text.Length < maxChars - 1))
|
||||
{
|
||||
text.Append((char)key);
|
||||
}
|
||||
|
||||
key = GetCharPressed();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Backspace) && (text.Length > 0)) text.Remove(text.Length - 1, 1);
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.RayWhite);
|
||||
DrawRectangleLinesEx(bounds, editMode ? 2 : 1, editMode ? Color.Red : (hover ? Color.Blue : Color.Gray));
|
||||
|
||||
string content = text.ToString();
|
||||
DrawText(content, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
|
||||
|
||||
// Draw blinking cursor while editing
|
||||
if (editMode && ((framesCounter / 20) % 2 == 0))
|
||||
{
|
||||
DrawText("_", (int)bounds.X + 4 + MeasureText(content, 20), (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
if (hover && IsMouseButtonPressed(MouseButton.Left)) pressed = true;
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
private static void GuiTextBoxReadOnly(Rectangle bounds, string text)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (text != null) DrawText(text, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.Gray);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ClipboardText();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
253
Examples/Core/ComputeHash.cs
Normal file
253
Examples/Core/ComputeHash.cs
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - compute hash
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream C example uses raygui (GuiTextBox/GuiButton/GuiLabel) for its UI.
|
||||
// raygui is not bound in raylib-cs, so the widgets below are minimal re-implementations
|
||||
// using plain raylib drawing/input. The hashing/Base64 logic is a faithful port.
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public unsafe partial class ComputeHash : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Compute Hash";
|
||||
|
||||
public string Title => "raylib [core] example - compute hash";
|
||||
|
||||
// UI controls variables
|
||||
private StringBuilder textInput;
|
||||
private bool textBoxEditMode;
|
||||
private bool btnComputeHashes;
|
||||
|
||||
// Data hash values
|
||||
private uint hashCRC32;
|
||||
private uint[] hashMD5;
|
||||
private uint[] hashSHA1;
|
||||
private uint[] hashSHA256;
|
||||
|
||||
// Base64 encoded data
|
||||
private string base64Text;
|
||||
|
||||
private int framesCounter;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
textInput = new StringBuilder("The quick brown fox jumps over the lazy dog.");
|
||||
textBoxEditMode = false;
|
||||
btnComputeHashes = false;
|
||||
|
||||
hashCRC32 = 0;
|
||||
hashMD5 = null;
|
||||
hashSHA1 = null;
|
||||
hashSHA256 = null;
|
||||
|
||||
base64Text = null;
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
framesCounter++;
|
||||
|
||||
if (btnComputeHashes)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(textInput.ToString());
|
||||
int textInputLen = bytes.Length;
|
||||
|
||||
fixed (byte* textInputPtr = bytes)
|
||||
{
|
||||
int base64TextSize;
|
||||
|
||||
// Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
|
||||
sbyte* base64 = EncodeDataBase64(textInputPtr, textInputLen, &base64TextSize);
|
||||
base64Text = (base64 != null) ? new string(base64) : null;
|
||||
MemFree(base64); // Free Base64 text data (kept managed above)
|
||||
|
||||
hashCRC32 = ComputeCRC32(textInputPtr, textInputLen); // Compute CRC32 hash code (4 bytes)
|
||||
hashMD5 = CopyHash(ComputeMD5(textInputPtr, textInputLen), 4); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||
hashSHA1 = CopyHash(ComputeSHA1(textInputPtr, textInputLen), 5); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||
hashSHA256 = CopyHash(ComputeSHA256(textInputPtr, textInputLen), 8); // Compute SHA256 hash code, returns static int[8] (32 bytes)
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
GuiLabel(new Rectangle(40, 26, 720, 32), "INPUT DATA (TEXT):", 20);
|
||||
|
||||
if (GuiTextBox(new Rectangle(40, 64, 720, 32), textInput, 95, textBoxEditMode, 10)) textBoxEditMode = !textBoxEditMode;
|
||||
|
||||
btnComputeHashes = GuiButton(new Rectangle(40, 64 + 40, 720, 32), "COMPUTE INPUT DATA HASHES", 10);
|
||||
|
||||
GuiLabel(new Rectangle(40, 160, 720, 32), "INPUT DATA HASH VALUES:", 20);
|
||||
|
||||
GuiLabel(new Rectangle(40, 200, 120, 32), "CRC32 [32 bit]:", 10);
|
||||
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200, 720 - 120, 32), GetDataAsHexText(new uint[] { hashCRC32 }, 1), 10);
|
||||
GuiLabel(new Rectangle(40, 200 + 36, 120, 32), "MD5 [128 bit]:", 10);
|
||||
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36, 720 - 120, 32), GetDataAsHexText(hashMD5, 4), 10);
|
||||
GuiLabel(new Rectangle(40, 200 + 36 * 2, 120, 32), "SHA1 [160 bit]:", 10);
|
||||
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 2, 720 - 120, 32), GetDataAsHexText(hashSHA1, 5), 10);
|
||||
GuiLabel(new Rectangle(40, 200 + 36 * 3, 120, 32), "SHA256 [256 bit]:", 10);
|
||||
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 3, 720 - 120, 32), GetDataAsHexText(hashSHA256, 8), 10);
|
||||
|
||||
GuiLabel(new Rectangle(40, 200 + 36 * 5 - 30, 320, 32), "BONUS - BAS64 ENCODED STRING:", 10);
|
||||
GuiLabel(new Rectangle(40, 200 + 36 * 5, 120, 32), "BASE64 ENCODING:", 10);
|
||||
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 5, 720 - 120, 32), base64Text, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
private static uint[] CopyHash(uint* data, int count)
|
||||
{
|
||||
if (data == null) return null;
|
||||
|
||||
uint[] result = new uint[count];
|
||||
for (int i = 0; i < count; i++) result[i] = data[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetDataAsHexText(uint[] data, int dataSize)
|
||||
{
|
||||
if ((data != null) && (dataSize > 0) && (dataSize < ((128 / 8) - 1)))
|
||||
{
|
||||
StringBuilder text = new StringBuilder();
|
||||
for (int i = 0; i < dataSize; i++) text.Append(data[i].ToString("X8"));
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
return "00000000";
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Minimal raygui-like widgets (plain raylib re-implementation)
|
||||
//----------------------------------------------------------------------------------
|
||||
private static void GuiLabel(Rectangle bounds, string text, int fontSize)
|
||||
{
|
||||
DrawText(text, (int)bounds.X, (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
|
||||
}
|
||||
|
||||
private static bool GuiButton(Rectangle bounds, string text, int fontSize)
|
||||
{
|
||||
bool pressed = false;
|
||||
Vector2 mouse = GetMousePosition();
|
||||
bool hover = CheckCollisionPointRec(mouse, bounds);
|
||||
|
||||
Color fill = hover ? (IsMouseButtonDown(MouseButton.Left) ? Color.SkyBlue : Color.LightGray) : Color.RayWhite;
|
||||
DrawRectangleRec(bounds, fill);
|
||||
DrawRectangleLinesEx(bounds, 1, hover ? Color.Blue : Color.Gray);
|
||||
|
||||
int textWidth = MeasureText(text, fontSize);
|
||||
DrawText(text, (int)(bounds.X + (bounds.Width - textWidth) / 2), (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
|
||||
|
||||
if (hover && IsMouseButtonReleased(MouseButton.Left)) pressed = true;
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
private bool GuiTextBox(Rectangle bounds, StringBuilder text, int maxChars, bool editMode, int fontSize)
|
||||
{
|
||||
bool pressed = false;
|
||||
Vector2 mouse = GetMousePosition();
|
||||
bool hover = CheckCollisionPointRec(mouse, bounds);
|
||||
|
||||
if (editMode)
|
||||
{
|
||||
int key = GetCharPressed();
|
||||
while (key > 0)
|
||||
{
|
||||
if ((key >= 32) && (key <= 125) && (text.Length < maxChars - 1))
|
||||
{
|
||||
text.Append((char)key);
|
||||
}
|
||||
|
||||
key = GetCharPressed();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Backspace) && (text.Length > 0)) text.Remove(text.Length - 1, 1);
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.RayWhite);
|
||||
DrawRectangleLinesEx(bounds, editMode ? 2 : 1, editMode ? Color.Red : (hover ? Color.Blue : Color.Gray));
|
||||
|
||||
string content = text.ToString();
|
||||
DrawText(content, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
|
||||
|
||||
if (editMode && ((framesCounter / 20) % 2 == 0))
|
||||
{
|
||||
DrawText("_", (int)bounds.X + 4 + MeasureText(content, fontSize), (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
|
||||
}
|
||||
|
||||
if (hover && IsMouseButtonPressed(MouseButton.Left)) pressed = true;
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
private static void GuiTextBoxReadOnly(Rectangle bounds, string text, int fontSize)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (text != null) DrawText(text, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.Gray);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - compute hash");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ComputeHash();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
188
Examples/Core/CustomFrameControl.cs
Normal file
188
Examples/Core/CustomFrameControl.cs
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - custom frame control
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: WARNING: This is an example for advanced users willing to have full control over
|
||||
* the frame processes. By default, EndDrawing() calls the following processes:
|
||||
* 1. Draw remaining batch data: rlDrawRenderBatchActive()
|
||||
* 2. SwapScreenBuffer()
|
||||
* 3. Frame time control: WaitTime()
|
||||
* 4. PollInputEvents()
|
||||
*
|
||||
* To avoid steps 2, 3 and 4, flag SUPPORT_CUSTOM_FRAME_CONTROL can be enabled in
|
||||
* config.h (it requires recompiling raylib). This way those steps are up to the user
|
||||
*
|
||||
* Note that enabling this flag invalidates some functions:
|
||||
* - GetFrameTime()
|
||||
* - SetTargetFPS()
|
||||
* - GetFPS()
|
||||
*
|
||||
* Example originally created with raylib 4.0, last time updated with raylib 4.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) 2021-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
// NOTE: This example is intended to run against a raylib built with SUPPORT_CUSTOM_FRAME_CONTROL,
|
||||
// where EndDrawing() does NOT swap buffers, wait or poll input, leaving those to the user code
|
||||
// below. The stock raylib-cs native library is built WITHOUT that flag, so EndDrawing() still
|
||||
// performs those steps and the manual SwapScreenBuffer()/WaitTime()/PollInputEvents() calls here
|
||||
// run in addition to them. The port is kept faithful to upstream regardless.
|
||||
[ExcludeFromBrowser("manual PollInputEvents/SwapScreenBuffer/WaitTime clashes with the emscripten main loop")]
|
||||
public partial class CustomFrameControl : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Custom Frame Control";
|
||||
|
||||
public string Title => "raylib [core] example - custom frame control";
|
||||
|
||||
// Custom timming variables
|
||||
private double previousTime; // Previous time measure
|
||||
private double currentTime; // Current time measure
|
||||
private double updateDrawTime; // Update + Draw time
|
||||
private double waitTime; // Wait time (if target fps required)
|
||||
private float deltaTime; // Frame time (Update + Draw + Wait time)
|
||||
|
||||
private float timeCounter; // Accumulative time counter (seconds)
|
||||
private float position; // Circle position
|
||||
private bool pause; // Pause control flag
|
||||
|
||||
private int targetFPS; // Our initial target fps
|
||||
|
||||
public void Init()
|
||||
{
|
||||
previousTime = GetTime();
|
||||
currentTime = 0.0;
|
||||
updateDrawTime = 0.0;
|
||||
waitTime = 0.0;
|
||||
deltaTime = 0.0f;
|
||||
|
||||
timeCounter = 0.0f;
|
||||
position = 0.0f;
|
||||
pause = false;
|
||||
|
||||
targetFPS = 60;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
#if !BROWSER
|
||||
// NOTE: On non web platforms the PollInputEvents just works before the inputs checks
|
||||
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
|
||||
#endif
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space)) pause = !pause;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Up)) targetFPS += 20;
|
||||
else if (IsKeyPressed(KeyboardKey.Down)) targetFPS -= 20;
|
||||
|
||||
if (targetFPS < 0) targetFPS = 0;
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
position += 200 * deltaTime; // We move at 200 pixels per second
|
||||
if (position >= GetScreenWidth()) position = 0;
|
||||
timeCounter += deltaTime; // We count time (seconds)
|
||||
}
|
||||
|
||||
#if BROWSER
|
||||
// NOTE: On web platform for some reason the PollInputEvents only works after the inputs
|
||||
// check, so just call it after check all your inputs (on web)
|
||||
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
|
||||
#endif
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = 0; i < GetScreenWidth() / 200; i++) DrawRectangle(200 * i, 0, 1, GetScreenHeight(), Color.SkyBlue);
|
||||
|
||||
DrawCircle((int)position, GetScreenHeight() / 2 - 25, 50, Color.Red);
|
||||
|
||||
DrawText($"{timeCounter * 1000.0f:000} ms", (int)position - 40, GetScreenHeight() / 2 - 100, 20, Color.Maroon);
|
||||
DrawText($"PosX: {position:000}", (int)position - 50, GetScreenHeight() / 2 + 40, 20, Color.Black);
|
||||
|
||||
DrawText("Circle is moving at a constant 200 pixels/sec,\nindependently of the frame rate.", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("PRESS SPACE to PAUSE MOVEMENT", 10, GetScreenHeight() - 60, 20, Color.Gray);
|
||||
DrawText("PRESS UP | DOWN to CHANGE TARGET FPS", 10, GetScreenHeight() - 30, 20, Color.Gray);
|
||||
DrawText($"TARGET FPS: {targetFPS}", GetScreenWidth() - 220, 10, 20, Color.Lime);
|
||||
if (deltaTime != 0)
|
||||
{
|
||||
DrawText($"CURRENT FPS: {(int)(1.0f / deltaTime)}", GetScreenWidth() - 220, 40, 20, Color.Green);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
|
||||
// NOTE: In case raylib is configured to SUPPORT_CUSTOM_FRAME_CONTROL,
|
||||
// Events polling, screen buffer swap and frame time control must be managed by the user
|
||||
|
||||
SwapScreenBuffer(); // Flip the back buffer to screen (front buffer)
|
||||
|
||||
currentTime = GetTime();
|
||||
updateDrawTime = currentTime - previousTime;
|
||||
|
||||
if (targetFPS > 0) // We want a fixed frame rate
|
||||
{
|
||||
waitTime = (1.0f / (float)targetFPS) - updateDrawTime;
|
||||
if (waitTime > 0.0)
|
||||
{
|
||||
WaitTime((float)waitTime);
|
||||
currentTime = GetTime();
|
||||
deltaTime = (float)(currentTime - previousTime);
|
||||
}
|
||||
}
|
||||
else deltaTime = (float)updateDrawTime; // Framerate could be variable
|
||||
|
||||
previousTime = currentTime;
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom frame control");
|
||||
|
||||
// NOTE: Not calling SetTargetFPS(): this example manages frame timing manually with
|
||||
// WaitTime() (SetTargetFPS/GetFrameTime/GetFPS are invalidated by SUPPORT_CUSTOM_FRAME_CONTROL)
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CustomFrameControl();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Custom logging
|
||||
* raylib [core] example - custom logging
|
||||
*
|
||||
* 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: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 2.5
|
||||
*
|
||||
* Example contributed by Pablo Marcos Oltra (@pamarcos) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2018 Pablo Marcos Oltra (@pamarcos) 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) 2018-2025 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -17,11 +21,23 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public unsafe class CustomLogging
|
||||
public unsafe partial class CustomLogging : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Custom Logging";
|
||||
|
||||
public string Title => "raylib [core] example - custom logging";
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })]
|
||||
private static void LogCustom(int logLevel, sbyte* text, sbyte* args)
|
||||
{
|
||||
#if BROWSER
|
||||
// WebAssembly can't invoke the C varargs vsprintf/vsnprintf that Logging.GetLogMessage relies on
|
||||
// (the wasm runtime traps with "function signature mismatch"), so log the raw, unformatted text.
|
||||
string message = Marshal.PtrToStringUTF8(new IntPtr(text)) ?? string.Empty;
|
||||
#else
|
||||
var message = Logging.GetLogMessage(new IntPtr(text), new IntPtr(args));
|
||||
|
||||
/*Console.ForegroundColor = (TraceLogLevel)logLevel switch
|
||||
|
|
@ -36,50 +52,64 @@ public unsafe class CustomLogging
|
|||
TraceLogLevel.LOG_NONE => ConsoleColor.White,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null)
|
||||
};*/
|
||||
#endif
|
||||
|
||||
Console.WriteLine($"Custom " + message);
|
||||
// Console.ResetColor();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// First thing we do is setting our custom logger to ensure everything raylib logs
|
||||
// will use our own logger instead of its internal one
|
||||
SetTraceLogCallback(&LogCustom);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
#if !BROWSER
|
||||
// Restore the default formatting logger on desktop. On WebAssembly we leave the (wasm-safe)
|
||||
// custom logger in place — Logging.LogConsole formats via vsprintf, which traps on wasm.
|
||||
SetTraceLogCallback(&Logging.LogConsole);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// First thing we do is setting our custom logger to ensure everything raylib logs
|
||||
// will use our own logger instead of its internal one
|
||||
SetTraceLogCallback(&LogCustom);
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging");
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CustomLogging();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
SetTraceLogCallback(&Logging.LogConsole);
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -21,108 +21,137 @@ namespace Examples.Core;
|
|||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
public class DeltaTime
|
||||
public partial class DeltaTime : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// The speed applied to both circles
|
||||
private const float speed = 10.0f;
|
||||
private const float circleRadius = 32.0f;
|
||||
|
||||
private int currentFps;
|
||||
|
||||
// Store the position for the both of the circles
|
||||
private Vector2 deltaCircle;
|
||||
private Vector2 frameCircle;
|
||||
|
||||
public string Name => "Core / Delta Time";
|
||||
|
||||
public string Title => "raylib [core] example - delta time";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
currentFps = 60;
|
||||
|
||||
// Store the position for the both of the circles
|
||||
deltaCircle = new Vector2(0, (float)screenHeight / 3.0f);
|
||||
frameCircle = new Vector2(0, (float)screenHeight * (2.0f / 3.0f));
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Adjust the FPS target based on the mouse wheel
|
||||
var 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();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
var game = new DeltaTime();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// 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();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
205
Examples/Core/DirectoryFiles.cs
Normal file
205
Examples/Core/DirectoryFiles.cs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - directory files
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed by Hugo ARNAL (@hugoarnal) 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 Hugo ARNAL (@hugoarnal)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The original example relies on raygui (GuiButton, GuiLabel, GuiListViewEx) for its UI.
|
||||
// raygui is not part of the raylib-cs bindings, so the back button, directory label and file
|
||||
// list view are reimplemented here with plain raylib primitives. The directory navigation
|
||||
// behaviour (enter directories, go back) is preserved.
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class DirectoryFiles : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const string FileFilter = "DIRS*;.png;.c";
|
||||
|
||||
public string Name => "Core / Directory Files";
|
||||
|
||||
public string Title => "raylib [core] example - directory files";
|
||||
|
||||
private string directory;
|
||||
private FilePathList files;
|
||||
|
||||
private bool btnBackPressed;
|
||||
|
||||
private int listScrollIndex;
|
||||
private int listItemActive;
|
||||
private int listItemFocused;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
directory = GetWorkingDirectoryAsString();
|
||||
|
||||
// Load file-paths on current working directory
|
||||
// NOTE: LoadDirectoryFiles() loads files and directories by default,
|
||||
// use LoadDirectoryFilesEx() for custom filters and recursive directories loading
|
||||
//files = LoadDirectoryFiles(directory);
|
||||
files = LoadDirectoryFilesEx(directory, FileFilter, false);
|
||||
|
||||
btnBackPressed = false;
|
||||
|
||||
listScrollIndex = 0;
|
||||
listItemActive = -1;
|
||||
listItemFocused = -1;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (btnBackPressed)
|
||||
{
|
||||
directory = GetPrevDirectoryPath(directory);
|
||||
UnloadDirectoryFiles(files);
|
||||
files = LoadDirectoryFilesEx(directory, FileFilter, false);
|
||||
|
||||
listScrollIndex = 0;
|
||||
listItemActive = -1;
|
||||
listItemFocused = -1;
|
||||
}
|
||||
|
||||
if ((listItemActive >= 0) && (listItemActive < (int)files.Count))
|
||||
{
|
||||
string selected = files[(uint)listItemActive];
|
||||
bool isDirectory = DirectoryExists(selected);
|
||||
if (isDirectory)
|
||||
{
|
||||
directory = selected;
|
||||
UnloadDirectoryFiles(files);
|
||||
files = LoadDirectoryFilesEx(directory, FileFilter, false);
|
||||
|
||||
listScrollIndex = 0;
|
||||
listItemActive = -1;
|
||||
listItemFocused = -1;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
Vector2 mouse = GetMousePosition();
|
||||
|
||||
// Back button "<"
|
||||
Rectangle backBounds = new Rectangle(40.0f, 10.0f, 48, 28);
|
||||
bool backHover = CheckCollisionPointRec(mouse, backBounds);
|
||||
DrawRectangleRec(backBounds, backHover ? Color.SkyBlue : Color.LightGray);
|
||||
DrawRectangleLinesEx(backBounds, 1, Color.Gray);
|
||||
int backTextWidth = MeasureText("<", 20);
|
||||
DrawText("<", (int)(backBounds.X + (backBounds.Width - backTextWidth) / 2), (int)(backBounds.Y + 4), 20, Color.DarkGray);
|
||||
btnBackPressed = backHover && IsMouseButtonReleased(MouseButton.Left);
|
||||
|
||||
// Current directory label
|
||||
DrawText(directory, 40 + 48 + 10, 16, 20, Color.DarkGray);
|
||||
|
||||
// File list view
|
||||
Rectangle listBounds = new Rectangle(0, 50, GetScreenWidth(), GetScreenHeight() - 50);
|
||||
DrawRectangleRec(listBounds, Color.RayWhite);
|
||||
DrawRectangleLinesEx(listBounds, 1, Color.Gray);
|
||||
|
||||
int count = (int)files.Count;
|
||||
float rowHeight = 28;
|
||||
int visibleRows = (int)(listBounds.Height / rowHeight);
|
||||
|
||||
bool mouseInList = CheckCollisionPointRec(mouse, listBounds);
|
||||
if (mouseInList)
|
||||
{
|
||||
listScrollIndex -= (int)GetMouseWheelMove();
|
||||
}
|
||||
int maxScroll = Math.Max(0, count - visibleRows);
|
||||
listScrollIndex = Math.Clamp(listScrollIndex, 0, maxScroll);
|
||||
|
||||
listItemFocused = -1;
|
||||
for (int i = 0; i < visibleRows; i++)
|
||||
{
|
||||
int itemIndex = listScrollIndex + i;
|
||||
if (itemIndex >= count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Rectangle rowRec = new Rectangle(listBounds.X + 1, listBounds.Y + 1 + i * rowHeight, listBounds.Width - 2, rowHeight);
|
||||
bool rowHover = mouseInList && CheckCollisionPointRec(mouse, rowRec);
|
||||
|
||||
if (itemIndex == listItemActive)
|
||||
{
|
||||
DrawRectangleRec(rowRec, Fade(Color.SkyBlue, 0.7f));
|
||||
}
|
||||
else if (rowHover)
|
||||
{
|
||||
DrawRectangleRec(rowRec, Fade(Color.SkyBlue, 0.3f));
|
||||
}
|
||||
|
||||
if (rowHover)
|
||||
{
|
||||
listItemFocused = itemIndex;
|
||||
if (IsMouseButtonReleased(MouseButton.Left))
|
||||
{
|
||||
listItemActive = itemIndex;
|
||||
}
|
||||
}
|
||||
|
||||
DrawText(files[(uint)itemIndex], (int)rowRec.X + 40, (int)rowRec.Y + 8, 10, Color.DarkGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadDirectoryFiles(files);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - directory files");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DirectoryFiles();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +1,125 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Windows drop files
|
||||
* raylib [core] example - drop files
|
||||
*
|
||||
* This example only works on platforms that support drag ref drop (Windows, Linux, OSX, Html5?)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* NOTE: This example only works on platforms that support drag & drop (Windows, Linux, OSX, Html5?)
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class DropFiles
|
||||
[ExcludeFromBrowser]
|
||||
public partial class DropFiles : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public const int MaxFilepathRecorded = 4096;
|
||||
|
||||
public string Name => "Core / Drop Files";
|
||||
|
||||
public string Title => "raylib [core] example - drop files";
|
||||
|
||||
private List<string> filePaths;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// We will register a maximum of filepaths
|
||||
filePaths = new();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsFileDropped())
|
||||
{
|
||||
var droppedFiles = GetDroppedFiles();
|
||||
|
||||
for (var i = 0; i < droppedFiles.Length; i++)
|
||||
{
|
||||
if (filePaths.Count < (MaxFilepathRecorded - 1))
|
||||
{
|
||||
filePaths.Add(droppedFiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (filePaths.Count == 0)
|
||||
{
|
||||
DrawText("Drop your files to this window!", 100, 40, 20, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Dropped files:", 100, 40, 20, Color.DarkGray);
|
||||
|
||||
for (var i = 0; i < filePaths.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, Fade(Color.LightGray, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, Fade(Color.LightGray, 0.3f));
|
||||
}
|
||||
|
||||
DrawText(filePaths[i], 120, 100 + 40 * i, 10, Color.Gray);
|
||||
}
|
||||
|
||||
DrawText("Drop new files...", 100, 110 + 40 * filePaths.Count, 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - drop files");
|
||||
|
||||
string[] files = new string[0];
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DropFiles();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsFileDropped())
|
||||
{
|
||||
files = Raylib.GetDroppedFiles();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (files.Length == 0)
|
||||
{
|
||||
DrawText("Drop your files to this window!", 100, 40, 20, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Dropped files:", 100, 40, 20, Color.DarkGray);
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, ColorAlpha(Color.LightGray, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, ColorAlpha(Color.LightGray, 0.3f));
|
||||
}
|
||||
DrawText(files[i], 120, 100 + 40 * i, 10, Color.Gray);
|
||||
}
|
||||
|
||||
DrawText("Drop new files...", 100, 110 + 40 * files.Length, 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
173
Examples/Core/HighDpiDemo.cs
Normal file
173
Examples/Core/HighDpiDemo.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - highdpi demo
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Jonathan Marler (@marler8997) 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 Jonathan Marler (@marler8997)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
[ExcludeFromBrowser("monitor/DPI APIs are meaningless on the fixed wasm canvas")]
|
||||
public partial class HighDpiDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / High DPI Demo";
|
||||
|
||||
public string Title => "raylib [core] example - highdpi demo";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.HighDpiWindow | ConfigFlags.ResizableWindow;
|
||||
|
||||
private int logicalGridDescY;
|
||||
private int logicalGridLabelY;
|
||||
private int logicalGridTop;
|
||||
private int logicalGridBottom;
|
||||
private int pixelGridTop;
|
||||
private int pixelGridBottom;
|
||||
private int pixelGridLabelY;
|
||||
private int pixelGridDescY;
|
||||
private int cellSize;
|
||||
private float cellSizePx;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
SetWindowMinSize(450, 450);
|
||||
|
||||
logicalGridDescY = 120;
|
||||
logicalGridLabelY = logicalGridDescY + 30;
|
||||
logicalGridTop = logicalGridLabelY + 30;
|
||||
logicalGridBottom = logicalGridTop + 80;
|
||||
pixelGridTop = logicalGridBottom - 20;
|
||||
pixelGridBottom = pixelGridTop + 80;
|
||||
pixelGridLabelY = pixelGridBottom + 30;
|
||||
pixelGridDescY = pixelGridLabelY + 30;
|
||||
cellSize = 50;
|
||||
cellSizePx = (float)cellSize;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
int monitorCount = GetMonitorCount();
|
||||
|
||||
if ((monitorCount > 1) && IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
SetWindowMonitor((GetCurrentMonitor() + 1) % monitorCount);
|
||||
}
|
||||
|
||||
int currentMonitor = GetCurrentMonitor();
|
||||
Vector2 dpiScale = GetWindowScaleDPI();
|
||||
cellSizePx = ((float)cellSize) / dpiScale.X;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
int windowCenter = GetScreenWidth() / 2;
|
||||
DrawTextCenter($"Dpi Scale: {dpiScale.X:F6}", windowCenter, 30, 40, Color.DarkGray);
|
||||
DrawTextCenter($"Monitor: {currentMonitor + 1}/{monitorCount} ([N] next monitor)", windowCenter, 70, 20, Color.LightGray);
|
||||
DrawTextCenter($"Window is {GetScreenWidth()} \"logical points\" wide", windowCenter, logicalGridDescY, 20, Color.Orange);
|
||||
|
||||
bool odd = true;
|
||||
for (int i = cellSize; i < GetScreenWidth(); i += cellSize, odd = !odd)
|
||||
{
|
||||
if (odd)
|
||||
{
|
||||
DrawRectangle(i, logicalGridTop, cellSize, logicalGridBottom - logicalGridTop, Color.Orange);
|
||||
}
|
||||
|
||||
DrawTextCenter($"{i}", i, logicalGridLabelY, 10, Color.LightGray);
|
||||
DrawLine(i, logicalGridLabelY + 10, i, logicalGridBottom, Color.Gray);
|
||||
}
|
||||
|
||||
odd = true;
|
||||
const int minTextSpace = 30;
|
||||
int lastTextX = -minTextSpace;
|
||||
for (int i = cellSize; i < GetRenderWidth(); i += cellSize, odd = !odd)
|
||||
{
|
||||
int x = (int)(((float)i) / dpiScale.X);
|
||||
if (odd)
|
||||
{
|
||||
DrawRectangle(x, pixelGridTop, (int)cellSizePx, pixelGridBottom - pixelGridTop, new Color(0, 121, 241, 100));
|
||||
}
|
||||
|
||||
DrawLine(x, pixelGridTop, (int)(((float)i) / dpiScale.X), pixelGridLabelY - 10, Color.Gray);
|
||||
|
||||
if ((x - lastTextX) >= minTextSpace)
|
||||
{
|
||||
DrawTextCenter($"{i}", x, pixelGridLabelY, 10, Color.LightGray);
|
||||
lastTextX = x;
|
||||
}
|
||||
}
|
||||
|
||||
DrawTextCenter($"Window is {GetRenderWidth()} \"physical pixels\" wide", windowCenter, pixelGridDescY, 20, Color.Blue);
|
||||
|
||||
string text = "Can you see this?";
|
||||
Vector2 size = MeasureTextEx(GetFontDefault(), text, 20, 3);
|
||||
Vector2 pos = new Vector2(GetScreenWidth() - size.X - 5, GetScreenHeight() - size.Y - 5);
|
||||
DrawTextEx(GetFontDefault(), text, pos, 20, 3, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Draw text centered on the given position
|
||||
private static void DrawTextCenter(string text, int x, int y, int fontSize, Color color)
|
||||
{
|
||||
Vector2 size = MeasureTextEx(GetFontDefault(), text, (float)fontSize, 3);
|
||||
Vector2 pos = new Vector2(x - size.X / 2, y - size.Y / 2);
|
||||
DrawTextEx(GetFontDefault(), text, pos, (float)fontSize, 3, color);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.HighDpiWindow | ConfigFlags.ResizableWindow);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi demo");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HighDpiDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
145
Examples/Core/HighDpiTestbed.cs
Normal file
145
Examples/Core/HighDpiTestbed.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - highdpi testbed
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Ramon Santamaria (@raysan5) 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 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
[ExcludeFromBrowser("fullscreen/borderless/monitor APIs are meaningless on the fixed wasm canvas")]
|
||||
public partial class HighDpiTestbed : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / High DPI Testbed";
|
||||
|
||||
public string Title => "raylib [core] example - highdpi testbed";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow | ConfigFlags.HighDpiWindow;
|
||||
|
||||
private Vector2 scaleDpi;
|
||||
private Vector2 mousePos;
|
||||
private int currentMonitor;
|
||||
private Vector2 windowPos;
|
||||
|
||||
private int gridSpacing; // Grid spacing in pixels
|
||||
|
||||
public void Init()
|
||||
{
|
||||
scaleDpi = GetWindowScaleDPI();
|
||||
mousePos = GetMousePosition();
|
||||
currentMonitor = GetCurrentMonitor();
|
||||
windowPos = GetWindowPosition();
|
||||
|
||||
gridSpacing = 40;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
mousePos = GetMousePosition();
|
||||
currentMonitor = GetCurrentMonitor();
|
||||
scaleDpi = GetWindowScaleDPI();
|
||||
windowPos = GetWindowPosition();
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
ToggleBorderlessWindowed();
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
ToggleFullscreen();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw grid
|
||||
for (int h = 0; h < GetScreenHeight() / gridSpacing + 1; h++)
|
||||
{
|
||||
DrawText($"{h * gridSpacing:D2}", 4, h * gridSpacing - 4, 10, Color.Gray);
|
||||
DrawLine(24, h * gridSpacing, GetScreenWidth(), h * gridSpacing, Color.LightGray);
|
||||
}
|
||||
for (int v = 0; v < GetScreenWidth() / gridSpacing + 1; v++)
|
||||
{
|
||||
DrawText($"{v * gridSpacing:D2}", v * gridSpacing - 10, 4, 10, Color.Gray);
|
||||
DrawLine(v * gridSpacing, 20, v * gridSpacing, GetScreenHeight(), Color.LightGray);
|
||||
}
|
||||
|
||||
// Draw UI info
|
||||
DrawText($"CURRENT MONITOR: {currentMonitor + 1}/{GetMonitorCount()} ({GetMonitorWidth(currentMonitor)}x{GetMonitorHeight(currentMonitor)})", 50, 50, 20, Color.DarkGray);
|
||||
DrawText($"WINDOW POSITION: {(int)windowPos.X}x{(int)windowPos.Y}", 50, 90, 20, Color.DarkGray);
|
||||
DrawText($"SCREEN SIZE: {GetScreenWidth()}x{GetScreenHeight()}", 50, 130, 20, Color.DarkGray);
|
||||
DrawText($"RENDER SIZE: {GetRenderWidth()}x{GetRenderHeight()}", 50, 170, 20, Color.DarkGray);
|
||||
DrawText($"SCALE FACTOR: {scaleDpi.X:F2}x{scaleDpi.Y:F2}", 50, 210, 20, Color.Gray);
|
||||
|
||||
// Draw reference rectangles, top-left and bottom-right corners
|
||||
DrawRectangle(0, 0, 30, 60, Color.Red);
|
||||
DrawRectangle(GetScreenWidth() - 30, GetScreenHeight() - 60, 30, 60, Color.Blue);
|
||||
|
||||
// Draw mouse position
|
||||
DrawCircleV(GetMousePosition(), 20, Color.Maroon);
|
||||
DrawRectangleRec(new Rectangle(mousePos.X - 25, mousePos.Y, 50, 2), Color.Black);
|
||||
DrawRectangleRec(new Rectangle(mousePos.X, mousePos.Y - 25, 2, 50), Color.Black);
|
||||
DrawText($"[{GetMouseX()},{GetMouseY()}]", (int)mousePos.X - 44,
|
||||
(mousePos.Y > GetScreenHeight() - 60) ? (int)mousePos.Y - 46 : (int)mousePos.Y + 30, 20, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// TODO: Unload all loaded resources at this point
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.HighDpiWindow);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HighDpiTestbed();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
224
Examples/Core/InputActions.cs
Normal file
224
Examples/Core/InputActions.cs
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - input actions
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed by Jett (@JettMonstersGoBoom) 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 Jett (@JettMonstersGoBoom)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons
|
||||
// For example instead of using `IsKeyDown(KEY_LEFT)`, you can use `IsActionDown(ACTION_LEFT)`
|
||||
// which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class InputActions : IExample
|
||||
{
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
private enum ActionType
|
||||
{
|
||||
NoAction = 0,
|
||||
ActionUp,
|
||||
ActionDown,
|
||||
ActionLeft,
|
||||
ActionRight,
|
||||
ActionFire,
|
||||
MaxAction
|
||||
}
|
||||
|
||||
// Key and button inputs
|
||||
private struct ActionInput
|
||||
{
|
||||
public KeyboardKey Key;
|
||||
public GamepadButton Button;
|
||||
}
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Input Actions";
|
||||
|
||||
public string Title => "raylib [core] example - input actions";
|
||||
|
||||
private int gamepadIndex; // Gamepad default index
|
||||
private ActionInput[] actionInputs;
|
||||
|
||||
private int actionSet;
|
||||
private bool releaseAction;
|
||||
private Vector2 position;
|
||||
private Vector2 size;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
gamepadIndex = 0;
|
||||
actionInputs = new ActionInput[(int)ActionType.MaxAction];
|
||||
|
||||
// Set default actions
|
||||
actionSet = 0;
|
||||
SetActionsDefault();
|
||||
releaseAction = false;
|
||||
|
||||
position = new Vector2(400.0f, 200.0f);
|
||||
size = new Vector2(40.0f, 40.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
gamepadIndex = 0; // Set gamepad being checked
|
||||
|
||||
if (IsActionDown(ActionType.ActionUp)) position.Y -= 2;
|
||||
if (IsActionDown(ActionType.ActionDown)) position.Y += 2;
|
||||
if (IsActionDown(ActionType.ActionLeft)) position.X -= 2;
|
||||
if (IsActionDown(ActionType.ActionRight)) position.X += 2;
|
||||
if (IsActionPressed(ActionType.ActionFire))
|
||||
{
|
||||
position.X = (screenWidth - size.X) / 2;
|
||||
position.Y = (screenHeight - size.Y) / 2;
|
||||
}
|
||||
|
||||
// Register release action for one frame
|
||||
releaseAction = false;
|
||||
if (IsActionReleased(ActionType.ActionFire)) releaseAction = true;
|
||||
|
||||
// Switch control scheme by pressing TAB
|
||||
if (IsKeyPressed(KeyboardKey.Tab))
|
||||
{
|
||||
actionSet = (actionSet == 0) ? 1 : 0;
|
||||
if (actionSet == 0) SetActionsDefault();
|
||||
else SetActionsCursor();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Gray);
|
||||
|
||||
DrawRectangleV(position, size, releaseAction ? Color.Blue : Color.Red);
|
||||
|
||||
DrawText((actionSet == 0) ? "Current input set: WASD (default)" : "Current input set: Arrow keys", 10, 10, 20, Color.White);
|
||||
DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, Color.Green);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Check action key/button pressed
|
||||
// NOTE: Combines key pressed and gamepad button pressed in one action
|
||||
private bool IsActionPressed(ActionType action)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (action < ActionType.MaxAction) result = (IsKeyPressed(actionInputs[(int)action].Key) || IsGamepadButtonPressed(gamepadIndex, actionInputs[(int)action].Button));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check action key/button released
|
||||
// NOTE: Combines key released and gamepad button released in one action
|
||||
private bool IsActionReleased(ActionType action)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (action < ActionType.MaxAction) result = (IsKeyReleased(actionInputs[(int)action].Key) || IsGamepadButtonReleased(gamepadIndex, actionInputs[(int)action].Button));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check action key/button down
|
||||
// NOTE: Combines key down and gamepad button down in one action
|
||||
private bool IsActionDown(ActionType action)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (action < ActionType.MaxAction) result = (IsKeyDown(actionInputs[(int)action].Key) || IsGamepadButtonDown(gamepadIndex, actionInputs[(int)action].Button));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set the "default" keyset
|
||||
// NOTE: Here WASD and gamepad buttons on the left side for movement
|
||||
private void SetActionsDefault()
|
||||
{
|
||||
actionInputs[(int)ActionType.ActionUp].Key = KeyboardKey.W;
|
||||
actionInputs[(int)ActionType.ActionDown].Key = KeyboardKey.S;
|
||||
actionInputs[(int)ActionType.ActionLeft].Key = KeyboardKey.A;
|
||||
actionInputs[(int)ActionType.ActionRight].Key = KeyboardKey.D;
|
||||
actionInputs[(int)ActionType.ActionFire].Key = KeyboardKey.Space;
|
||||
|
||||
actionInputs[(int)ActionType.ActionUp].Button = GamepadButton.LeftFaceUp;
|
||||
actionInputs[(int)ActionType.ActionDown].Button = GamepadButton.LeftFaceDown;
|
||||
actionInputs[(int)ActionType.ActionLeft].Button = GamepadButton.LeftFaceLeft;
|
||||
actionInputs[(int)ActionType.ActionRight].Button = GamepadButton.LeftFaceRight;
|
||||
actionInputs[(int)ActionType.ActionFire].Button = GamepadButton.RightFaceDown;
|
||||
}
|
||||
|
||||
// Set the "alternate" keyset
|
||||
// NOTE: Here cursor keys and gamepad buttons on the right side for movement
|
||||
private void SetActionsCursor()
|
||||
{
|
||||
actionInputs[(int)ActionType.ActionUp].Key = KeyboardKey.Up;
|
||||
actionInputs[(int)ActionType.ActionDown].Key = KeyboardKey.Down;
|
||||
actionInputs[(int)ActionType.ActionLeft].Key = KeyboardKey.Left;
|
||||
actionInputs[(int)ActionType.ActionRight].Key = KeyboardKey.Right;
|
||||
actionInputs[(int)ActionType.ActionFire].Key = KeyboardKey.Space;
|
||||
|
||||
actionInputs[(int)ActionType.ActionUp].Button = GamepadButton.RightFaceUp;
|
||||
actionInputs[(int)ActionType.ActionDown].Button = GamepadButton.RightFaceDown;
|
||||
actionInputs[(int)ActionType.ActionLeft].Button = GamepadButton.RightFaceLeft;
|
||||
actionInputs[(int)ActionType.ActionRight].Button = GamepadButton.RightFaceRight;
|
||||
actionInputs[(int)ActionType.ActionFire].Button = GamepadButton.LeftFaceDown;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input actions");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputActions();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,34 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
*
|
||||
* 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 static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputGamepad
|
||||
public partial class InputGamepad : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// NOTE: Gamepad name ID depends on drivers and OS
|
||||
// These are some possible names the gamepads could have.
|
||||
public const string XBOX_ALIAS_1 = "xbox";
|
||||
|
|
@ -34,320 +36,503 @@ public class InputGamepad
|
|||
public const string PS_ALIAS_1 = "playstation";
|
||||
public const string PS_ALIAS_2 = "sony";
|
||||
|
||||
// Set axis deadzones
|
||||
private const float leftStickDeadzoneX = 0.1f;
|
||||
private const float leftStickDeadzoneY = 0.1f;
|
||||
private const float rightStickDeadzoneX = 0.1f;
|
||||
private const float rightStickDeadzoneY = 0.1f;
|
||||
private const float leftTriggerDeadzone = -0.9f;
|
||||
private const float rightTriggerDeadzone = -0.9f;
|
||||
|
||||
private Texture2D texPs3Pad;
|
||||
private Texture2D texXboxPad;
|
||||
|
||||
private Rectangle vibrateButton;
|
||||
|
||||
private int gamepad; // which gamepad to display
|
||||
|
||||
public string Name => "Core / Input Gamepad";
|
||||
|
||||
public string Title => "raylib [core] example - input gamepad";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
texPs3Pad = LoadTexture("resources/ps3.png");
|
||||
texXboxPad = LoadTexture("resources/xbox.png");
|
||||
|
||||
vibrateButton = new Rectangle();
|
||||
|
||||
gamepad = 0; // which gamepad to display
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Left) && gamepad > 0)
|
||||
{
|
||||
gamepad--;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
gamepad++;
|
||||
}
|
||||
|
||||
var 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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (IsGamepadAvailable(gamepad))
|
||||
{
|
||||
var gamepadName = GetGamepadName_(gamepad);
|
||||
DrawText($"GP{gamepad}: {gamepadName}", 10, 10, 10, Color.Black);
|
||||
|
||||
// Get axis values
|
||||
var leftStickX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX);
|
||||
var leftStickY = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY);
|
||||
var rightStickX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightX);
|
||||
var rightStickY = GetGamepadAxisMovement(gamepad, GamepadAxis.RightY);
|
||||
var leftTrigger = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger);
|
||||
var rightTrigger = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger);
|
||||
|
||||
// Calculate deadzones
|
||||
if (leftStickX > -leftStickDeadzoneX && leftStickX < leftStickDeadzoneX)
|
||||
{
|
||||
leftStickX = 0.0f;
|
||||
}
|
||||
|
||||
if (leftStickY > -leftStickDeadzoneY && leftStickY < leftStickDeadzoneY)
|
||||
{
|
||||
leftStickY = 0.0f;
|
||||
}
|
||||
|
||||
if (rightStickX > -rightStickDeadzoneX && rightStickX < rightStickDeadzoneX)
|
||||
{
|
||||
rightStickX = 0.0f;
|
||||
}
|
||||
|
||||
if (rightStickY > -rightStickDeadzoneY && rightStickY < rightStickDeadzoneY)
|
||||
{
|
||||
rightStickY = 0.0f;
|
||||
}
|
||||
|
||||
if (leftTrigger < leftTriggerDeadzone)
|
||||
{
|
||||
leftTrigger = -1.0f;
|
||||
}
|
||||
|
||||
if (rightTrigger < rightTriggerDeadzone)
|
||||
{
|
||||
rightTrigger = -1.0f;
|
||||
}
|
||||
|
||||
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(gamepad, GamepadButton.Middle))
|
||||
{
|
||||
DrawCircle(394, 89, 19, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: basic
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
|
||||
{
|
||||
DrawCircle(436, 150, 9, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
|
||||
{
|
||||
DrawCircle(352, 150, 9, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
|
||||
{
|
||||
DrawCircle(501, 151, 15, Color.Blue);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
|
||||
{
|
||||
DrawCircle(536, 187, 15, Color.Lime);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
|
||||
{
|
||||
DrawCircle(572, 151, 15, Color.Maroon);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
|
||||
{
|
||||
DrawCircle(536, 115, 15, Color.Gold);
|
||||
}
|
||||
|
||||
// Draw buttons: d-pad
|
||||
DrawRectangle(317, 202, 19, 71, Color.Black);
|
||||
DrawRectangle(293, 228, 69, 19, Color.Black);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
|
||||
{
|
||||
DrawRectangle(317, 202, 19, 26, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
|
||||
{
|
||||
DrawRectangle(317, 202 + 45, 19, 26, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
|
||||
{
|
||||
DrawRectangle(292, 228, 25, 19, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
|
||||
{
|
||||
DrawRectangle(292 + 44, 228, 26, 19, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: left-right back
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
|
||||
{
|
||||
DrawCircle(259, 61, 20, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
|
||||
{
|
||||
DrawCircle(536, 61, 20, Color.Red);
|
||||
}
|
||||
|
||||
// Draw axis: left joystick
|
||||
var leftGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
|
||||
{
|
||||
leftGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(259, 152, 39, Color.Black);
|
||||
DrawCircle(259, 152, 34, Color.LightGray);
|
||||
DrawCircle(259 + (int)(leftStickX * 20), 152 + (int)(leftStickY * 20), 25, leftGamepadColor);
|
||||
|
||||
// Draw axis: right joystick
|
||||
var rightGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
|
||||
{
|
||||
rightGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(461, 237, 38, Color.Black);
|
||||
DrawCircle(461, 237, 33, Color.LightGray);
|
||||
DrawCircle(461 + (int)(rightStickX * 20), 237 + (int)(rightStickY * 20), 25, rightGamepadColor);
|
||||
|
||||
// Draw axis: left-right triggers
|
||||
DrawRectangle(170, 30, 15, 70, Color.Gray);
|
||||
DrawRectangle(604, 30, 15, 70, Color.Gray);
|
||||
DrawRectangle(170, 30, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
|
||||
DrawRectangle(604, 30, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
|
||||
}
|
||||
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(gamepad, GamepadButton.Middle))
|
||||
{
|
||||
DrawCircle(396, 222, 13, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: basic
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
|
||||
{
|
||||
DrawRectangle(328, 170, 32, 13, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
|
||||
{
|
||||
DrawTriangle(
|
||||
new Vector2(436, 168),
|
||||
new Vector2(436, 185),
|
||||
new Vector2(464, 177),
|
||||
Color.Red
|
||||
);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
|
||||
{
|
||||
DrawCircle(557, 144, 13, Color.Lime);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
|
||||
{
|
||||
DrawCircle(586, 173, 13, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
|
||||
{
|
||||
DrawCircle(557, 203, 13, Color.Violet);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
|
||||
{
|
||||
DrawCircle(527, 173, 13, Color.Pink);
|
||||
}
|
||||
|
||||
// Draw buttons: d-pad
|
||||
DrawRectangle(225, 132, 24, 84, Color.Black);
|
||||
DrawRectangle(195, 161, 84, 25, Color.Black);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
|
||||
{
|
||||
DrawRectangle(225, 132, 24, 29, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
|
||||
{
|
||||
DrawRectangle(225, 132 + 54, 24, 30, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
|
||||
{
|
||||
DrawRectangle(195, 161, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
|
||||
{
|
||||
DrawRectangle(195 + 54, 161, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: left-right back buttons
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
|
||||
{
|
||||
DrawCircle(239, 82, 20, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
|
||||
{
|
||||
DrawCircle(557, 82, 20, Color.Red);
|
||||
}
|
||||
|
||||
// Draw axis: left joystick
|
||||
var leftGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
|
||||
{
|
||||
leftGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(319, 255, 35, Color.Black);
|
||||
DrawCircle(319, 255, 31, Color.LightGray);
|
||||
DrawCircle(319 + (int)(leftStickX * 20), 255 + (int)(leftStickY * 20), 25, leftGamepadColor);
|
||||
|
||||
// Draw axis: right joystick
|
||||
var rightGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
|
||||
{
|
||||
rightGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(475, 255, 35, Color.Black);
|
||||
DrawCircle(475, 255, 31, Color.LightGray);
|
||||
DrawCircle(475 + (int)(rightStickX * 20), 255 + (int)(rightStickY * 20), 25, rightGamepadColor);
|
||||
|
||||
// Draw axis: left-right triggers
|
||||
DrawRectangle(169, 48, 15, 70, Color.Gray);
|
||||
DrawRectangle(611, 48, 15, 70, Color.Gray);
|
||||
DrawRectangle(169, 48, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
|
||||
DrawRectangle(611, 48, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw background: generic
|
||||
DrawRectangleRounded(new Rectangle(175, 110, 460, 220), 0.3f, 16, Color.DarkGray);
|
||||
|
||||
// Draw buttons: basic
|
||||
DrawCircle(365, 170, 12, Color.RayWhite);
|
||||
DrawCircle(405, 170, 12, Color.RayWhite);
|
||||
DrawCircle(445, 170, 12, Color.RayWhite);
|
||||
DrawCircle(516, 191, 17, Color.RayWhite);
|
||||
DrawCircle(551, 227, 17, Color.RayWhite);
|
||||
DrawCircle(587, 191, 17, Color.RayWhite);
|
||||
DrawCircle(551, 155, 17, Color.RayWhite);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
|
||||
{
|
||||
DrawCircle(365, 170, 10, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
|
||||
{
|
||||
DrawCircle(405, 170, 10, Color.Green);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
|
||||
{
|
||||
DrawCircle(445, 170, 10, Color.Blue);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
|
||||
{
|
||||
DrawCircle(516, 191, 15, Color.Gold);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
|
||||
{
|
||||
DrawCircle(551, 227, 15, Color.Blue);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
|
||||
{
|
||||
DrawCircle(587, 191, 15, Color.Green);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
|
||||
{
|
||||
DrawCircle(551, 155, 15, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: d-pad
|
||||
DrawRectangle(245, 145, 28, 88, Color.RayWhite);
|
||||
DrawRectangle(215, 174, 88, 29, Color.RayWhite);
|
||||
DrawRectangle(247, 147, 24, 84, Color.Black);
|
||||
DrawRectangle(217, 176, 84, 25, Color.Black);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
|
||||
{
|
||||
DrawRectangle(247, 147, 24, 29, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
|
||||
{
|
||||
DrawRectangle(247, 147 + 54, 24, 30, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
|
||||
{
|
||||
DrawRectangle(217, 176, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
|
||||
{
|
||||
DrawRectangle(217 + 54, 176, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: left-right back
|
||||
DrawRectangleRounded(new Rectangle(215, 98, 100, 10), 0.5f, 16, Color.DarkGray);
|
||||
DrawRectangleRounded(new Rectangle(495, 98, 100, 10), 0.5f, 16, Color.DarkGray);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
|
||||
{
|
||||
DrawRectangleRounded(new Rectangle(215, 98, 100, 10), 0.5f, 16, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
|
||||
{
|
||||
DrawRectangleRounded(new Rectangle(495, 98, 100, 10), 0.5f, 16, Color.Red);
|
||||
}
|
||||
|
||||
// Draw axis: left joystick
|
||||
var leftGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
|
||||
{
|
||||
leftGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(345, 260, 40, Color.Black);
|
||||
DrawCircle(345, 260, 35, Color.LightGray);
|
||||
DrawCircle(345 + (int)(leftStickX * 20), 260 + (int)(leftStickY * 20), 25, leftGamepadColor);
|
||||
|
||||
// Draw axis: right joystick
|
||||
var rightGamepadColor = Color.Black;
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
|
||||
{
|
||||
rightGamepadColor = Color.Red;
|
||||
}
|
||||
|
||||
DrawCircle(465, 260, 40, Color.Black);
|
||||
DrawCircle(465, 260, 35, Color.LightGray);
|
||||
DrawCircle(465 + (int)(rightStickX * 20), 260 + (int)(rightStickY * 20), 25, rightGamepadColor);
|
||||
|
||||
// Draw axis: left-right triggers
|
||||
DrawRectangle(151, 110, 15, 70, Color.Gray);
|
||||
DrawRectangle(644, 110, 15, 70, Color.Gray);
|
||||
DrawRectangle(151, 110, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
|
||||
DrawRectangle(644, 110, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
|
||||
}
|
||||
|
||||
DrawText($"DETECTED AXIS [{GetGamepadAxisCount(gamepad)}]:", 10, 50, 10, Color.Maroon);
|
||||
|
||||
for (var i = 0; i < GetGamepadAxisCount(gamepad); i++)
|
||||
{
|
||||
DrawText(
|
||||
$"AXIS {i}: {GetGamepadAxisMovement(gamepad, (GamepadAxis)i):F2}",
|
||||
20,
|
||||
70 + 20 * i,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
}
|
||||
|
||||
// Draw vibrate button
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("DETECTED BUTTON: NONE", 10, 430, 10, Color.Gray);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($"GP{gamepad}: NOT DETECTED", 10, 10, 10, Color.Gray);
|
||||
DrawTexture(texXboxPad, 0, 0, Color.LightGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texPs3Pad);
|
||||
UnloadTexture(texXboxPad);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Set MSAA 4X hint before windows creation
|
||||
|
||||
// Set MSAA 4X hint before windows creation
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - gamepad input");
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gamepad");
|
||||
|
||||
Texture2D texPs3Pad = LoadTexture("resources/ps3.png");
|
||||
Texture2D texXboxPad = LoadTexture("resources/xbox.png");
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
int gamepad = 0;
|
||||
Rectangle vibrateButton = new Rectangle();
|
||||
var game = new InputGamepad();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// 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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (IsGamepadAvailable(gamepad))
|
||||
{
|
||||
string gamepadName = GetGamepadName_(gamepad);
|
||||
DrawText($"GP{gamepad}: {gamepadName}", 10, 10, 10, Color.Black);
|
||||
|
||||
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(gamepad, GamepadButton.Middle))
|
||||
{
|
||||
DrawCircle(394, 89, 19, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: basic
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
|
||||
{
|
||||
DrawCircle(436, 150, 9, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
|
||||
{
|
||||
DrawCircle(352, 150, 9, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
|
||||
{
|
||||
DrawCircle(501, 151, 15, Color.Blue);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
|
||||
{
|
||||
DrawCircle(536, 187, 15, Color.Lime);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
|
||||
{
|
||||
DrawCircle(572, 151, 15, Color.Maroon);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
|
||||
{
|
||||
DrawCircle(536, 115, 15, Color.Gold);
|
||||
}
|
||||
|
||||
// Draw buttons: d-pad
|
||||
DrawRectangle(317, 202, 19, 71, Color.Black);
|
||||
DrawRectangle(293, 228, 69, 19, Color.Black);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
|
||||
{
|
||||
DrawRectangle(317, 202, 19, 26, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
|
||||
{
|
||||
DrawRectangle(317, 202 + 45, 19, 26, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
|
||||
{
|
||||
DrawRectangle(292, 228, 25, 19, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
|
||||
{
|
||||
DrawRectangle(292 + 44, 228, 26, 19, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: left-right back
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
|
||||
{
|
||||
DrawCircle(259, 61, 20, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
|
||||
{
|
||||
DrawCircle(536, 61, 20, Color.Red);
|
||||
}
|
||||
|
||||
// Draw axis: left joystick
|
||||
DrawCircle(259, 152, 39, Color.Black);
|
||||
DrawCircle(259, 152, 34, Color.LightGray);
|
||||
DrawCircle(
|
||||
259 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20),
|
||||
152 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20),
|
||||
25,
|
||||
Color.Black
|
||||
);
|
||||
|
||||
// Draw axis: right joystick
|
||||
DrawCircle(461, 237, 38, Color.Black);
|
||||
DrawCircle(461, 237, 33, Color.LightGray);
|
||||
DrawCircle(
|
||||
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(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.Contains(PS_ALIAS_1, StringComparison.OrdinalIgnoreCase) || gamepadName.Contains(PS_ALIAS_2, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
DrawTexture(texPs3Pad, 0, 0, Color.DarkGray);
|
||||
|
||||
// Draw buttons: ps
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
|
||||
{
|
||||
DrawCircle(396, 222, 13, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: basic
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
|
||||
{
|
||||
DrawRectangle(328, 170, 32, 13, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
|
||||
{
|
||||
DrawTriangle(
|
||||
new Vector2(436, 168),
|
||||
new Vector2(436, 185),
|
||||
new Vector2(464, 177),
|
||||
Color.Red
|
||||
);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
|
||||
{
|
||||
DrawCircle(557, 144, 13, Color.Lime);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
|
||||
{
|
||||
DrawCircle(586, 173, 13, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
|
||||
{
|
||||
DrawCircle(557, 203, 13, Color.Violet);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
|
||||
{
|
||||
DrawCircle(527, 173, 13, Color.Pink);
|
||||
}
|
||||
|
||||
// Draw buttons: d-pad
|
||||
DrawRectangle(225, 132, 24, 84, Color.Black);
|
||||
DrawRectangle(195, 161, 84, 25, Color.Black);
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
|
||||
{
|
||||
DrawRectangle(225, 132, 24, 29, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
|
||||
{
|
||||
DrawRectangle(225, 132 + 54, 24, 30, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
|
||||
{
|
||||
DrawRectangle(195, 161, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
|
||||
{
|
||||
DrawRectangle(195 + 54, 161, 30, 25, Color.Red);
|
||||
}
|
||||
|
||||
// Draw buttons: left-right back buttons
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
|
||||
{
|
||||
DrawCircle(239, 82, 20, Color.Red);
|
||||
}
|
||||
|
||||
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
|
||||
{
|
||||
DrawCircle(557, 82, 20, Color.Red);
|
||||
}
|
||||
|
||||
// Draw axis: left joystick
|
||||
DrawCircle(319, 255, 35, Color.Black);
|
||||
DrawCircle(319, 255, 31, Color.LightGray);
|
||||
DrawCircle(
|
||||
319 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20),
|
||||
255 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20),
|
||||
25,
|
||||
Color.Black
|
||||
);
|
||||
|
||||
// Draw axis: right joystick
|
||||
DrawCircle(475, 255, 35, Color.Black);
|
||||
DrawCircle(475, 255, 31, Color.LightGray);
|
||||
DrawCircle(
|
||||
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(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);
|
||||
DrawRectangle(611, 48, 15, (int)(((1.0f - rightTriggerX) / 2.0f) * 70), Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("- GENERIC GAMEPAD -", 280, 180, 20, Color.Gray);
|
||||
// TODO: Draw generic gamepad
|
||||
}
|
||||
|
||||
DrawText($"DETECTED AXIS [{GetGamepadAxisCount(gamepad)}]:", 10, 50, 10, Color.Maroon);
|
||||
|
||||
for (int i = 0; i < GetGamepadAxisCount(gamepad); i++)
|
||||
{
|
||||
DrawText(
|
||||
$"AXIS {i}: {GetGamepadAxisMovement(gamepad, (GamepadAxis)i)}",
|
||||
20,
|
||||
70 + 20 * i,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("DETECTED BUTTON: NONE", 10, 430, 10, Color.Gray);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($"GP{gamepad}: NOT DETECTED", 10, 10, 10, Color.Gray);
|
||||
DrawTexture(texXboxPad, 0, 0, Color.LightGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texPs3Pad);
|
||||
UnloadTexture(texXboxPad);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -18,145 +18,176 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputGestures
|
||||
public partial class InputGestures : IExample
|
||||
{
|
||||
public const int MaxGestureStrings = 20;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private Vector2 touchPosition;
|
||||
private Rectangle touchArea;
|
||||
|
||||
private int gesturesCount;
|
||||
private string[] gestureStrings;
|
||||
|
||||
private Gesture currentGesture;
|
||||
private Gesture lastGesture;
|
||||
|
||||
public string Name => "Core / Input Gestures";
|
||||
|
||||
public string Title => "raylib [core] example - input gestures";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
touchPosition = new(0, 0);
|
||||
touchArea = new(220, 10, screenWidth - 230, screenHeight - 20);
|
||||
|
||||
gesturesCount = 0;
|
||||
gestureStrings = new string[MaxGestureStrings];
|
||||
|
||||
currentGesture = Gesture.None;
|
||||
lastGesture = Gesture.None;
|
||||
|
||||
// SetGesturesEnabled(0b0000000000001001); // Enable only some gestures to be detected
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
lastGesture = currentGesture;
|
||||
currentGesture = GetGestureDetected();
|
||||
touchPosition = GetTouchPosition(0);
|
||||
|
||||
if (CheckCollisionPointRec(touchPosition, touchArea) && (currentGesture != Gesture.None))
|
||||
{
|
||||
if (currentGesture != lastGesture)
|
||||
{
|
||||
// Store gesture string
|
||||
switch ((Gesture)currentGesture)
|
||||
{
|
||||
case Gesture.Tap:
|
||||
gestureStrings[gesturesCount] = "GESTURE TAP";
|
||||
break;
|
||||
case Gesture.DoubleTap:
|
||||
gestureStrings[gesturesCount] = "GESTURE DOUBLETAP";
|
||||
break;
|
||||
case Gesture.Hold:
|
||||
gestureStrings[gesturesCount] = "GESTURE HOLD";
|
||||
break;
|
||||
case Gesture.Drag:
|
||||
gestureStrings[gesturesCount] = "GESTURE DRAG";
|
||||
break;
|
||||
case Gesture.SwipeRight:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE RIGHT";
|
||||
break;
|
||||
case Gesture.SwipeLeft:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE LEFT";
|
||||
break;
|
||||
case Gesture.SwipeUp:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE UP";
|
||||
break;
|
||||
case Gesture.SwipeDown:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE DOWN";
|
||||
break;
|
||||
case Gesture.PinchIn:
|
||||
gestureStrings[gesturesCount] = "GESTURE PINCH IN";
|
||||
break;
|
||||
case Gesture.PinchOut:
|
||||
gestureStrings[gesturesCount] = "GESTURE PINCH OUT";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gesturesCount++;
|
||||
|
||||
// Reset gestures strings
|
||||
if (gesturesCount >= MaxGestureStrings)
|
||||
{
|
||||
for (var i = 0; i < MaxGestureStrings; i++)
|
||||
{
|
||||
gestureStrings[i] = " ";
|
||||
}
|
||||
gesturesCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawRectangleRec(touchArea, Color.Gray);
|
||||
DrawRectangle(225, 15, screenWidth - 240, screenHeight - 30, Color.RayWhite);
|
||||
|
||||
DrawText("GESTURES TEST AREA", screenWidth - 270, screenHeight - 40, 20, Fade(Color.Gray, 0.5f));
|
||||
|
||||
for (var i = 0; i < gesturesCount; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
DrawRectangle(10, 30 + 20 * i, 200, 20, Fade(Color.LightGray, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangle(10, 30 + 20 * i, 200, 20, Fade(Color.LightGray, 0.3f));
|
||||
}
|
||||
|
||||
if (i < gesturesCount - 1)
|
||||
{
|
||||
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.Maroon);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleLines(10, 29, 200, screenHeight - 50, Color.Gray);
|
||||
DrawText("DETECTED GESTURES", 50, 15, 10, Color.Gray);
|
||||
|
||||
if (currentGesture != Gesture.None)
|
||||
{
|
||||
DrawCircleV(touchPosition, 30, Color.Maroon);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures");
|
||||
|
||||
Vector2 touchPosition = new(0, 0);
|
||||
Rectangle touchArea = new(220, 10, screenWidth - 230, screenHeight - 20);
|
||||
|
||||
int gesturesCount = 0;
|
||||
string[] gestureStrings = new string[MaxGestureStrings];
|
||||
|
||||
Gesture currentGesture = Gesture.None;
|
||||
Gesture lastGesture = Gesture.None;
|
||||
|
||||
// SetGesturesEnabled(0b0000000000001001); // Enable only some gestures to be detected
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputGestures();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
lastGesture = currentGesture;
|
||||
currentGesture = GetGestureDetected();
|
||||
touchPosition = GetTouchPosition(0);
|
||||
|
||||
if (CheckCollisionPointRec(touchPosition, touchArea) && (currentGesture != Gesture.None))
|
||||
{
|
||||
if (currentGesture != lastGesture)
|
||||
{
|
||||
// Store gesture string
|
||||
switch ((Gesture)currentGesture)
|
||||
{
|
||||
case Gesture.Tap:
|
||||
gestureStrings[gesturesCount] = "GESTURE TAP";
|
||||
break;
|
||||
case Gesture.DoubleTap:
|
||||
gestureStrings[gesturesCount] = "GESTURE DOUBLETAP";
|
||||
break;
|
||||
case Gesture.Hold:
|
||||
gestureStrings[gesturesCount] = "GESTURE HOLD";
|
||||
break;
|
||||
case Gesture.Drag:
|
||||
gestureStrings[gesturesCount] = "GESTURE DRAG";
|
||||
break;
|
||||
case Gesture.SwipeRight:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE RIGHT";
|
||||
break;
|
||||
case Gesture.SwipeLeft:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE LEFT";
|
||||
break;
|
||||
case Gesture.SwipeUp:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE UP";
|
||||
break;
|
||||
case Gesture.SwipeDown:
|
||||
gestureStrings[gesturesCount] = "GESTURE SWIPE DOWN";
|
||||
break;
|
||||
case Gesture.PinchIn:
|
||||
gestureStrings[gesturesCount] = "GESTURE PINCH IN";
|
||||
break;
|
||||
case Gesture.PinchOut:
|
||||
gestureStrings[gesturesCount] = "GESTURE PINCH OUT";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gesturesCount++;
|
||||
|
||||
// Reset gestures strings
|
||||
if (gesturesCount >= MaxGestureStrings)
|
||||
{
|
||||
for (int i = 0; i < MaxGestureStrings; i++)
|
||||
{
|
||||
gestureStrings[i] = " ";
|
||||
}
|
||||
gesturesCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawRectangleRec(touchArea, Color.Gray);
|
||||
DrawRectangle(225, 15, screenWidth - 240, screenHeight - 30, Color.RayWhite);
|
||||
|
||||
DrawText("GESTURES TEST AREA", screenWidth - 270, screenHeight - 40, 20, ColorAlpha(Color.Gray, 0.5f));
|
||||
|
||||
for (int i = 0; i < gesturesCount; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
DrawRectangle(10, 30 + 20 * i, 200, 20, ColorAlpha(Color.LightGray, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangle(10, 30 + 20 * i, 200, 20, ColorAlpha(Color.LightGray, 0.3f));
|
||||
}
|
||||
|
||||
if (i < gesturesCount - 1)
|
||||
{
|
||||
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.Maroon);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleLines(10, 29, 200, screenHeight - 50, Color.Gray);
|
||||
DrawText("DETECTED GESTURES", 50, 15, 10, Color.Gray);
|
||||
|
||||
if (currentGesture != Gesture.None)
|
||||
{
|
||||
DrawCircleV(touchPosition, 30, Color.Maroon);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,406 +1,454 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
*
|
||||
* 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;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
public class InputGesturesTestBed
|
||||
public partial class InputGesturesTestBed : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public const int GESTURE_LOG_SIZE = 20;
|
||||
public const int MAX_TOUCH_COUNT = 32;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
public string Name => "Core / Input Gestures Test Bed";
|
||||
|
||||
public static int Main()
|
||||
public string Title => "raylib [core] example - input gestures testbed";
|
||||
|
||||
private Vector2 messagePosition;
|
||||
|
||||
// Last gesture variables definitions
|
||||
private Gesture lastGesture;
|
||||
private Vector2 lastGesturePosition;
|
||||
|
||||
// Gesture log variables definitions
|
||||
// NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures
|
||||
private string[] gestureLog;
|
||||
|
||||
// NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around)
|
||||
private int gestureLogIndex;
|
||||
private Gesture previousGesture;
|
||||
|
||||
// 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
|
||||
private int logMode;
|
||||
|
||||
private Color gestureColor;
|
||||
private Rectangle logButton1;
|
||||
private Rectangle logButton2;
|
||||
private Vector2 gestureLogPosition;
|
||||
|
||||
// Protractor variables definitions
|
||||
private float angleLength;
|
||||
private float currentAngleDegrees;
|
||||
private Vector2 finalVector;
|
||||
private Vector2 protractorPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed");
|
||||
|
||||
Vector2 messagePosition = new Vector2(160, 7);
|
||||
messagePosition = new Vector2(160, 7);
|
||||
|
||||
// Last gesture variables definitions
|
||||
Gesture lastGesture = 0;
|
||||
Vector2 lastGesturePosition = new Vector2(165, 130);
|
||||
lastGesture = 0;
|
||||
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 = new string[GESTURE_LOG_SIZE + 1];
|
||||
for (var 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;
|
||||
gestureLogIndex = GESTURE_LOG_SIZE;
|
||||
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;
|
||||
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);
|
||||
gestureColor = new Color(0, 0, 0, 255);
|
||||
logButton1 = new Rectangle(53, 7, 48, 26);
|
||||
logButton2 = new Rectangle(108, 7, 36, 26);
|
||||
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);
|
||||
angleLength = 90.0f;
|
||||
currentAngleDegrees = 0.0f;
|
||||
finalVector = new Vector2(0.0f, 0.0f);
|
||||
protractorPosition = new Vector2(266.0f, 315.0f);
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Handle common gestures data
|
||||
int i, ii; // Iterators that will be reused by all for loops
|
||||
var currentGesture = GetGestureDetected();
|
||||
var currentDragDegrees = GetGestureDragAngle();
|
||||
var currentPitchDegrees = GetGesturePinchAngle();
|
||||
var touchCount = GetTouchPointCount();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
// Handle last gesture
|
||||
if ((currentGesture != 0) && ((int)currentGesture != 4) && (currentGesture != previousGesture))
|
||||
{
|
||||
// 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();
|
||||
lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display
|
||||
}
|
||||
|
||||
// Handle last gesture
|
||||
if ((currentGesture != 0) && ((int)currentGesture != 4) && (currentGesture != previousGesture))
|
||||
// Handle gesture log
|
||||
if (IsMouseButtonReleased(MouseButton.Left))
|
||||
{
|
||||
if (CheckCollisionPointRec(GetMousePosition(), logButton1))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
case 3:
|
||||
logMode = 2;
|
||||
break;
|
||||
case 2:
|
||||
logMode = 3;
|
||||
break;
|
||||
case 1:
|
||||
logMode = 0;
|
||||
break;
|
||||
default:
|
||||
logMode = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled
|
||||
if (currentGesture != 0)
|
||||
else if (CheckCollisionPointRec(GetMousePosition(), logButton2))
|
||||
{
|
||||
if (logMode == 3) // 3 hides repeated events and hide hold events
|
||||
switch (logMode)
|
||||
{
|
||||
if ((((int)currentGesture != 4) && (currentGesture != previousGesture)) || ((int)currentGesture < 3))
|
||||
{
|
||||
fillLog = 1;
|
||||
}
|
||||
case 3:
|
||||
logMode = 1;
|
||||
break;
|
||||
case 2:
|
||||
logMode = 0;
|
||||
break;
|
||||
case 1:
|
||||
logMode = 3;
|
||||
break;
|
||||
default:
|
||||
logMode = 2;
|
||||
break;
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
var 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (fillLog > 0) // If one of the conditions from logMode was met, fill the gesture log
|
||||
else if (logMode == 2) // 2 shows repeated events but hide hold events
|
||||
{
|
||||
previousGesture = currentGesture;
|
||||
gestureColor = GetGestureColor((int)currentGesture);
|
||||
if (gestureLogIndex <= 0)
|
||||
if ((int)currentGesture != 4)
|
||||
{
|
||||
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();
|
||||
fillLog = 1;
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// 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++)
|
||||
else if (logMode == 1) // 1 hides repeated events
|
||||
{
|
||||
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)
|
||||
if (currentGesture != previousGesture)
|
||||
{
|
||||
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);
|
||||
fillLog = 1;
|
||||
}
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//--------------------------------------------------------------------------------------
|
||||
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
|
||||
}
|
||||
|
||||
var 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
|
||||
var touchPosition = new Vector2[MAX_TOUCH_COUNT];
|
||||
|
||||
var 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.
|
||||
var angleString = currentAngleDegrees.ToString("F3");
|
||||
var angleStringDot = angleString.IndexOf('.');
|
||||
var angleStringTrim = angleString[..(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();
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputGesturesTestBed();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
|
|
@ -409,7 +457,8 @@ public class InputGesturesTestBed
|
|||
return 0;
|
||||
}
|
||||
|
||||
static string GetGestureName(int gesture)
|
||||
// Get text string for gesture value
|
||||
private static string GetGestureName(int gesture)
|
||||
{
|
||||
switch (gesture)
|
||||
{
|
||||
|
|
@ -441,7 +490,7 @@ public class InputGesturesTestBed
|
|||
}
|
||||
|
||||
// Get color for gesture value
|
||||
static Color GetGestureColor(int gesture)
|
||||
private static Color GetGestureColor(int gesture)
|
||||
{
|
||||
switch (gesture)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,64 +18,87 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputKeys
|
||||
public partial class InputKeys : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Input Keys";
|
||||
|
||||
public string Title => "raylib [core] example - input keys";
|
||||
|
||||
private Vector2 ballPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
ballPosition = new((float)screenWidth / 2, (float)screenHeight / 2);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
ballPosition.X += 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
ballPosition.X -= 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
ballPosition.Y -= 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
ballPosition.Y += 2.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("move the ball with arrow keys", 10, 10, 20, Color.DarkGray);
|
||||
|
||||
DrawCircleV(ballPosition, 50, Color.Maroon);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input keys");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input");
|
||||
|
||||
Vector2 ballPosition = new((float)screenWidth / 2, (float)screenHeight / 2);
|
||||
|
||||
SetTargetFPS(60); // Set target frames-per-second
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputKeys();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
ballPosition.X += 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
ballPosition.X -= 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
ballPosition.Y -= 2.0f;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
ballPosition.Y += 2.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("move the ball with arrow keys", 10, 10, 20, Color.DarkGray);
|
||||
|
||||
DrawCircleV(ballPosition, 50, Color.Maroon);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -19,95 +19,122 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputMouse
|
||||
public partial class InputMouse : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Input Mouse";
|
||||
|
||||
public string Title => "raylib [core] example - input mouse";
|
||||
|
||||
private Vector2 ballPosition;
|
||||
private Color ballColor;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
ballPosition = new(-100.0f, -100.0f);
|
||||
ballColor = Color.DarkBlue;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.H))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
ShowCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
ballPosition = GetMousePosition();
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
ballColor = Color.Maroon;
|
||||
}
|
||||
else if (IsMouseButtonPressed(MouseButton.Middle))
|
||||
{
|
||||
ballColor = Color.Lime;
|
||||
}
|
||||
else if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
ballColor = Color.DarkBlue;
|
||||
}
|
||||
else if (IsMouseButtonPressed(MouseButton.Side))
|
||||
{
|
||||
ballColor = Color.Purple;
|
||||
}
|
||||
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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
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();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse input");
|
||||
|
||||
Vector2 ballPosition = new(-100.0f, -100.0f);
|
||||
Color ballColor = Color.DarkBlue;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputMouse();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.H))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
ShowCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
ballPosition = GetMousePosition();
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
ballColor = Color.Maroon;
|
||||
}
|
||||
else if (IsMouseButtonPressed(MouseButton.Middle))
|
||||
{
|
||||
ballColor = Color.Lime;
|
||||
}
|
||||
else if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
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
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
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();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -17,48 +17,72 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputMouseWheel
|
||||
public partial class InputMouseWheel : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Mouse Wheel";
|
||||
|
||||
public string Title => "raylib [core] example - input mouse wheel";
|
||||
|
||||
private int boxPositionY;
|
||||
private int scrollSpeed; // Scrolling speed in pixels
|
||||
|
||||
public void Init()
|
||||
{
|
||||
boxPositionY = screenHeight / 2 - 40;
|
||||
scrollSpeed = 4; // Scrolling speed in pixels
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
boxPositionY -= (int)(GetMouseWheelMove() * scrollSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawRectangle(screenWidth / 2 - 40, boxPositionY, 80, 80, Color.Maroon);
|
||||
|
||||
DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, Color.Gray);
|
||||
DrawText($"Box position Y: {boxPositionY:000}", 10, 40, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse wheel");
|
||||
|
||||
int boxPositionY = screenHeight / 2 - 40;
|
||||
int scrollSpeed = 4; // Scrolling speed in pixels
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputMouseWheel();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
boxPositionY -= (int)(GetMouseWheelMove() * scrollSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawRectangle(screenWidth / 2 - 40, boxPositionY, 80, 80, Color.Maroon);
|
||||
|
||||
DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, Color.Gray);
|
||||
DrawText($"Box position Y: {boxPositionY}", 10, 40, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -20,74 +20,98 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class InputMultitouch
|
||||
public partial class InputMultitouch : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxTouchPoints = 10;
|
||||
|
||||
public string Name => "Core / Input Multitouch";
|
||||
|
||||
public string Title => "raylib [core] example - input multitouch";
|
||||
|
||||
private Vector2[] touchPositions;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
touchPositions = new Vector2[MaxTouchPoints];
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Get the touch point count ( how many fingers are touching the screen )
|
||||
var tCount = GetTouchPointCount();
|
||||
|
||||
// Clamp touch points available ( set the maximum touch points allowed )
|
||||
if (tCount > MaxTouchPoints)
|
||||
{
|
||||
tCount = MaxTouchPoints;
|
||||
}
|
||||
|
||||
// Get touch points positions
|
||||
for (var i = 0; i < tCount; i++)
|
||||
{
|
||||
touchPositions[i] = GetTouchPosition(i);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (var i = 0; i < tCount; i++)
|
||||
{
|
||||
// Make sure point is not (0, 0) as this means there is no touch for it
|
||||
if ((touchPositions[i].X > 0) && (touchPositions[i].Y > 0))
|
||||
{
|
||||
// Draw circle and touch index number
|
||||
DrawCircleV(touchPositions[i], 34, Color.Orange);
|
||||
DrawText(i.ToString(),
|
||||
(int)touchPositions[i].X - 10,
|
||||
(int)touchPositions[i].Y - 70,
|
||||
40,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("touch the screen at multiple locations to get multiple balls", 10, 10, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input multitouch");
|
||||
|
||||
const int MaxTouchPoints = 10;
|
||||
Vector2[] touchPositions = new Vector2[MaxTouchPoints];
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputMultitouch();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Get the touch point count (how many fingers are touching the screen )
|
||||
int tCount = GetTouchPointCount();
|
||||
|
||||
// Clamp touch points available (set the maximum touch points allowed )
|
||||
if (tCount > MaxTouchPoints)
|
||||
{
|
||||
tCount = MaxTouchPoints;
|
||||
}
|
||||
|
||||
// Get touch points positions
|
||||
for (int i = 0; i < tCount; i++)
|
||||
{
|
||||
touchPositions[i] = GetTouchPosition(i);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = 0; i < tCount; i++)
|
||||
{
|
||||
// Make sure point is not (0, 0) as this means there is no touch for it
|
||||
if ((touchPositions[i].X > 0) && (touchPositions[i].Y > 0))
|
||||
{
|
||||
// Draw circle and touch index number
|
||||
DrawCircleV(touchPositions[i], 34, Color.Orange);
|
||||
DrawText(i.ToString(),
|
||||
(int)touchPositions[i].X - 10,
|
||||
(int)touchPositions[i].Y - 70,
|
||||
40,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("touch the screen at multiple locations to get multiple balls", 10, 10, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
*
|
||||
* 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;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
public enum PadButton
|
||||
{
|
||||
BUTTON_NONE = -1,
|
||||
|
|
@ -32,21 +32,31 @@ public enum PadButton
|
|||
BUTTON_MAX
|
||||
}
|
||||
|
||||
public class InputVirtualControls
|
||||
public partial class InputVirtualControls : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Input Virtual Controls";
|
||||
|
||||
public string Title => "raylib [core] example - input virtual controls";
|
||||
|
||||
private Vector2 padPosition;
|
||||
private float buttonRadius;
|
||||
private Vector2[] buttonPositions;
|
||||
private Vector2[][] arrowTris;
|
||||
private Color[] buttonLabelColors;
|
||||
private int pressedButton;
|
||||
private Vector2 inputPosition;
|
||||
private Vector2 playerPosition;
|
||||
private float playerSpeed;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
padPosition = new Vector2(100, 350);
|
||||
buttonRadius = 30;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
|
||||
|
||||
Vector2 padPosition = new Vector2(100, 350);
|
||||
float buttonRadius = 30;
|
||||
|
||||
Vector2[] buttonPositions =
|
||||
buttonPositions =
|
||||
[
|
||||
new Vector2(
|
||||
padPosition.X,padPosition.Y - buttonRadius * 1.5f
|
||||
|
|
@ -62,7 +72,7 @@ public class InputVirtualControls
|
|||
) // Down
|
||||
];
|
||||
|
||||
Vector2[][] arrowTris = [
|
||||
arrowTris = [
|
||||
// Up
|
||||
[
|
||||
new Vector2(
|
||||
|
|
@ -114,107 +124,126 @@ public class InputVirtualControls
|
|||
]
|
||||
;
|
||||
|
||||
Color[] buttonLabelColors = [
|
||||
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);
|
||||
pressedButton = (int)PadButton.BUTTON_NONE;
|
||||
inputPosition = new Vector2(0, 0);
|
||||
|
||||
Vector2 playerPosition = new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
|
||||
float playerSpeed = 75f;
|
||||
playerPosition = new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
|
||||
playerSpeed = 75f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// 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 (var i = 0; i < (int)PadButton.BUTTON_MAX; i++)
|
||||
{
|
||||
var distX = MathF.Abs(buttonPositions[i].X - inputPosition.X);
|
||||
var 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 (var 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();
|
||||
//--------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new InputVirtualControls();
|
||||
game.Init();
|
||||
|
||||
// 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();
|
||||
//--------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
|
|
|
|||
374
Examples/Core/KeyboardTestbed.cs
Normal file
374
Examples/Core/KeyboardTestbed.cs
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - keyboard testbed
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* NOTE: raylib defined keys refer to ENG-US Keyboard layout,
|
||||
* mapping to other layouts is up to the user
|
||||
*
|
||||
* Example originally created with raylib 5.6, last time updated with raylib 5.6
|
||||
*
|
||||
* 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) 2026 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class KeyboardTestbed : IExample
|
||||
{
|
||||
private const int KeyRecSpacing = 4; // Space in pixels between key rectangles
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Keyboard Testbed";
|
||||
|
||||
public string Title => "raylib [core] example - keyboard testbed";
|
||||
|
||||
private int[] line01KeyWidths;
|
||||
private int[] line01Keys;
|
||||
private int[] line02KeyWidths;
|
||||
private int[] line02Keys;
|
||||
private int[] line03KeyWidths;
|
||||
private int[] line03Keys;
|
||||
private int[] line04KeyWidths;
|
||||
private int[] line04Keys;
|
||||
private int[] line05KeyWidths;
|
||||
private int[] line05Keys;
|
||||
private int[] line06KeyWidths;
|
||||
private int[] line06Keys;
|
||||
|
||||
private Vector2 keyboardOffset;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
SetExitKey(KeyboardKey.Null); // Avoid exit on KEY_ESCAPE
|
||||
|
||||
// Keyboard line 01
|
||||
line01KeyWidths = new int[15];
|
||||
for (int i = 0; i < 15; i++) line01KeyWidths[i] = 45;
|
||||
line01KeyWidths[13] = 62; // PRINTSCREEN
|
||||
line01Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.Escape, (int)KeyboardKey.F1, (int)KeyboardKey.F2, (int)KeyboardKey.F3, (int)KeyboardKey.F4, (int)KeyboardKey.F5,
|
||||
(int)KeyboardKey.F6, (int)KeyboardKey.F7, (int)KeyboardKey.F8, (int)KeyboardKey.F9, (int)KeyboardKey.F10, (int)KeyboardKey.F11,
|
||||
(int)KeyboardKey.F12, (int)KeyboardKey.PrintScreen, (int)KeyboardKey.Pause
|
||||
};
|
||||
|
||||
// Keyboard line 02
|
||||
line02KeyWidths = new int[15];
|
||||
for (int i = 0; i < 15; i++) line02KeyWidths[i] = 45;
|
||||
line02KeyWidths[0] = 25; // GRAVE
|
||||
line02KeyWidths[13] = 82; // BACKSPACE
|
||||
line02Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.Grave, (int)KeyboardKey.One, (int)KeyboardKey.Two, (int)KeyboardKey.Three, (int)KeyboardKey.Four,
|
||||
(int)KeyboardKey.Five, (int)KeyboardKey.Six, (int)KeyboardKey.Seven, (int)KeyboardKey.Eight, (int)KeyboardKey.Nine,
|
||||
(int)KeyboardKey.Zero, (int)KeyboardKey.Minus, (int)KeyboardKey.Equal, (int)KeyboardKey.Backspace, (int)KeyboardKey.Delete
|
||||
};
|
||||
|
||||
// Keyboard line 03
|
||||
line03KeyWidths = new int[15];
|
||||
for (int i = 0; i < 15; i++) line03KeyWidths[i] = 45;
|
||||
line03KeyWidths[0] = 50; // TAB
|
||||
line03KeyWidths[13] = 57; // BACKSLASH
|
||||
line03Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.Tab, (int)KeyboardKey.Q, (int)KeyboardKey.W, (int)KeyboardKey.E, (int)KeyboardKey.R, (int)KeyboardKey.T, (int)KeyboardKey.Y,
|
||||
(int)KeyboardKey.U, (int)KeyboardKey.I, (int)KeyboardKey.O, (int)KeyboardKey.P, (int)KeyboardKey.LeftBracket,
|
||||
(int)KeyboardKey.RightBracket, (int)KeyboardKey.Backslash, (int)KeyboardKey.Insert
|
||||
};
|
||||
|
||||
// Keyboard line 04
|
||||
line04KeyWidths = new int[14];
|
||||
for (int i = 0; i < 14; i++) line04KeyWidths[i] = 45;
|
||||
line04KeyWidths[0] = 68; // CAPS
|
||||
line04KeyWidths[12] = 88; // ENTER
|
||||
line04Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.CapsLock, (int)KeyboardKey.A, (int)KeyboardKey.S, (int)KeyboardKey.D, (int)KeyboardKey.F, (int)KeyboardKey.G,
|
||||
(int)KeyboardKey.H, (int)KeyboardKey.J, (int)KeyboardKey.K, (int)KeyboardKey.L, (int)KeyboardKey.Semicolon,
|
||||
(int)KeyboardKey.Apostrophe, (int)KeyboardKey.Enter, (int)KeyboardKey.PageUp
|
||||
};
|
||||
|
||||
// Keyboard line 05
|
||||
line05KeyWidths = new int[14];
|
||||
for (int i = 0; i < 14; i++) line05KeyWidths[i] = 45;
|
||||
line05KeyWidths[0] = 80; // LSHIFT
|
||||
line05KeyWidths[11] = 76; // RSHIFT
|
||||
line05Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.LeftShift, (int)KeyboardKey.Z, (int)KeyboardKey.X, (int)KeyboardKey.C, (int)KeyboardKey.V, (int)KeyboardKey.B,
|
||||
(int)KeyboardKey.N, (int)KeyboardKey.M, (int)KeyboardKey.Comma, (int)KeyboardKey.Period, /*KEY_MINUS*/
|
||||
(int)KeyboardKey.Slash, (int)KeyboardKey.RightShift, (int)KeyboardKey.Up, (int)KeyboardKey.PageDown
|
||||
};
|
||||
|
||||
// Keyboard line 06
|
||||
line06KeyWidths = new int[11];
|
||||
for (int i = 0; i < 11; i++) line06KeyWidths[i] = 45;
|
||||
line06KeyWidths[0] = 80; // LCTRL
|
||||
line06KeyWidths[3] = 208; // SPACE
|
||||
line06KeyWidths[7] = 60; // RCTRL
|
||||
line06Keys = new int[]
|
||||
{
|
||||
(int)KeyboardKey.LeftControl, (int)KeyboardKey.LeftSuper, (int)KeyboardKey.LeftAlt,
|
||||
(int)KeyboardKey.Space, (int)KeyboardKey.RightAlt, 162, (int)KeyboardKey.Null,
|
||||
(int)KeyboardKey.RightControl, (int)KeyboardKey.Left, (int)KeyboardKey.Down, (int)KeyboardKey.Right
|
||||
};
|
||||
|
||||
keyboardOffset = new Vector2(26, 80);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
int key = GetKeyPressed(); // Get pressed keycode
|
||||
if (key > 0) TraceLog(TraceLogLevel.Info, $"KEYBOARD TESTBED: KEY PRESSED: {key}");
|
||||
|
||||
int ch = GetCharPressed(); // Get pressed char for text input, using OS mapping
|
||||
if (ch > 0) TraceLog(TraceLogLevel.Info, $"KEYBOARD TESTBED: CHAR PRESSED: {(char)ch} ({ch})");
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("KEYBOARD LAYOUT: ENG-US", 26, 38, 20, Color.LightGray);
|
||||
|
||||
// Keyboard line 01 - 15 keys
|
||||
// ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, IMP, CLOSE
|
||||
for (int i = 0, recOffsetX = 0; i < 15; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y, (float)line01KeyWidths[i], 30.0f), line01Keys[i]);
|
||||
recOffsetX += line01KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
// Keyboard line 02 - 15 keys
|
||||
// `, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -, =, BACKSPACE, DEL
|
||||
for (int i = 0, recOffsetX = 0; i < 15; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + KeyRecSpacing, (float)line02KeyWidths[i], 38.0f), line02Keys[i]);
|
||||
recOffsetX += line02KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
// Keyboard line 03 - 15 keys
|
||||
// TAB, Q, W, E, R, T, Y, U, I, O, P, [, ], \, INS
|
||||
for (int i = 0, recOffsetX = 0; i < 15; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 + KeyRecSpacing * 2, (float)line03KeyWidths[i], 38.0f), line03Keys[i]);
|
||||
recOffsetX += line03KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
// Keyboard line 04 - 14 keys
|
||||
// MAYUS, A, S, D, F, G, H, J, K, L, ;, ', ENTER, REPAG
|
||||
for (int i = 0, recOffsetX = 0; i < 14; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 2 + KeyRecSpacing * 3, (float)line04KeyWidths[i], 38.0f), line04Keys[i]);
|
||||
recOffsetX += line04KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
// Keyboard line 05 - 14 keys
|
||||
// LSHIFT, Z, X, C, V, B, N, M, ,, ., /, RSHIFT, UP, AVPAG
|
||||
for (int i = 0, recOffsetX = 0; i < 14; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 3 + KeyRecSpacing * 4, (float)line05KeyWidths[i], 38.0f), line05Keys[i]);
|
||||
recOffsetX += line05KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
// Keyboard line 06 - 11 keys
|
||||
// LCTRL, WIN, LALT, SPACE, ALTGR, \, FN, RCTRL, LEFT, DOWN, RIGHT
|
||||
for (int i = 0, recOffsetX = 0; i < 11; i++)
|
||||
{
|
||||
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 4 + KeyRecSpacing * 5, (float)line06KeyWidths[i], 38.0f), line06Keys[i]);
|
||||
recOffsetX += line06KeyWidths[i] + KeyRecSpacing;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Get keyboard keycode as text (US keyboard)
|
||||
// NOTE: Mapping for other keyboard layouts can be done here
|
||||
private static string GetKeyText(int key)
|
||||
{
|
||||
switch ((KeyboardKey)key)
|
||||
{
|
||||
case KeyboardKey.Apostrophe: return "'"; // Key: '
|
||||
case KeyboardKey.Comma: return ","; // Key: ,
|
||||
case KeyboardKey.Minus: return "-"; // Key: -
|
||||
case KeyboardKey.Period: return "."; // Key: .
|
||||
case KeyboardKey.Slash: return "/"; // Key: /
|
||||
case KeyboardKey.Zero: return "0"; // Key: 0
|
||||
case KeyboardKey.One: return "1"; // Key: 1
|
||||
case KeyboardKey.Two: return "2"; // Key: 2
|
||||
case KeyboardKey.Three: return "3"; // Key: 3
|
||||
case KeyboardKey.Four: return "4"; // Key: 4
|
||||
case KeyboardKey.Five: return "5"; // Key: 5
|
||||
case KeyboardKey.Six: return "6"; // Key: 6
|
||||
case KeyboardKey.Seven: return "7"; // Key: 7
|
||||
case KeyboardKey.Eight: return "8"; // Key: 8
|
||||
case KeyboardKey.Nine: return "9"; // Key: 9
|
||||
case KeyboardKey.Semicolon: return ";"; // Key: ;
|
||||
case KeyboardKey.Equal: return "="; // Key: =
|
||||
case KeyboardKey.A: return "A"; // Key: A | a
|
||||
case KeyboardKey.B: return "B"; // Key: B | b
|
||||
case KeyboardKey.C: return "C"; // Key: C | c
|
||||
case KeyboardKey.D: return "D"; // Key: D | d
|
||||
case KeyboardKey.E: return "E"; // Key: E | e
|
||||
case KeyboardKey.F: return "F"; // Key: F | f
|
||||
case KeyboardKey.G: return "G"; // Key: G | g
|
||||
case KeyboardKey.H: return "H"; // Key: H | h
|
||||
case KeyboardKey.I: return "I"; // Key: I | i
|
||||
case KeyboardKey.J: return "J"; // Key: J | j
|
||||
case KeyboardKey.K: return "K"; // Key: K | k
|
||||
case KeyboardKey.L: return "L"; // Key: L | l
|
||||
case KeyboardKey.M: return "M"; // Key: M | m
|
||||
case KeyboardKey.N: return "N"; // Key: N | n
|
||||
case KeyboardKey.O: return "O"; // Key: O | o
|
||||
case KeyboardKey.P: return "P"; // Key: P | p
|
||||
case KeyboardKey.Q: return "Q"; // Key: Q | q
|
||||
case KeyboardKey.R: return "R"; // Key: R | r
|
||||
case KeyboardKey.S: return "S"; // Key: S | s
|
||||
case KeyboardKey.T: return "T"; // Key: T | t
|
||||
case KeyboardKey.U: return "U"; // Key: U | u
|
||||
case KeyboardKey.V: return "V"; // Key: V | v
|
||||
case KeyboardKey.W: return "W"; // Key: W | w
|
||||
case KeyboardKey.X: return "X"; // Key: X | x
|
||||
case KeyboardKey.Y: return "Y"; // Key: Y | y
|
||||
case KeyboardKey.Z: return "Z"; // Key: Z | z
|
||||
case KeyboardKey.LeftBracket: return "["; // Key: [
|
||||
case KeyboardKey.Backslash: return "\\"; // Key: '\'
|
||||
case KeyboardKey.RightBracket: return "]"; // Key: ]
|
||||
case KeyboardKey.Grave: return "`"; // Key: `
|
||||
case KeyboardKey.Space: return "SPACE"; // Key: Space
|
||||
case KeyboardKey.Escape: return "ESC"; // Key: Esc
|
||||
case KeyboardKey.Enter: return "ENTER"; // Key: Enter
|
||||
case KeyboardKey.Tab: return "TAB"; // Key: Tab
|
||||
case KeyboardKey.Backspace: return "BACK"; // Key: Backspace
|
||||
case KeyboardKey.Insert: return "INS"; // Key: Ins
|
||||
case KeyboardKey.Delete: return "DEL"; // Key: Del
|
||||
case KeyboardKey.Right: return "RIGHT"; // Key: Cursor right
|
||||
case KeyboardKey.Left: return "LEFT"; // Key: Cursor left
|
||||
case KeyboardKey.Down: return "DOWN"; // Key: Cursor down
|
||||
case KeyboardKey.Up: return "UP"; // Key: Cursor up
|
||||
case KeyboardKey.PageUp: return "PGUP"; // Key: Page up
|
||||
case KeyboardKey.PageDown: return "PGDOWN"; // Key: Page down
|
||||
case KeyboardKey.Home: return "HOME"; // Key: Home
|
||||
case KeyboardKey.End: return "END"; // Key: End
|
||||
case KeyboardKey.CapsLock: return "CAPS"; // Key: Caps lock
|
||||
case KeyboardKey.ScrollLock: return "LOCK"; // Key: Scroll down
|
||||
case KeyboardKey.NumLock: return "NUMLOCK"; // Key: Num lock
|
||||
case KeyboardKey.PrintScreen: return "PRINTSCR"; // Key: Print screen
|
||||
case KeyboardKey.Pause: return "PAUSE"; // Key: Pause
|
||||
case KeyboardKey.F1: return "F1"; // Key: F1
|
||||
case KeyboardKey.F2: return "F2"; // Key: F2
|
||||
case KeyboardKey.F3: return "F3"; // Key: F3
|
||||
case KeyboardKey.F4: return "F4"; // Key: F4
|
||||
case KeyboardKey.F5: return "F5"; // Key: F5
|
||||
case KeyboardKey.F6: return "F6"; // Key: F6
|
||||
case KeyboardKey.F7: return "F7"; // Key: F7
|
||||
case KeyboardKey.F8: return "F8"; // Key: F8
|
||||
case KeyboardKey.F9: return "F9"; // Key: F9
|
||||
case KeyboardKey.F10: return "F10"; // Key: F10
|
||||
case KeyboardKey.F11: return "F11"; // Key: F11
|
||||
case KeyboardKey.F12: return "F12"; // Key: F12
|
||||
case KeyboardKey.LeftShift: return "LSHIFT"; // Key: Shift left
|
||||
case KeyboardKey.LeftControl: return "LCTRL"; // Key: Control left
|
||||
case KeyboardKey.LeftAlt: return "LALT"; // Key: Alt left
|
||||
case KeyboardKey.LeftSuper: return "WIN"; // Key: Super left
|
||||
case KeyboardKey.RightShift: return "RSHIFT"; // Key: Shift right
|
||||
case KeyboardKey.RightControl: return "RCTRL"; // Key: Control right
|
||||
case KeyboardKey.RightAlt: return "ALTGR"; // Key: Alt right
|
||||
case KeyboardKey.RightSuper: return "RSUPER"; // Key: Super right
|
||||
case KeyboardKey.KeyboardMenu: return "KBMENU"; // Key: KB menu
|
||||
case KeyboardKey.Kp0: return "KP0"; // Key: Keypad 0
|
||||
case KeyboardKey.Kp1: return "KP1"; // Key: Keypad 1
|
||||
case KeyboardKey.Kp2: return "KP2"; // Key: Keypad 2
|
||||
case KeyboardKey.Kp3: return "KP3"; // Key: Keypad 3
|
||||
case KeyboardKey.Kp4: return "KP4"; // Key: Keypad 4
|
||||
case KeyboardKey.Kp5: return "KP5"; // Key: Keypad 5
|
||||
case KeyboardKey.Kp6: return "KP6"; // Key: Keypad 6
|
||||
case KeyboardKey.Kp7: return "KP7"; // Key: Keypad 7
|
||||
case KeyboardKey.Kp8: return "KP8"; // Key: Keypad 8
|
||||
case KeyboardKey.Kp9: return "KP9"; // Key: Keypad 9
|
||||
case KeyboardKey.KpDecimal: return "KPDEC"; // Key: Keypad .
|
||||
case KeyboardKey.KpDivide: return "KPDIV"; // Key: Keypad /
|
||||
case KeyboardKey.KpMultiply: return "KPMUL"; // Key: Keypad *
|
||||
case KeyboardKey.KpSubtract: return "KPSUB"; // Key: Keypad -
|
||||
case KeyboardKey.KpAdd: return "KPADD"; // Key: Keypad +
|
||||
case KeyboardKey.KpEnter: return "KPENTER"; // Key: Keypad Enter
|
||||
case KeyboardKey.KpEqual: return "KPEQU"; // Key: Keypad =
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Draw keyboard key
|
||||
private static void GuiKeyboardKey(Rectangle bounds, int key)
|
||||
{
|
||||
if (key == (int)KeyboardKey.Null) DrawRectangleLinesEx(bounds, 2.0f, Color.LightGray);
|
||||
else
|
||||
{
|
||||
if (IsKeyDown((KeyboardKey)key))
|
||||
{
|
||||
DrawRectangleLinesEx(bounds, 2.0f, Color.Maroon);
|
||||
DrawText(GetKeyText(key), (int)(bounds.X + 4), (int)(bounds.Y + 4), 10, Color.Maroon);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangleLinesEx(bounds, 2.0f, Color.DarkGray);
|
||||
DrawText(GetKeyText(key), (int)(bounds.X + 4), (int)(bounds.Y + 4), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), bounds))
|
||||
{
|
||||
DrawRectangleRec(bounds, Fade(Color.Red, 0.2f));
|
||||
DrawRectangleLinesEx(bounds, 3.0f, Color.Red);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard testbed");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new KeyboardTestbed();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,153 +1,185 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib example - loading thread
|
||||
* raylib [core] example - loading thread
|
||||
*
|
||||
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||
* NOTE: raylib is NOT thread-safe: the loading thread only updates plain data
|
||||
* (progress counter and loaded flag); all raylib calls happen on the main thread.
|
||||
*
|
||||
* Example originally created with raylib 2.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Color;
|
||||
using static Raylib_cs.KeyboardKey;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
enum State
|
||||
[ExcludeFromBrowser("System.Threading.Thread is unsupported on single-threaded wasm")]
|
||||
public partial class LoadingThread : IExample
|
||||
{
|
||||
STATE_WAITING,
|
||||
STATE_LOADING,
|
||||
STATE_FINISHED
|
||||
}
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
public class LoadingThread
|
||||
{
|
||||
// C# bool is atomic. Used for synchronization
|
||||
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#atomicity-of-variable-references
|
||||
// Data Loaded completion indicator
|
||||
static bool dataLoaded = false;
|
||||
public string Name => "Core / Loading Thread";
|
||||
|
||||
// Data progress accumulator
|
||||
static int dataProgress = 0;
|
||||
public string Title => "raylib [core] example - loading thread";
|
||||
|
||||
enum State
|
||||
{
|
||||
Waiting,
|
||||
Loading,
|
||||
Finished
|
||||
}
|
||||
|
||||
// Loading data thread; a Thread can only be started once, so a fresh one
|
||||
// is created for every load
|
||||
Thread loadingThread;
|
||||
|
||||
// Data loaded completion indicator; volatile so the main thread sees the
|
||||
// background thread's writes
|
||||
volatile bool dataLoaded;
|
||||
|
||||
// Data progress accumulator (0..500, the progress bar width in pixels)
|
||||
volatile int dataProgress;
|
||||
|
||||
State state;
|
||||
int framesCounter;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
loadingThread = null;
|
||||
dataLoaded = false;
|
||||
dataProgress = 0;
|
||||
|
||||
state = State.Waiting;
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (state)
|
||||
{
|
||||
case State.Waiting:
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
loadingThread = new Thread(LoadDataThread) { IsBackground = true };
|
||||
loadingThread.Start();
|
||||
TraceLog(TraceLogLevel.Info, "Loading thread initialized successfully");
|
||||
|
||||
state = State.Loading;
|
||||
}
|
||||
break;
|
||||
|
||||
case State.Loading:
|
||||
framesCounter++;
|
||||
if (dataLoaded)
|
||||
{
|
||||
framesCounter = 0;
|
||||
loadingThread.Join();
|
||||
TraceLog(TraceLogLevel.Info, "Loading thread terminated");
|
||||
|
||||
state = State.Finished;
|
||||
}
|
||||
break;
|
||||
|
||||
case State.Finished:
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
// Reset everything to launch again
|
||||
dataLoaded = false;
|
||||
dataProgress = 0;
|
||||
|
||||
state = State.Waiting;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case State.Waiting:
|
||||
DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, Color.DarkGray);
|
||||
break;
|
||||
|
||||
case State.Loading:
|
||||
DrawRectangle(150, 200, dataProgress, 60, Color.SkyBlue);
|
||||
if ((framesCounter / 15) % 2 == 0)
|
||||
{
|
||||
DrawText("LOADING DATA...", 240, 210, 40, Color.DarkBlue);
|
||||
}
|
||||
break;
|
||||
|
||||
case State.Finished:
|
||||
DrawRectangle(150, 200, 500, 60, Color.Lime);
|
||||
DrawText("DATA LOADED!", 250, 210, 40, Color.Green);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DrawRectangleLines(150, 200, 500, 60, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - loading thread");
|
||||
|
||||
// Loading data thread id
|
||||
Thread thread = new(new ThreadStart(LoadDataThread));
|
||||
|
||||
State state = State.STATE_WAITING;
|
||||
int framesCounter = 0;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingThread();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (state)
|
||||
{
|
||||
case State.STATE_WAITING:
|
||||
{
|
||||
if (IsKeyPressed(KEY_ENTER))
|
||||
{
|
||||
thread.Start();
|
||||
//int error = pthread_create(ref, NULL, ref, NULL);
|
||||
//if (error != 0) TraceLog(TraceLogLevel.LOG_ERROR, "Error creating loading thread");
|
||||
//else TraceLog(TraceLogLevel.LOG_INFO, "Loading thread initialized successfully");
|
||||
|
||||
state = State.STATE_LOADING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case State.STATE_LOADING:
|
||||
{
|
||||
framesCounter++;
|
||||
if (dataLoaded)
|
||||
{
|
||||
framesCounter = 0;
|
||||
state = State.STATE_FINISHED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case State.STATE_FINISHED:
|
||||
{
|
||||
if (IsKeyPressed(KEY_ENTER))
|
||||
{
|
||||
// Reset everything to launch again
|
||||
// atomic_store(ref, false);
|
||||
dataProgress = 0;
|
||||
state = State.STATE_WAITING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case State.STATE_WAITING:
|
||||
DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, DARKGRAY);
|
||||
break;
|
||||
case State.STATE_LOADING:
|
||||
{
|
||||
DrawRectangle(150, 200, dataProgress, 60, SKYBLUE);
|
||||
if ((framesCounter / 15) % 2 == 0) DrawText("LOADING DATA...", 240, 210, 40, DARKBLUE);
|
||||
}
|
||||
break;
|
||||
case State.STATE_FINISHED:
|
||||
{
|
||||
DrawRectangle(150, 200, 500, 60, LIME);
|
||||
DrawText("DATA LOADED!", 250, 210, 40, GREEN);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
DrawRectangleLines(150, 200, 500, 60, DARKGRAY);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Loading data thread function definition
|
||||
static void LoadDataThread()
|
||||
void LoadDataThread()
|
||||
{
|
||||
int timeCounter = 0; // Time counted in ms
|
||||
// clock_t prevTime = clock(); // Previous time
|
||||
int timeCounter = 0; // Time counted in ms
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
// We simulate data loading with a time counter for 5 seconds
|
||||
while (timeCounter < 5000)
|
||||
{
|
||||
//clock_t currentTime = clock() - prevTime;
|
||||
//timeCounter = currentTime*1000/CLOCKS_PER_SEC;
|
||||
timeCounter += 1;
|
||||
timeCounter = (int)stopwatch.ElapsedMilliseconds;
|
||||
|
||||
// We accumulate time over a global variable to be used in
|
||||
// main thread as a progress bar
|
||||
|
|
@ -158,4 +190,3 @@ public class LoadingThread
|
|||
dataLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
209
Examples/Core/MonitorDetector.cs
Normal file
209
Examples/Core/MonitorDetector.cs
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - monitor detector
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
[ExcludeFromBrowser("GetMonitorCount() is not implemented on the wasm target")]
|
||||
public partial class MonitorDetector : IExample
|
||||
{
|
||||
private const int MaxMonitors = 10;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Monitor Detector";
|
||||
|
||||
public string Title => "raylib [core] example - monitor detector";
|
||||
|
||||
// Monitor info
|
||||
private struct MonitorInfo
|
||||
{
|
||||
public Vector2 Position;
|
||||
public string Name;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int PhysicalWidth;
|
||||
public int PhysicalHeight;
|
||||
public int RefreshRate;
|
||||
}
|
||||
|
||||
private MonitorInfo[] monitors;
|
||||
private int currentMonitorIndex;
|
||||
private int monitorCount;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
monitors = new MonitorInfo[MaxMonitors];
|
||||
currentMonitorIndex = GetCurrentMonitor();
|
||||
monitorCount = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Variables to find the max x and Y to calculate the scale
|
||||
int maxWidth = 1;
|
||||
int maxHeight = 1;
|
||||
|
||||
// Monitor offset is to fix when monitor position x is negative
|
||||
int monitorOffsetX = 0;
|
||||
|
||||
// Rebuild monitors array every frame
|
||||
monitorCount = GetMonitorCount();
|
||||
for (int i = 0; i < monitorCount; i++)
|
||||
{
|
||||
monitors[i] = new MonitorInfo
|
||||
{
|
||||
Position = GetMonitorPosition(i),
|
||||
Name = GetMonitorName_(i),
|
||||
Width = GetMonitorWidth(i),
|
||||
Height = GetMonitorHeight(i),
|
||||
PhysicalWidth = GetMonitorPhysicalWidth(i),
|
||||
PhysicalHeight = GetMonitorPhysicalHeight(i),
|
||||
RefreshRate = GetMonitorRefreshRate(i)
|
||||
};
|
||||
|
||||
if (monitors[i].Position.X < monitorOffsetX)
|
||||
{
|
||||
monitorOffsetX = -(int)monitors[i].Position.X;
|
||||
}
|
||||
|
||||
int width = (int)monitors[i].Position.X + monitors[i].Width;
|
||||
int height = (int)monitors[i].Position.Y + monitors[i].Height;
|
||||
|
||||
if (maxWidth < width)
|
||||
{
|
||||
maxWidth = width;
|
||||
}
|
||||
if (maxHeight < height)
|
||||
{
|
||||
maxHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter) && (monitorCount > 1))
|
||||
{
|
||||
currentMonitorIndex += 1;
|
||||
|
||||
// Set index to 0 if the last one
|
||||
if (currentMonitorIndex == monitorCount)
|
||||
{
|
||||
currentMonitorIndex = 0;
|
||||
}
|
||||
|
||||
SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex
|
||||
}
|
||||
else
|
||||
{
|
||||
currentMonitorIndex = GetCurrentMonitor(); // Get currentMonitorIndex if manually moved
|
||||
}
|
||||
|
||||
float monitorScale = 0.6f;
|
||||
|
||||
if (maxHeight > (maxWidth + monitorOffsetX))
|
||||
{
|
||||
monitorScale *= ((float)screenHeight / (float)maxHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
monitorScale *= ((float)screenWidth / (float)(maxWidth + monitorOffsetX));
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press [Enter] to move window to next monitor available", 20, 20, 20, Color.DarkGray);
|
||||
|
||||
DrawRectangleLines(20, 60, screenWidth - 40, screenHeight - 100, Color.DarkGray);
|
||||
|
||||
// Draw Monitor Rectangles with information inside
|
||||
for (int i = 0; i < monitorCount; i++)
|
||||
{
|
||||
// Calculate retangle position and size using monitorScale
|
||||
Rectangle rec = new Rectangle(
|
||||
(monitors[i].Position.X + monitorOffsetX) * monitorScale + 140,
|
||||
monitors[i].Position.Y * monitorScale + 80,
|
||||
monitors[i].Width * monitorScale,
|
||||
monitors[i].Height * monitorScale
|
||||
);
|
||||
|
||||
// Draw monitor name and information inside the rectangle
|
||||
DrawText($"[{i}] {monitors[i].Name}", (int)rec.X + 10, (int)rec.Y + (int)(100 * monitorScale), (int)(120 * monitorScale), Color.Blue);
|
||||
DrawText(
|
||||
$"Resolution: [{monitors[i].Width}px x {monitors[i].Height}px]\nRefreshRate: [{monitors[i].RefreshRate}hz]\nPhysical Size: [{monitors[i].PhysicalWidth}mm x {monitors[i].PhysicalHeight}mm]\nPosition: {monitors[i].Position.X,3:F0} x {monitors[i].Position.Y,3:F0}",
|
||||
(int)rec.X + 10, (int)rec.Y + (int)(200 * monitorScale), (int)(120 * monitorScale), Color.DarkGray);
|
||||
|
||||
// Highlight current monitor
|
||||
if (i == currentMonitorIndex)
|
||||
{
|
||||
DrawRectangleLinesEx(rec, 5, Color.Red);
|
||||
Vector2 windowPosition = new Vector2((GetWindowPosition().X + monitorOffsetX) * monitorScale + 140, GetWindowPosition().Y * monitorScale + 80);
|
||||
|
||||
// Draw window position based on monitors
|
||||
DrawRectangleV(windowPosition, new Vector2(screenWidth * monitorScale, screenHeight * monitorScale), Fade(Color.Green, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectangleLinesEx(rec, 5, Color.Gray);
|
||||
}
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor detector");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MonitorDetector();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Picking in 3d mode
|
||||
* raylib [core] example - 3d picking
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 4.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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,106 +18,148 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Picking3d
|
||||
public partial class Picking3d : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Picking 3D";
|
||||
|
||||
public string Title => "raylib [core] example - 3d picking";
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
private Vector3 cubeSize;
|
||||
private Ray ray; // Picking line ray
|
||||
private RayCollision collision; // Ray collision hit info
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new Camera3D();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cubePosition = new(0.0f, 1.0f, 0.0f);
|
||||
cubeSize = new(2.0f, 2.0f, 2.0f);
|
||||
|
||||
ray = new(); // Picking line ray
|
||||
collision = new(); // Ray collision hit info
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
}
|
||||
|
||||
// Toggle camera controls
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
EnableCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableCursor();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (!collision.Hit)
|
||||
{
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check collision between ray and box
|
||||
BoundingBox box = new(
|
||||
cubePosition - cubeSize / 2,
|
||||
cubePosition + cubeSize / 2
|
||||
);
|
||||
collision = GetRayCollisionBox(ray, box);
|
||||
}
|
||||
else
|
||||
{
|
||||
collision.Hit = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Red);
|
||||
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Maroon);
|
||||
|
||||
DrawCubeWires(cubePosition, cubeSize.X + 0.2f, cubeSize.Y + 0.2f, cubeSize.Z + 0.2f, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Gray);
|
||||
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.DarkGray);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Try clicking on the box with your mouse!", 240, 10, 20, Color.DarkGray);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
var posX = (screenWidth - MeasureText("BOX SELECTED", 30)) / 2;
|
||||
DrawText("BOX SELECTED", posX, (int)(screenHeight * 0.1f), 30, Color.Green);
|
||||
}
|
||||
|
||||
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 1.0f, 0.0f);
|
||||
Vector3 cubeSize = new(2.0f, 2.0f, 2.0f);
|
||||
|
||||
// Picking line ray
|
||||
Ray ray = new(new Vector3(0.0f, 0.0f, 0.0f), Vector3.Zero);
|
||||
RayCollision collision = new();
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Picking3d();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (!collision.Hit)
|
||||
{
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check collision between ray and box
|
||||
BoundingBox box = new(
|
||||
cubePosition - cubeSize / 2,
|
||||
cubePosition + cubeSize / 2
|
||||
);
|
||||
collision = GetRayCollisionBox(ray, box);
|
||||
}
|
||||
else
|
||||
{
|
||||
collision.Hit = false;
|
||||
}
|
||||
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Red);
|
||||
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Maroon);
|
||||
|
||||
DrawCubeWires(cubePosition, cubeSize.X + 0.2f, cubeSize.Y + 0.2f, cubeSize.Z + 0.2f, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Gray);
|
||||
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.DarkGray);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Try selecting the box with mouse!", 240, 10, 20, Color.DarkGray);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
int posX = (screenWidth - MeasureText("BOX SELECTED", 30)) / 2;
|
||||
DrawText("BOX SELECTED", posX, (int)(screenHeight * 0.1f), 30, Color.Green);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
183
Examples/Core/RandomSequence.cs
Normal file
183
Examples/Core/RandomSequence.cs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - random sequence
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example contributed by Dalton Overmyer (@REDl3east) 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 Dalton Overmyer (@REDl3east)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class RandomSequence : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Random Sequence";
|
||||
|
||||
public string Title => "raylib [core] example - random sequence";
|
||||
|
||||
private struct ColorRect
|
||||
{
|
||||
public Color Color;
|
||||
public Rectangle Rect;
|
||||
}
|
||||
|
||||
private int rectCount;
|
||||
private float rectSize;
|
||||
private ColorRect[] rectangles;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
rectCount = 20;
|
||||
rectSize = (float)screenWidth / rectCount;
|
||||
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
ShuffleColorRectSequence(rectangles, rectCount);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Up))
|
||||
{
|
||||
rectCount++;
|
||||
rectSize = (float)screenWidth / rectCount;
|
||||
|
||||
// Re-generate random sequence with new count
|
||||
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Down))
|
||||
{
|
||||
if (rectCount >= 4)
|
||||
{
|
||||
rectCount--;
|
||||
rectSize = (float)screenWidth / rectCount;
|
||||
|
||||
// Re-generate random sequence with new count
|
||||
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = 0; i < rectCount; i++)
|
||||
{
|
||||
DrawRectangleRec(rectangles[i].Rect, rectangles[i].Color);
|
||||
|
||||
DrawText("Press SPACE to shuffle the current sequence", 10, screenHeight - 96, 20, Color.Black);
|
||||
DrawText("Press UP to add a rectangle and generate a new sequence", 10, screenHeight - 64, 20, Color.Black);
|
||||
DrawText("Press DOWN to remove a rectangle and generate a new sequence", 10, screenHeight - 32, 20, Color.Black);
|
||||
}
|
||||
|
||||
DrawText($"Count: {rectCount} rectangles", 10, 10, 20, Color.Maroon);
|
||||
|
||||
DrawFPS(screenWidth - 80, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
private static Color GenerateRandomColor()
|
||||
{
|
||||
return new Color(
|
||||
GetRandomValue(0, 255),
|
||||
GetRandomValue(0, 255),
|
||||
GetRandomValue(0, 255),
|
||||
255
|
||||
);
|
||||
}
|
||||
|
||||
private static ColorRect[] GenerateRandomColorRectSequence(float rectCount, float rectWidth, float screenWidth, float screenHeight)
|
||||
{
|
||||
ColorRect[] rectangles = new ColorRect[(int)rectCount];
|
||||
|
||||
int[] seq = GetRandomSequence((uint)rectCount, 0, (int)rectCount - 1);
|
||||
float rectSeqWidth = rectCount * rectWidth;
|
||||
float startX = (screenWidth - rectSeqWidth) * 0.5f;
|
||||
|
||||
for (int i = 0; i < rectCount; i++)
|
||||
{
|
||||
int rectHeight = (int)Remap(seq[i], 0, rectCount - 1, 0, screenHeight);
|
||||
|
||||
rectangles[i].Color = GenerateRandomColor();
|
||||
rectangles[i].Rect = new Rectangle(startX + i * rectWidth, screenHeight - rectHeight, rectWidth, rectHeight);
|
||||
}
|
||||
|
||||
return rectangles;
|
||||
}
|
||||
|
||||
private static void ShuffleColorRectSequence(ColorRect[] rectangles, int rectCount)
|
||||
{
|
||||
int[] seq = GetRandomSequence((uint)rectCount, 0, rectCount - 1);
|
||||
|
||||
for (int i1 = 0; i1 < rectCount; i1++)
|
||||
{
|
||||
int i2 = seq[i1];
|
||||
|
||||
// Swap only the color and height
|
||||
ColorRect tmp = rectangles[i1];
|
||||
rectangles[i1].Color = rectangles[i2].Color;
|
||||
rectangles[i1].Rect.Height = rectangles[i2].Rect.Height;
|
||||
rectangles[i1].Rect.Y = rectangles[i2].Rect.Y;
|
||||
rectangles[i2].Color = tmp.Color;
|
||||
rectangles[i2].Rect.Height = tmp.Rect.Height;
|
||||
rectangles[i2].Rect.Y = tmp.Rect.Y;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - random sequence");
|
||||
|
||||
SetTargetFPS(60);
|
||||
|
||||
var game = new RandomSequence();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Generate random values
|
||||
* raylib [core] example - random values
|
||||
*
|
||||
* This example 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.1
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -13,57 +17,81 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class RandomValues
|
||||
public partial class RandomValues : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Random Values";
|
||||
|
||||
public string Title => "raylib [core] example - random values";
|
||||
|
||||
private int randValue; // Get a random integer number between -8 and 5 (both included)
|
||||
private int framesCounter; // Variable used to count frames
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// SetRandomSeed(0xaabbccff); // Set a custom random seed if desired, by default: "time(NULL)"
|
||||
|
||||
randValue = GetRandomValue(-8, 5); // Get a random integer number between -8 and 5 (both included)
|
||||
|
||||
framesCounter = 0; // Variable used to count frames
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
framesCounter++;
|
||||
|
||||
// Every two seconds (120 frames) a new random value is generated
|
||||
if (((framesCounter / 120) % 2) == 1)
|
||||
{
|
||||
randValue = GetRandomValue(-8, 5);
|
||||
framesCounter = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, Color.Maroon);
|
||||
|
||||
DrawText($"{randValue}", 360, 180, 80, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - random values");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - generate random values");
|
||||
|
||||
// Variable used to count frames
|
||||
int framesCounter = 0;
|
||||
|
||||
// Get a random integer number between -8 and 5 (both included)
|
||||
int randValue = GetRandomValue(-8, 5);
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new RandomValues();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
framesCounter++;
|
||||
|
||||
// Every two seconds (120 frames) a new random value is generated
|
||||
if (((framesCounter / 120) % 2) == 1)
|
||||
{
|
||||
randValue = GetRandomValue(-8, 5);
|
||||
framesCounter = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, Color.Maroon);
|
||||
|
||||
DrawText($"{randValue}", 360, 180, 80, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
139
Examples/Core/RenderTexture.cs
Normal file
139
Examples/Core/RenderTexture.cs
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - render texture
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class RenderTextureDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// Define a render texture to render
|
||||
private const int renderTextureWidth = 300;
|
||||
private const int renderTextureHeight = 300;
|
||||
|
||||
public string Name => "Core / Render Texture";
|
||||
|
||||
public string Title => "raylib [core] example - render texture";
|
||||
|
||||
private RenderTexture2D target;
|
||||
private Vector2 ballPosition;
|
||||
private Vector2 ballSpeed;
|
||||
private int ballRadius;
|
||||
private float rotation;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
target = LoadRenderTexture(renderTextureWidth, renderTextureHeight);
|
||||
|
||||
ballPosition = new Vector2(renderTextureWidth / 2.0f, renderTextureHeight / 2.0f);
|
||||
ballSpeed = new Vector2(5.0f, 4.0f);
|
||||
ballRadius = 20;
|
||||
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//-----------------------------------------------------
|
||||
// Ball movement logic
|
||||
ballPosition.X += ballSpeed.X;
|
||||
ballPosition.Y += ballSpeed.Y;
|
||||
|
||||
// Check walls collision for bouncing
|
||||
if ((ballPosition.X >= (renderTextureWidth - ballRadius)) || (ballPosition.X <= ballRadius))
|
||||
{
|
||||
ballSpeed.X *= -1.0f;
|
||||
}
|
||||
if ((ballPosition.Y >= (renderTextureHeight - ballRadius)) || (ballPosition.Y <= ballRadius))
|
||||
{
|
||||
ballSpeed.Y *= -1.0f;
|
||||
}
|
||||
|
||||
// Render texture rotation
|
||||
rotation += 0.5f;
|
||||
//-----------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//-----------------------------------------------------
|
||||
// Draw our scene to the render texture
|
||||
BeginTextureMode(target);
|
||||
|
||||
ClearBackground(Color.SkyBlue);
|
||||
|
||||
DrawRectangle(0, 0, 20, 20, Color.Red);
|
||||
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Draw render texture to main framebuffer
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw our render texture with rotation applied
|
||||
// NOTE 1: We set the origin of the texture to the center of the render texture
|
||||
// NOTE 2: We flip vertically the texture setting negative source rectangle height
|
||||
DrawTexturePro(target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Rectangle(screenWidth / 2.0f, screenHeight / 2.0f, target.Texture.Width, target.Texture.Height),
|
||||
new Vector2(target.Texture.Width / 2.0f, target.Texture.Height / 2.0f), rotation, Color.White);
|
||||
|
||||
DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, Color.Black);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//-----------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//---------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - render texture");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//----------------------------------------------------------
|
||||
|
||||
var game = new RenderTextureDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//---------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//----------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Scissor test
|
||||
* raylib [core] example - scissor test
|
||||
*
|
||||
* 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: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.0
|
||||
*
|
||||
* Example contributed by Chris Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 Chris Dill (@MysteriousSpace)
|
||||
* 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 Chris Dill (@MysteriousSpace)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,68 +19,92 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class ScissorTest
|
||||
public partial class ScissorTest : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Scissor Test";
|
||||
|
||||
public string Title => "raylib [core] example - scissor test";
|
||||
|
||||
private Rectangle scissorArea;
|
||||
private bool scissorMode;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
scissorArea = new(0, 0, 300, 300);
|
||||
scissorMode = true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.S))
|
||||
{
|
||||
scissorMode = !scissorMode;
|
||||
}
|
||||
|
||||
// Centre the scissor area around the mouse position
|
||||
scissorArea.X = GetMouseX() - scissorArea.Width / 2;
|
||||
scissorArea.Y = GetMouseY() - scissorArea.Height / 2;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (scissorMode)
|
||||
{
|
||||
BeginScissorMode((int)scissorArea.X, (int)scissorArea.Y, (int)scissorArea.Width, (int)scissorArea.Height);
|
||||
}
|
||||
|
||||
// Draw full screen rectangle and some text
|
||||
// NOTE: Only part defined by scissor area will be rendered
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Red);
|
||||
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
if (scissorMode)
|
||||
{
|
||||
EndScissorMode();
|
||||
}
|
||||
|
||||
DrawRectangleLinesEx(scissorArea, 1, Color.Black);
|
||||
DrawText("Press S to toggle scissor test", 10, 10, 20, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - scissor test");
|
||||
|
||||
Rectangle scissorArea = new(0, 0, 300, 300);
|
||||
bool scissorMode = true;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ScissorTest();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.S))
|
||||
{
|
||||
scissorMode = !scissorMode;
|
||||
}
|
||||
|
||||
// Centre the scissor area around the mouse position
|
||||
scissorArea.X = GetMouseX() - scissorArea.Width / 2;
|
||||
scissorArea.Y = GetMouseY() - scissorArea.Height / 2;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (scissorMode)
|
||||
{
|
||||
BeginScissorMode((int)scissorArea.X, (int)scissorArea.Y, (int)scissorArea.Width, (int)scissorArea.Height);
|
||||
}
|
||||
|
||||
// Draw full screen rectangle and some text
|
||||
// NOTE: Only part defined by scissor area will be rendered
|
||||
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Red);
|
||||
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
if (scissorMode)
|
||||
{
|
||||
EndScissorMode();
|
||||
}
|
||||
|
||||
DrawRectangleLinesEx(scissorArea, 1, Color.Black);
|
||||
DrawText("Press S to toggle scissor test", 10, 10, 20, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
382
Examples/Core/ScreenRecording.cs
Normal file
382
Examples/Core/ScreenRecording.cs
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - screen recording
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
// NOTE: The upstream C example records frames into an animated GIF using the bundled msf_gif.h
|
||||
// single-header library. raylib-cs does not bind msf_gif, so this port replaces it with a small,
|
||||
// self-contained GIF89a encoder (GifRecorder, below) that uses a fixed 3-3-2 RGB palette. The
|
||||
// rest of the example (rendering, CTRL+R toggle, saving to <appdir>/screenrecording.gif) mirrors
|
||||
// upstream. Frame capture via LoadImageFromScreen() is slow and can cause stuttering, as noted
|
||||
// upstream.
|
||||
[ExcludeFromBrowser("desktop screen capture + gif file export, no web equivalent")]
|
||||
public partial class ScreenRecording : IExample
|
||||
{
|
||||
private const int GIF_RECORD_FRAMERATE = 5; // Record framerate, we get a frame every N frames
|
||||
|
||||
private const int MAX_SINEWAVE_POINTS = 256;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Screen Recording";
|
||||
|
||||
public string Title => "raylib [core] example - screen recording";
|
||||
|
||||
private bool gifRecording; // GIF recording state
|
||||
private uint gifFrameCounter; // GIF frames counter
|
||||
private GifRecorder gifState; // GIF context state
|
||||
|
||||
private Vector2 circlePosition;
|
||||
private float timeCounter;
|
||||
|
||||
private Vector2[] sinePoints;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
gifRecording = false;
|
||||
gifFrameCounter = 0;
|
||||
gifState = new GifRecorder();
|
||||
|
||||
circlePosition = new Vector2(0.0f, screenHeight / 2.0f);
|
||||
timeCounter = 0.0f;
|
||||
|
||||
// Get sine wave points for line drawing
|
||||
sinePoints = new Vector2[MAX_SINEWAVE_POINTS];
|
||||
for (int i = 0; i < MAX_SINEWAVE_POINTS; i++)
|
||||
{
|
||||
sinePoints[i].X = i * GetScreenWidth() / 180.0f;
|
||||
sinePoints[i].Y = screenHeight / 2.0f + 150 * MathF.Sin((2 * MathF.PI / 1.5f) * (1.0f / 60.0f) * (float)i); // Calculate for 60 fps
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Update circle sinusoidal movement
|
||||
timeCounter += GetFrameTime();
|
||||
circlePosition.X += GetScreenWidth() / 180.0f;
|
||||
circlePosition.Y = screenHeight / 2.0f + 150 * MathF.Sin((2 * MathF.PI / 1.5f) * timeCounter);
|
||||
if (circlePosition.X > screenWidth)
|
||||
{
|
||||
circlePosition.X = 0.0f;
|
||||
circlePosition.Y = screenHeight / 2.0f;
|
||||
timeCounter = 0.0f;
|
||||
}
|
||||
|
||||
// Start-Stop GIF recording on CTRL+R
|
||||
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
if (gifRecording)
|
||||
{
|
||||
// Stop current recording and save file
|
||||
gifRecording = false;
|
||||
byte[] result = gifState.End();
|
||||
SaveFileData(result, $"{GetApplicationDirectoryString()}/screenrecording.gif");
|
||||
|
||||
TraceLog(TraceLogLevel.Info, "Finish animated GIF recording");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start a new recording
|
||||
gifRecording = true;
|
||||
gifFrameCounter = 0;
|
||||
gifState.Begin(GetRenderWidth(), GetRenderHeight());
|
||||
|
||||
TraceLog(TraceLogLevel.Info, "Start animated GIF recording");
|
||||
}
|
||||
}
|
||||
|
||||
if (gifRecording)
|
||||
{
|
||||
gifFrameCounter++;
|
||||
|
||||
// NOTE: We record one gif frame depending on the desired gif framerate
|
||||
if (gifFrameCounter > GIF_RECORD_FRAMERATE)
|
||||
{
|
||||
// Get image data for the current frame (from backbuffer)
|
||||
// WARNING: This process is quite slow, it can generate stuttering
|
||||
Image imScreen = LoadImageFromScreen();
|
||||
|
||||
// Add the frame to the gif recording, providing and "estimated" time for display in centiseconds
|
||||
int delayCs = (int)((1.0f / 60.0f) * GIF_RECORD_FRAMERATE) / 10;
|
||||
gifState.AddFrame((byte*)imScreen.Data, imScreen.Width, imScreen.Height, imScreen.Width * 4, delayCs);
|
||||
gifFrameCounter = 0;
|
||||
|
||||
UnloadImage(imScreen); // Free image data
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = 0; i < (MAX_SINEWAVE_POINTS - 1); i++)
|
||||
{
|
||||
DrawLineV(sinePoints[i], sinePoints[i + 1], Color.Maroon);
|
||||
DrawCircleV(sinePoints[i], 3, Color.Maroon);
|
||||
}
|
||||
|
||||
DrawCircleV(circlePosition, 30, Color.Red);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
/*
|
||||
// Draw record indicator
|
||||
// WARNING: If drawn here, it will appear in the recorded image,
|
||||
// use a render texture instead for the recording and LoadImageFromTexture(rt.texture)
|
||||
if (gifRecording)
|
||||
{
|
||||
// Display the recording indicator every half-second
|
||||
if ((int)(GetTime()/0.5)%2 == 1)
|
||||
{
|
||||
DrawCircle(30, GetScreenHeight() - 20, 10, Color.Maroon);
|
||||
DrawText("GIF RECORDING", 50, GetScreenHeight() - 25, 10, Color.Red);
|
||||
}
|
||||
}
|
||||
*/
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// If still recording a GIF on close window, just finish
|
||||
if (gifRecording)
|
||||
{
|
||||
gifState.End();
|
||||
gifRecording = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - screen recording");
|
||||
|
||||
var game = new ScreenRecording();
|
||||
game.Init();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Minimal self-contained animated GIF89a encoder (replacement for msf_gif.h)
|
||||
// Uses a fixed 3-3-2 RGB global palette and standard GIF-variant LZW compression.
|
||||
private class GifRecorder
|
||||
{
|
||||
private List<byte> output;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
// LZW bit-packing state (per-frame)
|
||||
private int bitBuffer;
|
||||
private int bitCount;
|
||||
private List<byte> subBlock;
|
||||
|
||||
public void Begin(int w, int h)
|
||||
{
|
||||
width = w;
|
||||
height = h;
|
||||
output = new List<byte>();
|
||||
|
||||
// Header
|
||||
output.AddRange(new byte[] { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' });
|
||||
|
||||
// Logical Screen Descriptor
|
||||
WriteU16(width);
|
||||
WriteU16(height);
|
||||
output.Add(0xF7); // Global color table present, 8-bit color res, 256-entry table
|
||||
output.Add(0x00); // Background color index
|
||||
output.Add(0x00); // Pixel aspect ratio
|
||||
|
||||
// Global Color Table: 256 entries, 3-3-2 RGB
|
||||
for (int k = 0; k < 256; k++)
|
||||
{
|
||||
int r3 = (k >> 5) & 0x7;
|
||||
int g3 = (k >> 2) & 0x7;
|
||||
int b2 = k & 0x3;
|
||||
output.Add((byte)((r3 << 5) | (r3 << 2) | (r3 >> 1)));
|
||||
output.Add((byte)((g3 << 5) | (g3 << 2) | (g3 >> 1)));
|
||||
output.Add((byte)((b2 << 6) | (b2 << 4) | (b2 << 2) | b2));
|
||||
}
|
||||
|
||||
// NETSCAPE2.0 application extension (loop forever)
|
||||
output.Add(0x21);
|
||||
output.Add(0xFF);
|
||||
output.Add(0x0B);
|
||||
output.AddRange(new byte[] { (byte)'N', (byte)'E', (byte)'T', (byte)'S', (byte)'C', (byte)'A', (byte)'P', (byte)'E', (byte)'2', (byte)'.', (byte)'0' });
|
||||
output.Add(0x03);
|
||||
output.Add(0x01);
|
||||
WriteU16(0); // Loop count (0 = forever)
|
||||
output.Add(0x00);
|
||||
}
|
||||
|
||||
public unsafe void AddFrame(byte* data, int w, int h, int stride, int delayCs)
|
||||
{
|
||||
if (output == null) return;
|
||||
|
||||
// Graphic Control Extension
|
||||
output.Add(0x21);
|
||||
output.Add(0xF9);
|
||||
output.Add(0x04);
|
||||
output.Add(0x00); // No transparency, disposal method 0
|
||||
WriteU16(delayCs);
|
||||
output.Add(0x00); // Transparent color index
|
||||
output.Add(0x00); // Block terminator
|
||||
|
||||
// Image Descriptor
|
||||
output.Add(0x2C);
|
||||
WriteU16(0); // Left
|
||||
WriteU16(0); // Top
|
||||
WriteU16(w);
|
||||
WriteU16(h);
|
||||
output.Add(0x00); // No local color table, not interlaced
|
||||
|
||||
// Map pixels to palette indices (3-3-2)
|
||||
byte[] indices = new byte[w * h];
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
int row = y * stride;
|
||||
int dst = y * w;
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
byte r = data[row + x * 4 + 0];
|
||||
byte g = data[row + x * 4 + 1];
|
||||
byte b = data[row + x * 4 + 2];
|
||||
indices[dst + x] = (byte)((r & 0xE0) | ((g & 0xE0) >> 3) | (b >> 6));
|
||||
}
|
||||
}
|
||||
|
||||
// LZW image data
|
||||
const int minCodeSize = 8;
|
||||
output.Add((byte)minCodeSize);
|
||||
|
||||
bitBuffer = 0;
|
||||
bitCount = 0;
|
||||
subBlock = new List<byte>();
|
||||
|
||||
int clearCode = 1 << minCodeSize; // 256
|
||||
int stopCode = clearCode + 1; // 257
|
||||
int keySize = minCodeSize + 1; // 9
|
||||
int nkeys = clearCode + 2; // 258
|
||||
var dict = new Dictionary<int, int>();
|
||||
|
||||
WriteBits(clearCode, keySize);
|
||||
|
||||
int key = indices[0];
|
||||
for (int i = 1; i < indices.Length; i++)
|
||||
{
|
||||
int p = indices[i];
|
||||
int combined = (key << 8) | p;
|
||||
if (dict.TryGetValue(combined, out int existing))
|
||||
{
|
||||
key = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBits(key, keySize);
|
||||
dict[combined] = nkeys;
|
||||
nkeys++;
|
||||
if (nkeys == (1 << keySize))
|
||||
{
|
||||
if (keySize < 12) keySize++;
|
||||
}
|
||||
if (nkeys == 0x1000)
|
||||
{
|
||||
WriteBits(clearCode, keySize);
|
||||
dict.Clear();
|
||||
keySize = minCodeSize + 1;
|
||||
nkeys = clearCode + 2;
|
||||
}
|
||||
key = p;
|
||||
}
|
||||
}
|
||||
|
||||
WriteBits(key, keySize);
|
||||
WriteBits(stopCode, keySize);
|
||||
|
||||
// Flush remaining bits
|
||||
if (bitCount > 0)
|
||||
{
|
||||
subBlock.Add((byte)(bitBuffer & 0xFF));
|
||||
bitBuffer = 0;
|
||||
bitCount = 0;
|
||||
}
|
||||
if (subBlock.Count > 0) FlushSubBlock();
|
||||
output.Add(0x00); // Image data block terminator
|
||||
}
|
||||
|
||||
public byte[] End()
|
||||
{
|
||||
if (output == null) return Array.Empty<byte>();
|
||||
output.Add(0x3B); // Trailer
|
||||
byte[] result = output.ToArray();
|
||||
output = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void WriteBits(int code, int len)
|
||||
{
|
||||
bitBuffer |= code << bitCount;
|
||||
bitCount += len;
|
||||
while (bitCount >= 8)
|
||||
{
|
||||
subBlock.Add((byte)(bitBuffer & 0xFF));
|
||||
bitBuffer >>= 8;
|
||||
bitCount -= 8;
|
||||
if (subBlock.Count == 255) FlushSubBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void FlushSubBlock()
|
||||
{
|
||||
output.Add((byte)subBlock.Count);
|
||||
output.AddRange(subBlock);
|
||||
subBlock.Clear();
|
||||
}
|
||||
|
||||
private void WriteU16(int value)
|
||||
{
|
||||
output.Add((byte)(value & 0xFF));
|
||||
output.Add((byte)((value >> 8) & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,18 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - smooth pixel-perfect camera
|
||||
* raylib [core] example - smooth pixelperfect
|
||||
*
|
||||
* This example has been created using raylib 3.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 3.7, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Giancamillo Alessandroni (@NotManyIdeasDev) and
|
||||
* reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Giancamillo Alessandroni (@NotManyIdeasDev) 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) 2021-2025 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -18,117 +22,193 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public static class SmoothPixelPerfect
|
||||
public partial class SmoothPixelPerfect : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int virtualScreenWidth = 160;
|
||||
private const int virtualScreenHeight = 90;
|
||||
|
||||
private const float virtualRatio = (float)screenWidth / (float)virtualScreenWidth;
|
||||
|
||||
public string Name => "Core / Smooth Pixelperfect";
|
||||
|
||||
public string Title => "raylib [core] example - smooth pixelperfect";
|
||||
|
||||
private Camera2D worldSpaceCamera; // Game world camera
|
||||
private Camera2D screenSpaceCamera; // Smoothing camera
|
||||
private RenderTexture2D target;
|
||||
|
||||
private Rectangle rec01;
|
||||
private Rectangle rec02;
|
||||
private Rectangle rec03;
|
||||
|
||||
private Rectangle sourceRec;
|
||||
private Rectangle destRec;
|
||||
|
||||
private Vector2 origin;
|
||||
private float rotation;
|
||||
private float cameraX;
|
||||
private float cameraY;
|
||||
private bool smoothOn;
|
||||
private bool overscan;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
const int virtualScreenWidth = 160;
|
||||
const int virtualScreenHeight = 90;
|
||||
|
||||
const float virtualRatio = (float)screenWidth / (float)virtualScreenWidth;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixel-perfect camera");
|
||||
|
||||
// Game world camera
|
||||
Camera2D worldSpaceCamera = new();
|
||||
worldSpaceCamera = new(); // Game world camera
|
||||
worldSpaceCamera.Zoom = 1.0f;
|
||||
|
||||
// Smoothing camera
|
||||
Camera2D screenSpaceCamera = new();
|
||||
screenSpaceCamera = new(); // Smoothing camera
|
||||
screenSpaceCamera.Zoom = 1.0f;
|
||||
|
||||
// This is where we'll draw all our objects.
|
||||
RenderTexture2D target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight);
|
||||
// Load render texture to draw all our objects
|
||||
target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight);
|
||||
|
||||
Rectangle rec01 = new(70.0f, 35.0f, 20.0f, 20.0f);
|
||||
Rectangle rec02 = new(90.0f, 55.0f, 30.0f, 10.0f);
|
||||
Rectangle rec03 = new(80.0f, 65.0f, 15.0f, 25.0f);
|
||||
rec01 = new(70.0f, 35.0f, 20.0f, 20.0f);
|
||||
rec02 = new(90.0f, 55.0f, 30.0f, 10.0f);
|
||||
rec03 = new(80.0f, 65.0f, 15.0f, 25.0f);
|
||||
|
||||
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
|
||||
Rectangle sourceRec = new(
|
||||
sourceRec = new(
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)target.Texture.Width,
|
||||
-(float)target.Texture.Height
|
||||
);
|
||||
Rectangle destRec = new(
|
||||
-virtualRatio,
|
||||
-virtualRatio,
|
||||
screenWidth + (virtualRatio * 2),
|
||||
screenHeight + (virtualRatio * 2)
|
||||
destRec = new(
|
||||
(screenWidth - screenWidth / 1.25f) / 2.0f,
|
||||
(screenHeight - screenHeight / 1.25f) / 2.0f,
|
||||
screenWidth / 1.25f,
|
||||
screenHeight / 1.25f
|
||||
);
|
||||
|
||||
Vector2 origin = new(0.0f, 0.0f);
|
||||
origin = new(0.0f, 0.0f);
|
||||
|
||||
float rotation = 0.0f;
|
||||
rotation = 0.0f;
|
||||
|
||||
float cameraX = 0.0f;
|
||||
float cameraY = 0.0f;
|
||||
cameraX = 0.0f;
|
||||
cameraY = 0.0f;
|
||||
|
||||
smoothOn = true;
|
||||
overscan = false;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation += 60.0f * GetFrameTime(); // Rotate the rectangles, 60 degrees per second
|
||||
|
||||
// Make the camera move to demonstrate the effect
|
||||
cameraX = (MathF.Sin((float)GetTime()) * 50.0f) - 10.0f;
|
||||
cameraY = MathF.Cos((float)GetTime()) * 30.0f;
|
||||
|
||||
// Set the camera's target to the values computed above
|
||||
screenSpaceCamera.Target = new Vector2(cameraX, cameraY);
|
||||
|
||||
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
|
||||
worldSpaceCamera.Target.X = MathF.Truncate(screenSpaceCamera.Target.X);
|
||||
screenSpaceCamera.Target.X -= worldSpaceCamera.Target.X;
|
||||
screenSpaceCamera.Target.X *= virtualRatio;
|
||||
|
||||
worldSpaceCamera.Target.Y = MathF.Truncate(screenSpaceCamera.Target.Y);
|
||||
screenSpaceCamera.Target.Y -= worldSpaceCamera.Target.Y;
|
||||
screenSpaceCamera.Target.Y *= virtualRatio;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.S))
|
||||
{
|
||||
smoothOn = !smoothOn;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.O))
|
||||
{
|
||||
overscan = !overscan;
|
||||
}
|
||||
|
||||
if (overscan)
|
||||
{
|
||||
destRec = new Rectangle(
|
||||
-virtualRatio,
|
||||
-virtualRatio,
|
||||
screenWidth + (virtualRatio * 2),
|
||||
screenHeight + (virtualRatio * 2)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
destRec = new Rectangle(
|
||||
(screenWidth - screenWidth / 1.25f) / 2.0f,
|
||||
(screenHeight - screenHeight / 1.25f) / 2.0f,
|
||||
screenWidth / 1.25f,
|
||||
screenHeight / 1.25f
|
||||
);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(worldSpaceCamera);
|
||||
DrawRectanglePro(rec01, origin, rotation, Color.Black);
|
||||
DrawRectanglePro(rec02, origin, -rotation, Color.Red);
|
||||
DrawRectanglePro(rec03, origin, rotation + 45.0f, Color.Blue);
|
||||
EndMode2D();
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
if (smoothOn)
|
||||
{
|
||||
BeginMode2D(screenSpaceCamera);
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
|
||||
EndMode2D();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
|
||||
}
|
||||
|
||||
DrawText($"Screen resolution: {screenWidth}x{screenHeight}", 10, 10, 20, Color.DarkBlue);
|
||||
DrawText($"World resolution: {virtualScreenWidth}x{virtualScreenHeight}", 10, 40, 20, Color.DarkGreen);
|
||||
DrawText($"Smooth: {(smoothOn ? "ON" : "OFF")}", 10, screenHeight - 60, 20, Color.Red);
|
||||
DrawText($"Overscan: {(overscan ? "ON" : "OFF")}", 10, screenHeight - 30, 20, Color.Red);
|
||||
DrawFPS(GetScreenWidth() - 95, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixelperfect");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SmoothPixelPerfect();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation += 60.0f * GetFrameTime(); // Rotate the rectangles, 60 degrees per second
|
||||
|
||||
// Make the camera move to demonstrate the effect
|
||||
cameraX = (MathF.Sin((float)GetTime()) * 50.0f) - 10.0f;
|
||||
cameraY = MathF.Cos((float)GetTime()) * 30.0f;
|
||||
|
||||
// Set the camera's target to the values computed above
|
||||
screenSpaceCamera.Target = new Vector2(cameraX, cameraY);
|
||||
|
||||
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
|
||||
worldSpaceCamera.Target.X = (int)screenSpaceCamera.Target.X;
|
||||
screenSpaceCamera.Target.X -= worldSpaceCamera.Target.X;
|
||||
screenSpaceCamera.Target.X *= virtualRatio;
|
||||
|
||||
worldSpaceCamera.Target.Y = (int)screenSpaceCamera.Target.Y;
|
||||
screenSpaceCamera.Target.Y -= worldSpaceCamera.Target.Y;
|
||||
screenSpaceCamera.Target.Y *= virtualRatio;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(worldSpaceCamera);
|
||||
DrawRectanglePro(rec01, origin, rotation, Color.Black);
|
||||
DrawRectanglePro(rec02, origin, -rotation, Color.Red);
|
||||
DrawRectanglePro(rec03, origin, rotation + 45.0f, Color.Blue);
|
||||
EndMode2D();
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Red);
|
||||
|
||||
BeginMode2D(screenSpaceCamera);
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
|
||||
EndMode2D();
|
||||
|
||||
DrawText($"Screen resolution: {screenWidth}x{screenHeight}", 10, 10, 20, Color.DarkBlue);
|
||||
DrawText($"World resolution: {virtualScreenWidth}x{virtualScreenHeight}", 10, 40, 20, Color.DarkGreen);
|
||||
DrawFPS(GetScreenWidth() - 95, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - split screen
|
||||
* raylib [core] example - 3d camera split screen
|
||||
*
|
||||
* This example has been created using raylib 3.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 3.7, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Jeffery Myers (@JeffM2501) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2021 Jeffery Myers (@JeffM2501)
|
||||
* 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) 2021-2025 Jeffery Myers (@JeffM2501)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,25 +20,34 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public unsafe class SplitScreen
|
||||
public partial class SplitScreen : IExample
|
||||
{
|
||||
static Texture2D TextureGrid;
|
||||
static Camera3D CameraPlayer1;
|
||||
static Camera3D CameraPlayer2;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private Camera3D CameraPlayer1;
|
||||
private Camera3D CameraPlayer2;
|
||||
|
||||
private RenderTexture2D screenPlayer1;
|
||||
private RenderTexture2D screenPlayer2;
|
||||
private Rectangle splitScreenRect;
|
||||
|
||||
public string Name => "Core / Split Screen";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera split screen";
|
||||
|
||||
// Scene drawing
|
||||
static void DrawScene()
|
||||
private void DrawScene()
|
||||
{
|
||||
int count = 5;
|
||||
var count = 5;
|
||||
float spacing = 4;
|
||||
|
||||
// Grid of cube trees on a plane to make a "world"
|
||||
// Simple world plane
|
||||
DrawPlane(new Vector3(0, 0, 0), new Vector2(50, 50), Color.Beige);
|
||||
// Draw scene: grid of cube trees on a plane to make a "world"
|
||||
DrawPlane(new Vector3(0, 0, 0), new Vector2(50, 50), Color.Beige); // Simple world plane
|
||||
|
||||
for (float x = -count * spacing; x <= count * spacing; x += spacing)
|
||||
for (var x = -count * spacing; x <= count * spacing; x += spacing)
|
||||
{
|
||||
for (float z = -count * spacing; z <= count * spacing; z += spacing)
|
||||
for (var z = -count * spacing; z <= count * spacing; z += spacing)
|
||||
{
|
||||
DrawCube(new Vector3(x, 1.5f, z), 1, 1, 1, Color.Lime);
|
||||
DrawCube(new Vector3(x, 0.5f, z), 0.25f, 1, 0.25f, Color.Brown);
|
||||
|
|
@ -46,22 +59,8 @@ public unsafe class SplitScreen
|
|||
DrawCube(CameraPlayer2.Position, 1, 1, 1, Color.Blue);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - split screen");
|
||||
|
||||
// Generate a simple texture to use for trees
|
||||
Image img = GenImageChecked(256, 256, 32, 32, Color.DarkGray, Color.White);
|
||||
TextureGrid = LoadTextureFromImage(img);
|
||||
UnloadImage(img);
|
||||
SetTextureFilter(TextureGrid, TextureFilter.Anisotropic16X);
|
||||
SetTextureWrap(TextureGrid, TextureWrap.Clamp);
|
||||
|
||||
// Setup player 1 camera and screen
|
||||
CameraPlayer1.FovY = 45.0f;
|
||||
CameraPlayer1.Up.Y = 1.0f;
|
||||
|
|
@ -69,7 +68,7 @@ public unsafe class SplitScreen
|
|||
CameraPlayer1.Position.Z = -3.0f;
|
||||
CameraPlayer1.Position.Y = 1.0f;
|
||||
|
||||
RenderTexture2D screenPlayer1 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
screenPlayer1 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
|
||||
// Setup player two camera and screen
|
||||
CameraPlayer2.FovY = 45.0f;
|
||||
|
|
@ -78,97 +77,119 @@ public unsafe class SplitScreen
|
|||
CameraPlayer2.Position.X = -3.0f;
|
||||
CameraPlayer2.Position.Y = 3.0f;
|
||||
|
||||
RenderTexture2D screenPlayer2 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
screenPlayer2 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
|
||||
// Build a flipped rectangle the size of the split view to use for drawing later
|
||||
Rectangle splitScreenRect = new(
|
||||
splitScreenRect = new(
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)screenPlayer1.Texture.Width,
|
||||
(float)-screenPlayer1.Texture.Height
|
||||
);
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// If anyone moves this frame, how far will they move based on the time since the last frame
|
||||
// this moves things at 10 world units per second, regardless of the actual FPS
|
||||
var offsetThisFrame = 10.0f * GetFrameTime();
|
||||
|
||||
// Move Player1 forward and backwards (no turning)
|
||||
if (IsKeyDown(KeyboardKey.W))
|
||||
{
|
||||
CameraPlayer1.Position.Z += offsetThisFrame;
|
||||
CameraPlayer1.Target.Z += offsetThisFrame;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
CameraPlayer1.Position.Z -= offsetThisFrame;
|
||||
CameraPlayer1.Target.Z -= offsetThisFrame;
|
||||
}
|
||||
|
||||
// Move Player2 forward and backwards (no turning)
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
CameraPlayer2.Position.X += offsetThisFrame;
|
||||
CameraPlayer2.Target.X += offsetThisFrame;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
CameraPlayer2.Position.X -= offsetThisFrame;
|
||||
CameraPlayer2.Target.X -= offsetThisFrame;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw Player1 view to the render texture
|
||||
BeginTextureMode(screenPlayer1);
|
||||
ClearBackground(Color.SkyBlue);
|
||||
|
||||
BeginMode3D(CameraPlayer1);
|
||||
DrawScene();
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(0, 0, GetScreenWidth() / 2, 40, Fade(Color.RayWhite, 0.8f));
|
||||
DrawText("PLAYER1: W/S to move", 10, 10, 20, Color.Maroon);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw Player2 view to the render texture
|
||||
BeginTextureMode(screenPlayer2);
|
||||
ClearBackground(Color.SkyBlue);
|
||||
|
||||
BeginMode3D(CameraPlayer2);
|
||||
DrawScene();
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(0, 0, GetScreenWidth() / 2, 40, Fade(Color.RayWhite, 0.8f));
|
||||
DrawText("PLAYER2: UP/DOWN to move", 10, 10, 20, Color.DarkBlue);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw both views render textures to the screen side by side
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
DrawTextureRec(screenPlayer1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
|
||||
DrawTextureRec(screenPlayer2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
|
||||
|
||||
DrawRectangle(GetScreenWidth() / 2 - 2, 0, 4, GetScreenHeight(), Color.LightGray);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(screenPlayer1); // Unload render texture
|
||||
UnloadRenderTexture(screenPlayer2); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera split screen");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SplitScreen();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// If anyone moves this frame, how far will they move based on the time since the last frame
|
||||
// this moves thigns at 10 world units per second, regardless of the actual FPS
|
||||
float offsetThisFrame = 10.0f * GetFrameTime();
|
||||
|
||||
// Move Player1 forward and backwards (no turning)
|
||||
if (IsKeyDown(KeyboardKey.W))
|
||||
{
|
||||
CameraPlayer1.Position.Z += offsetThisFrame;
|
||||
CameraPlayer1.Target.Z += offsetThisFrame;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
CameraPlayer1.Position.Z -= offsetThisFrame;
|
||||
CameraPlayer1.Target.Z -= offsetThisFrame;
|
||||
}
|
||||
|
||||
// Move Player2 forward and backwards (no turning)
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
CameraPlayer2.Position.X += offsetThisFrame;
|
||||
CameraPlayer2.Target.X += offsetThisFrame;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
CameraPlayer2.Position.X -= offsetThisFrame;
|
||||
CameraPlayer2.Target.X -= offsetThisFrame;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw Player1 view to the render texture
|
||||
BeginTextureMode(screenPlayer1);
|
||||
ClearBackground(Color.SkyBlue);
|
||||
|
||||
BeginMode3D(CameraPlayer1);
|
||||
DrawScene();
|
||||
EndMode3D();
|
||||
|
||||
DrawText("PLAYER 1 W/S to move", 10, 10, 20, Color.Red);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw Player2 view to the render texture
|
||||
BeginTextureMode(screenPlayer2);
|
||||
ClearBackground(Color.SkyBlue);
|
||||
|
||||
BeginMode3D(CameraPlayer2);
|
||||
DrawScene();
|
||||
EndMode3D();
|
||||
|
||||
DrawText("PLAYER 2 UP/DOWN to move", 10, 10, 20, Color.Blue);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw both views render textures to the screen side by side
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
DrawTextureRec(screenPlayer1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
|
||||
DrawTextureRec(screenPlayer2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
|
||||
|
||||
EndDrawing();
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTexture(screenPlayer1);
|
||||
UnloadRenderTexture(screenPlayer2);
|
||||
UnloadTexture(TextureGrid);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
204
Examples/Core/SplitScreen2D.cs
Normal file
204
Examples/Core/SplitScreen2D.cs
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - 2d camera split screen
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Addapted from the core_3d_camera_split_screen example:
|
||||
* https://github.com/raysan5/raylib/blob/master/examples/core/core_3d_camera_split_screen.c
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Gabriel dos Santos Sanches (@gabrielssanches) 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 Gabriel dos Santos Sanches (@gabrielssanches)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class SplitScreen2D : IExample
|
||||
{
|
||||
private const int PLAYER_SIZE = 40;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 440;
|
||||
|
||||
public string Name => "Core / 2D Camera Split Screen";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera split screen";
|
||||
|
||||
public int Width => screenWidth;
|
||||
|
||||
public int Height => screenHeight;
|
||||
|
||||
private Rectangle player1;
|
||||
private Rectangle player2;
|
||||
private Camera2D camera1;
|
||||
private Camera2D camera2;
|
||||
private RenderTexture2D screenCamera1;
|
||||
private RenderTexture2D screenCamera2;
|
||||
private Rectangle splitScreenRect;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
player1 = new Rectangle(200, 200, PLAYER_SIZE, PLAYER_SIZE);
|
||||
player2 = new Rectangle(250, 200, PLAYER_SIZE, PLAYER_SIZE);
|
||||
|
||||
camera1 = new Camera2D();
|
||||
camera1.Target = new Vector2(player1.X, player1.Y);
|
||||
camera1.Offset = new Vector2(200.0f, 200.0f);
|
||||
camera1.Rotation = 0.0f;
|
||||
camera1.Zoom = 1.0f;
|
||||
|
||||
camera2 = new Camera2D();
|
||||
camera2.Target = new Vector2(player2.X, player2.Y);
|
||||
camera2.Offset = new Vector2(200.0f, 200.0f);
|
||||
camera2.Rotation = 0.0f;
|
||||
camera2.Zoom = 1.0f;
|
||||
|
||||
screenCamera1 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
screenCamera2 = LoadRenderTexture(screenWidth / 2, screenHeight);
|
||||
|
||||
// Build a flipped rectangle the size of the split view to use for drawing later
|
||||
splitScreenRect = new Rectangle(0.0f, 0.0f, (float)screenCamera1.Texture.Width, (float)-screenCamera1.Texture.Height);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.S)) player1.Y += 3.0f;
|
||||
else if (IsKeyDown(KeyboardKey.W)) player1.Y -= 3.0f;
|
||||
if (IsKeyDown(KeyboardKey.D)) player1.X += 3.0f;
|
||||
else if (IsKeyDown(KeyboardKey.A)) player1.X -= 3.0f;
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up)) player2.Y -= 3.0f;
|
||||
else if (IsKeyDown(KeyboardKey.Down)) player2.Y += 3.0f;
|
||||
if (IsKeyDown(KeyboardKey.Right)) player2.X += 3.0f;
|
||||
else if (IsKeyDown(KeyboardKey.Left)) player2.X -= 3.0f;
|
||||
|
||||
camera1.Target = new Vector2(player1.X, player1.Y);
|
||||
camera2.Target = new Vector2(player2.X, player2.Y);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(screenCamera1);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera1);
|
||||
|
||||
// Draw full scene with first camera
|
||||
for (int i = 0; i < screenWidth / PLAYER_SIZE + 1; i++)
|
||||
{
|
||||
DrawLineV(new Vector2((float)PLAYER_SIZE * i, 0), new Vector2((float)PLAYER_SIZE * i, (float)screenHeight), Color.LightGray);
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenHeight / PLAYER_SIZE + 1; i++)
|
||||
{
|
||||
DrawLineV(new Vector2(0, (float)PLAYER_SIZE * i), new Vector2((float)screenWidth, (float)PLAYER_SIZE * i), Color.LightGray);
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenWidth / PLAYER_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < screenHeight / PLAYER_SIZE; j++)
|
||||
{
|
||||
DrawText($"[{i},{j}]", 10 + PLAYER_SIZE * i, 15 + PLAYER_SIZE * j, 10, Color.LightGray);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleRec(player1, Color.Red);
|
||||
DrawRectangleRec(player2, Color.Blue);
|
||||
EndMode2D();
|
||||
|
||||
DrawRectangle(0, 0, GetScreenWidth() / 2, 30, Fade(Color.RayWhite, 0.6f));
|
||||
DrawText("PLAYER1: W/S/A/D to move", 10, 10, 10, Color.Maroon);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
BeginTextureMode(screenCamera2);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera2);
|
||||
|
||||
// Draw full scene with second camera
|
||||
for (int i = 0; i < screenWidth / PLAYER_SIZE + 1; i++)
|
||||
{
|
||||
DrawLineV(new Vector2((float)PLAYER_SIZE * i, 0), new Vector2((float)PLAYER_SIZE * i, (float)screenHeight), Color.LightGray);
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenHeight / PLAYER_SIZE + 1; i++)
|
||||
{
|
||||
DrawLineV(new Vector2(0, (float)PLAYER_SIZE * i), new Vector2((float)screenWidth, (float)PLAYER_SIZE * i), Color.LightGray);
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenWidth / PLAYER_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < screenHeight / PLAYER_SIZE; j++)
|
||||
{
|
||||
DrawText($"[{i},{j}]", 10 + PLAYER_SIZE * i, 15 + PLAYER_SIZE * j, 10, Color.LightGray);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleRec(player1, Color.Red);
|
||||
DrawRectangleRec(player2, Color.Blue);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawRectangle(0, 0, GetScreenWidth() / 2, 30, Fade(Color.RayWhite, 0.6f));
|
||||
DrawText("PLAYER2: UP/DOWN/LEFT/RIGHT to move", 10, 10, 10, Color.DarkBlue);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Draw both views render textures to the screen side by side
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
DrawTextureRec(screenCamera1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
|
||||
DrawTextureRec(screenCamera2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
|
||||
|
||||
DrawRectangle(GetScreenWidth() / 2 - 2, 0, 4, GetScreenHeight(), Color.LightGray);
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(screenCamera1); // Unload render texture
|
||||
UnloadRenderTexture(screenCamera2); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera split screen");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SplitScreen2D();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Storage save/load values
|
||||
* raylib [core] example - storage values
|
||||
*
|
||||
* 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) 2015 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -13,79 +17,104 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class StorageValues
|
||||
public partial class StorageValues : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
private const string storageDataFile = "storage.data";
|
||||
|
||||
// NOTE: Storage positions must start with 0, directly related to file memory layout
|
||||
enum StorageData
|
||||
private enum StorageData
|
||||
{
|
||||
Score,
|
||||
HiScore
|
||||
}
|
||||
|
||||
public string Name => "Core / Storage Values";
|
||||
|
||||
public string Title => "raylib [core] example - storage values";
|
||||
|
||||
private int score = 0;
|
||||
private int hiscore = 0;
|
||||
private int framesCounter = 0;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
score = 0;
|
||||
hiscore = 0;
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
score = GetRandomValue(1000, 2000);
|
||||
hiscore = GetRandomValue(2000, 4000);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
SaveStorageValue(storageDataFile, (int)StorageData.Score, score);
|
||||
SaveStorageValue(storageDataFile, (int)StorageData.HiScore, hiscore);
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
// NOTE: If requested position could not be found, value 0 is returned
|
||||
score = LoadStorageValue(storageDataFile, (int)StorageData.Score);
|
||||
hiscore = LoadStorageValue(storageDataFile, (int)StorageData.HiScore);
|
||||
}
|
||||
|
||||
framesCounter++;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText($"SCORE: {score}", 280, 130, 40, Color.Maroon);
|
||||
DrawText($"HI-SCORE: {hiscore}", 210, 200, 50, Color.Black);
|
||||
|
||||
DrawText($"frames: {framesCounter}", 10, 10, 20, Color.Lime);
|
||||
|
||||
DrawText("Press R to generate random numbers", 220, 40, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to SAVE values", 250, 310, 20, Color.LightGray);
|
||||
DrawText("Press SPACE to LOAD values", 252, 350, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
const string storageDataFile = "storage.data";
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - storage values");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - storage save/load values");
|
||||
|
||||
int score = 0;
|
||||
int hiscore = 0;
|
||||
int framesCounter = 0;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StorageValues();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
score = GetRandomValue(1000, 2000);
|
||||
hiscore = GetRandomValue(2000, 4000);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
SaveStorageValue(storageDataFile, (int)StorageData.Score, score);
|
||||
SaveStorageValue(storageDataFile, (int)StorageData.HiScore, hiscore);
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
// NOTE: If requested position could not be found, value 0 is returned
|
||||
score = LoadStorageValue(storageDataFile, (int)StorageData.Score);
|
||||
hiscore = LoadStorageValue(storageDataFile, (int)StorageData.HiScore);
|
||||
}
|
||||
|
||||
framesCounter++;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText($"SCORE: {score}", 280, 130, 40, Color.Maroon);
|
||||
DrawText($"HI-SCORE: {hiscore}", 210, 200, 50, Color.Black);
|
||||
|
||||
DrawText($"frames: {framesCounter}", 10, 10, 20, Color.Lime);
|
||||
|
||||
DrawText("Press R to generate random numbers", 220, 40, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to SAVE values", 250, 310, 20, Color.LightGray);
|
||||
DrawText("Press SPACE to LOAD values", 252, 350, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
@ -97,11 +126,11 @@ public class StorageValues
|
|||
{
|
||||
using var fileNameBuffer = fileName.ToUtf8Buffer();
|
||||
|
||||
bool success = false;
|
||||
int dataSize = 0;
|
||||
int newDataSize = 0;
|
||||
var success = false;
|
||||
var dataSize = 0;
|
||||
var newDataSize = 0;
|
||||
|
||||
byte* fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
|
||||
var fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
|
||||
byte* newFileData = null;
|
||||
|
||||
if (fileData != null)
|
||||
|
|
@ -115,13 +144,13 @@ public class StorageValues
|
|||
if (newFileData != null)
|
||||
{
|
||||
// RL_REALLOC succeded
|
||||
int* dataPtr = (int*)newFileData;
|
||||
var dataPtr = (int*)newFileData;
|
||||
dataPtr[position] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// RL_REALLOC failed
|
||||
int positionInBytes = position * sizeof(int);
|
||||
var positionInBytes = position * sizeof(int);
|
||||
TraceLog(
|
||||
TraceLogLevel.Warning,
|
||||
@$"FILEIO: [{fileName}] Failed to realloc data ({dataSize}),
|
||||
|
|
@ -140,7 +169,7 @@ public class StorageValues
|
|||
newDataSize = dataSize;
|
||||
|
||||
// Replace value on selected position
|
||||
int* dataPtr = (int*)newFileData;
|
||||
var dataPtr = (int*)newFileData;
|
||||
dataPtr[position] = value;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +184,7 @@ public class StorageValues
|
|||
|
||||
dataSize = (position + 1) * sizeof(int);
|
||||
fileData = (byte*)MemAlloc((uint)dataSize);
|
||||
int* dataPtr = (int*)fileData;
|
||||
var dataPtr = (int*)fileData;
|
||||
dataPtr[position] = value;
|
||||
|
||||
success = SaveFileData(fileNameBuffer.AsPointer(), fileData, dataSize);
|
||||
|
|
@ -173,9 +202,9 @@ public class StorageValues
|
|||
{
|
||||
using var fileNameBuffer = fileName.ToUtf8Buffer();
|
||||
|
||||
int value = 0;
|
||||
int dataSize = 0;
|
||||
byte* fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
|
||||
var value = 0;
|
||||
var dataSize = 0;
|
||||
var fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
|
||||
|
||||
if (fileData != null)
|
||||
{
|
||||
|
|
@ -188,7 +217,7 @@ public class StorageValues
|
|||
}
|
||||
else
|
||||
{
|
||||
int* dataPtr = (int*)fileData;
|
||||
var dataPtr = (int*)fileData;
|
||||
value = dataPtr[position];
|
||||
}
|
||||
|
||||
|
|
|
|||
209
Examples/Core/TextFileLoading.cs
Normal file
209
Examples/Core/TextFileLoading.cs
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - text file loading
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed by Aanjishnu Bhattacharyya (@NimComPoo-04) 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) 0 Aanjishnu Bhattacharyya (@NimComPoo-04)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
// NOTE: The upstream C code mutates the raw char buffers returned by LoadTextLines() in place,
|
||||
// temporarily null-terminating to reuse MeasureText for word wrapping. This C# port keeps the
|
||||
// same algorithm but works on managed char arrays: LoadFileText + split on '\n' reproduces
|
||||
// raylib's LoadTextLines('\n') behaviour, and '\n' characters are inserted where lines wrap.
|
||||
public partial class TextFileLoading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Text File Loading";
|
||||
|
||||
public string Title => "raylib [core] example - text file loading";
|
||||
|
||||
private Camera2D cam;
|
||||
private string fileName;
|
||||
private string[] lines;
|
||||
private int lineCount;
|
||||
private int fontSize;
|
||||
private int textTop;
|
||||
private int wrapWidth;
|
||||
private int textHeight;
|
||||
private Rectangle scrollBar;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Setting up the camera
|
||||
cam = new Camera2D();
|
||||
cam.Offset = new Vector2(0, 0);
|
||||
cam.Target = new Vector2(0, 0);
|
||||
cam.Rotation = 0;
|
||||
cam.Zoom = 1;
|
||||
|
||||
// Loading text file from resources/text_file.txt
|
||||
fileName = "resources/text_file.txt";
|
||||
string text = LoadFileText(fileName);
|
||||
|
||||
// Loading all the text lines (raylib's LoadTextLines splits on '\n')
|
||||
lines = text.Split('\n');
|
||||
lineCount = lines.Length;
|
||||
|
||||
// Stylistic choises
|
||||
fontSize = 20;
|
||||
textTop = 25 + fontSize; // Top of the screen from where the text is rendered
|
||||
wrapWidth = screenWidth - 20;
|
||||
|
||||
// Wrap the lines as needed
|
||||
for (int i = 0; i < lineCount; i++)
|
||||
{
|
||||
char[] chars = lines[i].ToCharArray();
|
||||
int len = chars.Length;
|
||||
int j = 0;
|
||||
int lastSpace = 0; // Keeping track of last valid space to insert '\n'
|
||||
int lastWrapStart = 0; // Keeping track of the start of this wrapped line.
|
||||
|
||||
while (j <= len)
|
||||
{
|
||||
char cur = (j < len) ? chars[j] : '\0';
|
||||
if (cur == ' ' || cur == '\0')
|
||||
{
|
||||
// Making a C style string by "cutting" at the required location so that we can use MeasureText
|
||||
string sub = new string(chars, lastWrapStart, j - lastWrapStart);
|
||||
|
||||
// Checking if the text has crossed the wrapWidth, then going back and inserting a newline
|
||||
if (MeasureText(sub, fontSize) > wrapWidth)
|
||||
{
|
||||
chars[lastSpace] = '\n';
|
||||
|
||||
// Since we added a newline the place of wrap changed so we update our lastWrapStart
|
||||
lastWrapStart = lastSpace + 1;
|
||||
}
|
||||
|
||||
lastSpace = j; // Since we encountered a new space we update our last encountered space location
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
lines[i] = new string(chars);
|
||||
}
|
||||
|
||||
// Calculating the total height so that we can show a scrollbar
|
||||
textHeight = 0;
|
||||
|
||||
for (int i = 0; i < lineCount; i++)
|
||||
{
|
||||
Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
|
||||
textHeight += (int)size.Y + 10;
|
||||
}
|
||||
|
||||
// A simple scrollbar on the side to show how far we have read into the file
|
||||
scrollBar = new Rectangle(
|
||||
(float)screenWidth - 5,
|
||||
0,
|
||||
5,
|
||||
screenHeight * 100.0f / (textHeight - screenHeight)); // Scrollbar height is just a percentage
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float scroll = GetMouseWheelMove();
|
||||
cam.Target.Y -= scroll * fontSize * 1.5f; // Choosing an arbitrary speed for scroll
|
||||
|
||||
if (cam.Target.Y < 0) cam.Target.Y = 0; // Snapping to 0 if we go too far back
|
||||
|
||||
// Ensuring that the camera does not scroll past all text
|
||||
if (cam.Target.Y > textHeight - screenHeight + textTop)
|
||||
cam.Target.Y = (float)textHeight - screenHeight + textTop;
|
||||
|
||||
// Computing the position of the scrollBar depending on the percentage of text covered
|
||||
scrollBar.Y = Lerp((float)textTop, (float)screenHeight - scrollBar.Height, (float)(cam.Target.Y - textTop) / (textHeight - screenHeight));
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(cam);
|
||||
// Going through all the read lines
|
||||
for (int i = 0, t = textTop; i < lineCount; i++)
|
||||
{
|
||||
// Each time we go through and calculate the height of the text to move the cursor appropriately
|
||||
Vector2 size;
|
||||
if (lines[i] != "")
|
||||
{
|
||||
size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix for empty line in the text file
|
||||
size = MeasureTextEx(GetFontDefault(), " ", (float)fontSize, 2);
|
||||
}
|
||||
|
||||
DrawText(lines[i], 10, t, fontSize, Color.Red);
|
||||
|
||||
// Inserting extra space for real newlines,
|
||||
// wrapped lines are rendered closer together
|
||||
t += (int)size.Y + 10;
|
||||
}
|
||||
EndMode2D();
|
||||
|
||||
// Header displaying which file is being read currently
|
||||
DrawRectangle(0, 0, screenWidth, textTop - 10, Color.Beige);
|
||||
DrawText($"File: {fileName}", 10, 10, fontSize, Color.Maroon);
|
||||
|
||||
DrawRectangleRec(scrollBar, Color.Maroon);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - text file loading");
|
||||
|
||||
var game = new TextFileLoading();
|
||||
game.Init();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
333
Examples/Core/UndoRedo.cs
Normal file
333
Examples/Core/UndoRedo.cs
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - undo redo
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.6
|
||||
*
|
||||
* Example contributed 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 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class UndoRedo : IExample
|
||||
{
|
||||
private const int MAX_UNDO_STATES = 26; // Maximum undo states supported for the ring buffer
|
||||
|
||||
private const int GRID_CELL_SIZE = 24;
|
||||
private const int MAX_GRID_CELLS_X = 30;
|
||||
private const int MAX_GRID_CELLS_Y = 13;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Undo Redo";
|
||||
|
||||
public string Title => "raylib [core] example - undo redo";
|
||||
|
||||
// Point struct, like Vector2 but using int
|
||||
private struct Point
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
}
|
||||
|
||||
// Player state struct
|
||||
// NOTE: Contains all player data that needs to be affected by undo/redo
|
||||
private struct PlayerState
|
||||
{
|
||||
public Point Cell;
|
||||
public Color Color;
|
||||
}
|
||||
|
||||
// Undo/redo system variables
|
||||
private int currentUndoIndex;
|
||||
private int firstUndoIndex;
|
||||
private int lastUndoIndex;
|
||||
private int undoFrameCounter;
|
||||
private Vector2 undoInfoPos;
|
||||
|
||||
private PlayerState player;
|
||||
private PlayerState[] states;
|
||||
|
||||
// Grid variables
|
||||
private Vector2 gridPosition;
|
||||
|
||||
// Compare two player states (replaces memcmp)
|
||||
private static bool SameState(in PlayerState a, in PlayerState b)
|
||||
{
|
||||
return (a.Cell.X == b.Cell.X) && (a.Cell.Y == b.Cell.Y) &&
|
||||
(a.Color.R == b.Color.R) && (a.Color.G == b.Color.G) &&
|
||||
(a.Color.B == b.Color.B) && (a.Color.A == b.Color.A);
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
currentUndoIndex = 0;
|
||||
firstUndoIndex = 0;
|
||||
lastUndoIndex = 0;
|
||||
undoFrameCounter = 0;
|
||||
undoInfoPos = new Vector2(110, 400);
|
||||
|
||||
// Init current player state and undo/redo recorded states array
|
||||
player = new PlayerState();
|
||||
player.Cell = new Point { X = 10, Y = 10 };
|
||||
player.Color = Color.Red;
|
||||
|
||||
// Init undo buffer to store MAX_UNDO_STATES states
|
||||
states = new PlayerState[MAX_UNDO_STATES];
|
||||
// Init all undo states to current state
|
||||
for (int i = 0; i < MAX_UNDO_STATES; i++) states[i] = player;
|
||||
|
||||
// Grid variables
|
||||
gridPosition = new Vector2(40, 60);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Player movement logic
|
||||
if (IsKeyPressed(KeyboardKey.Right)) player.Cell.X++;
|
||||
else if (IsKeyPressed(KeyboardKey.Left)) player.Cell.X--;
|
||||
else if (IsKeyPressed(KeyboardKey.Up)) player.Cell.Y--;
|
||||
else if (IsKeyPressed(KeyboardKey.Down)) player.Cell.Y++;
|
||||
|
||||
// Make sure player does not go out of bounds
|
||||
if (player.Cell.X < 0) player.Cell.X = 0;
|
||||
else if (player.Cell.X >= MAX_GRID_CELLS_X) player.Cell.X = MAX_GRID_CELLS_X - 1;
|
||||
if (player.Cell.Y < 0) player.Cell.Y = 0;
|
||||
else if (player.Cell.Y >= MAX_GRID_CELLS_Y) player.Cell.Y = MAX_GRID_CELLS_Y - 1;
|
||||
|
||||
// Player color change logic
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
player.Color.R = (byte)GetRandomValue(20, 255);
|
||||
player.Color.G = (byte)GetRandomValue(20, 220);
|
||||
player.Color.B = (byte)GetRandomValue(20, 240);
|
||||
}
|
||||
|
||||
// Undo state change logic
|
||||
undoFrameCounter++;
|
||||
|
||||
// Waiting a number of frames before checking if we should store a new state snapshot
|
||||
if (undoFrameCounter >= 2) // Checking every 2 frames
|
||||
{
|
||||
if (!SameState(states[currentUndoIndex], player))
|
||||
{
|
||||
// Move cursor to next available position of the undo ring buffer to record state
|
||||
currentUndoIndex++;
|
||||
if (currentUndoIndex >= MAX_UNDO_STATES) currentUndoIndex = 0;
|
||||
if (currentUndoIndex == firstUndoIndex) firstUndoIndex++;
|
||||
if (firstUndoIndex >= MAX_UNDO_STATES) firstUndoIndex = 0;
|
||||
|
||||
states[currentUndoIndex] = player;
|
||||
lastUndoIndex = currentUndoIndex;
|
||||
}
|
||||
|
||||
undoFrameCounter = 0;
|
||||
}
|
||||
|
||||
// Recover previous state from buffer: CTRL+Z
|
||||
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
if (currentUndoIndex != firstUndoIndex)
|
||||
{
|
||||
currentUndoIndex--;
|
||||
if (currentUndoIndex < 0) currentUndoIndex = MAX_UNDO_STATES - 1;
|
||||
|
||||
if (!SameState(states[currentUndoIndex], player))
|
||||
{
|
||||
player = states[currentUndoIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recover next state from buffer: CTRL+Y
|
||||
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.Y))
|
||||
{
|
||||
if (currentUndoIndex != lastUndoIndex)
|
||||
{
|
||||
int nextUndoIndex = currentUndoIndex + 1;
|
||||
if (nextUndoIndex >= MAX_UNDO_STATES) nextUndoIndex = 0;
|
||||
|
||||
if (nextUndoIndex != firstUndoIndex)
|
||||
{
|
||||
currentUndoIndex = nextUndoIndex;
|
||||
|
||||
if (!SameState(states[currentUndoIndex], player))
|
||||
{
|
||||
player = states[currentUndoIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw controls info
|
||||
DrawText("[ARROWS] MOVE PLAYER - [SPACE] CHANGE PLAYER COLOR", 40, 20, 20, Color.DarkGray);
|
||||
|
||||
// Draw player visited cells recorded by undo
|
||||
// NOTE: Remember we are using a ring buffer approach so,
|
||||
// some cells info could start at the end of the array and end at the beginning
|
||||
if (lastUndoIndex > firstUndoIndex)
|
||||
{
|
||||
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
|
||||
DrawRectangleRec(new Rectangle(gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE, GRID_CELL_SIZE), Color.LightGray);
|
||||
}
|
||||
else if (firstUndoIndex > lastUndoIndex)
|
||||
{
|
||||
if ((currentUndoIndex < MAX_UNDO_STATES) && (currentUndoIndex > lastUndoIndex))
|
||||
{
|
||||
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
|
||||
DrawRectangleRec(new Rectangle(gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE, GRID_CELL_SIZE), Color.LightGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
|
||||
DrawRectangle((int)gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE, GRID_CELL_SIZE, Color.LightGray);
|
||||
for (int i = 0; i < currentUndoIndex; i++)
|
||||
DrawRectangle((int)gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE, GRID_CELL_SIZE, Color.LightGray);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game grid
|
||||
for (int y = 0; y <= MAX_GRID_CELLS_Y; y++)
|
||||
DrawLine((int)gridPosition.X, (int)gridPosition.Y + y * GRID_CELL_SIZE,
|
||||
(int)gridPosition.X + MAX_GRID_CELLS_X * GRID_CELL_SIZE, (int)gridPosition.Y + y * GRID_CELL_SIZE, Color.Gray);
|
||||
for (int x = 0; x <= MAX_GRID_CELLS_X; x++)
|
||||
DrawLine((int)gridPosition.X + x * GRID_CELL_SIZE, (int)gridPosition.Y,
|
||||
(int)gridPosition.X + x * GRID_CELL_SIZE, (int)gridPosition.Y + MAX_GRID_CELLS_Y * GRID_CELL_SIZE, Color.Gray);
|
||||
|
||||
// Draw player
|
||||
DrawRectangle((int)gridPosition.X + player.Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + player.Cell.Y * GRID_CELL_SIZE,
|
||||
GRID_CELL_SIZE + 1, GRID_CELL_SIZE + 1, player.Color);
|
||||
|
||||
// Draw undo system buffer info
|
||||
DrawText("UNDO STATES:", (int)undoInfoPos.X - 85, (int)undoInfoPos.Y + 9, 10, Color.DarkGray);
|
||||
DrawUndoBuffer(undoInfoPos, firstUndoIndex, lastUndoIndex, currentUndoIndex, 24);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Draw undo system visualization logic
|
||||
// NOTE: Visualizing the ring buffer array, every square can store a player state
|
||||
private static void DrawUndoBuffer(Vector2 position, int firstUndoIndex, int lastUndoIndex, int currentUndoIndex, int slotSize)
|
||||
{
|
||||
// Draw index marks
|
||||
DrawRectangle((int)position.X + 8 + slotSize * currentUndoIndex, (int)position.Y - 10, 8, 8, Color.Red);
|
||||
DrawRectangleLines((int)position.X + 2 + slotSize * firstUndoIndex, (int)position.Y + 27, 8, 8, Color.Black);
|
||||
DrawRectangle((int)position.X + 14 + slotSize * lastUndoIndex, (int)position.Y + 27, 8, 8, Color.Black);
|
||||
|
||||
// Draw background gray slots
|
||||
for (int i = 0; i < MAX_UNDO_STATES; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.LightGray);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Gray);
|
||||
}
|
||||
|
||||
// Draw occupied slots: firstUndoIndex --> lastUndoIndex
|
||||
if (firstUndoIndex <= lastUndoIndex)
|
||||
{
|
||||
for (int i = firstUndoIndex; i < lastUndoIndex + 1; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
|
||||
}
|
||||
}
|
||||
else if (lastUndoIndex < firstUndoIndex)
|
||||
{
|
||||
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
|
||||
}
|
||||
|
||||
for (int i = 0; i < lastUndoIndex + 1; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw occupied slots: firstUndoIndex --> currentUndoIndex
|
||||
if (firstUndoIndex < currentUndoIndex)
|
||||
{
|
||||
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
|
||||
}
|
||||
}
|
||||
else if (currentUndoIndex < firstUndoIndex)
|
||||
{
|
||||
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < currentUndoIndex; i++)
|
||||
{
|
||||
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
|
||||
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw current selected UNDO slot
|
||||
DrawRectangle((int)position.X + slotSize * currentUndoIndex, (int)position.Y, slotSize, slotSize, Color.Gold);
|
||||
DrawRectangleLines((int)position.X + slotSize * currentUndoIndex, (int)position.Y, slotSize, slotSize, Color.Orange);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - undo redo");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new UndoRedo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
361
Examples/Core/ViewportScaling.cs
Normal file
361
Examples/Core/ViewportScaling.cs
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - viewport scaling
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class ViewportScaling : IExample
|
||||
{
|
||||
private const int ResolutionCount = 4; // For iteration purposes and teaching example
|
||||
|
||||
private enum ViewportType
|
||||
{
|
||||
// Only upscale, useful for pixel art
|
||||
KeepAspectInteger,
|
||||
KeepHeightInteger,
|
||||
KeepWidthInteger,
|
||||
// Can also downscale
|
||||
KeepAspect,
|
||||
KeepHeight,
|
||||
KeepWidth,
|
||||
// For itteration purposes and as a teaching example
|
||||
ViewportTypeCount,
|
||||
}
|
||||
|
||||
// For displaying on GUI
|
||||
private static readonly string[] ViewportTypeNames = new string[]
|
||||
{
|
||||
"KEEP_ASPECT_INTEGER",
|
||||
"KEEP_HEIGHT_INTEGER",
|
||||
"KEEP_WIDTH_INTEGER",
|
||||
"KEEP_ASPECT",
|
||||
"KEEP_HEIGHT",
|
||||
"KEEP_WIDTH",
|
||||
};
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Viewport Scaling";
|
||||
|
||||
public string Title => "raylib [core] example - viewport scaling";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow;
|
||||
|
||||
// Mutable window size (tracked from GetScreenWidth/GetScreenHeight)
|
||||
private int curScreenWidth;
|
||||
private int curScreenHeight;
|
||||
|
||||
private Vector2[] resolutionList;
|
||||
private int resolutionIndex;
|
||||
private int gameWidth;
|
||||
private int gameHeight;
|
||||
|
||||
private RenderTexture2D target;
|
||||
private Rectangle sourceRect;
|
||||
private Rectangle destRect;
|
||||
|
||||
private ViewportType viewportType;
|
||||
|
||||
// Button rectangles
|
||||
private Rectangle decreaseResolutionButton;
|
||||
private Rectangle increaseResolutionButton;
|
||||
private Rectangle decreaseTypeButton;
|
||||
private Rectangle increaseTypeButton;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
curScreenWidth = screenWidth;
|
||||
curScreenHeight = screenHeight;
|
||||
|
||||
// Preset resolutions that could be created by subdividing screen resolution
|
||||
resolutionList = new Vector2[]
|
||||
{
|
||||
new Vector2(64, 64),
|
||||
new Vector2(256, 240),
|
||||
new Vector2(320, 180),
|
||||
// 4K doesn't work with integer scaling but included for example purposes with non-integer scaling
|
||||
new Vector2(3840, 2160),
|
||||
};
|
||||
|
||||
resolutionIndex = 0;
|
||||
gameWidth = 64;
|
||||
gameHeight = 64;
|
||||
|
||||
target = default;
|
||||
sourceRect = default;
|
||||
destRect = default;
|
||||
|
||||
viewportType = ViewportType.KeepAspectInteger;
|
||||
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
|
||||
// Button rectangles
|
||||
decreaseResolutionButton = new Rectangle(200, 30, 10, 10);
|
||||
increaseResolutionButton = new Rectangle(215, 30, 10, 10);
|
||||
decreaseTypeButton = new Rectangle(200, 45, 10, 10);
|
||||
increaseTypeButton = new Rectangle(215, 45, 10, 10);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsWindowResized()) ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
|
||||
Vector2 mousePosition = GetMousePosition();
|
||||
bool mousePressed = IsMouseButtonPressed(MouseButton.Left);
|
||||
|
||||
// Check buttons and rescale
|
||||
if (CheckCollisionPointRec(mousePosition, decreaseResolutionButton) && mousePressed)
|
||||
{
|
||||
resolutionIndex = (resolutionIndex + ResolutionCount - 1) % ResolutionCount;
|
||||
gameWidth = (int)resolutionList[resolutionIndex].X;
|
||||
gameHeight = (int)resolutionList[resolutionIndex].Y;
|
||||
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
}
|
||||
|
||||
if (CheckCollisionPointRec(mousePosition, increaseResolutionButton) && mousePressed)
|
||||
{
|
||||
resolutionIndex = (resolutionIndex + 1) % ResolutionCount;
|
||||
gameWidth = (int)resolutionList[resolutionIndex].X;
|
||||
gameHeight = (int)resolutionList[resolutionIndex].Y;
|
||||
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
}
|
||||
|
||||
if (CheckCollisionPointRec(mousePosition, decreaseTypeButton) && mousePressed)
|
||||
{
|
||||
viewportType = (ViewportType)(((int)viewportType + (int)ViewportType.ViewportTypeCount - 1) % (int)ViewportType.ViewportTypeCount);
|
||||
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
}
|
||||
|
||||
if (CheckCollisionPointRec(mousePosition, increaseTypeButton) && mousePressed)
|
||||
{
|
||||
viewportType = (ViewportType)(((int)viewportType + 1) % (int)ViewportType.ViewportTypeCount);
|
||||
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
|
||||
}
|
||||
|
||||
Vector2 textureMousePosition = Screen2RenderTexturePosition(mousePosition, sourceRect, destRect);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw our scene to the render texture
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
DrawCircleV(textureMousePosition, 20.0f, Color.Lime);
|
||||
EndTextureMode();
|
||||
|
||||
// Draw render texture to main framebuffer
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw our render texture with rotation applied
|
||||
DrawTexturePro(target.Texture, sourceRect, destRect, new Vector2(0.0f, 0.0f), 0.0f, Color.White);
|
||||
|
||||
// Draw Native resolution (GUI or anything)
|
||||
// Draw info box
|
||||
Rectangle infoRect = new Rectangle(5, 5, 330, 105);
|
||||
DrawRectangleRec(infoRect, Fade(Color.LightGray, 0.7f));
|
||||
DrawRectangleLinesEx(infoRect, 1, Color.Blue);
|
||||
|
||||
DrawText($"Window Resolution: {curScreenWidth} x {curScreenHeight}", 15, 15, 10, Color.Black);
|
||||
DrawText($"Game Resolution: {gameWidth} x {gameHeight}", 15, 30, 10, Color.Black);
|
||||
|
||||
DrawText($"Type: {ViewportTypeNames[(int)viewportType]}", 15, 45, 10, Color.Black);
|
||||
Vector2 scaleRatio = new Vector2(destRect.Width / sourceRect.Width, -destRect.Height / sourceRect.Height);
|
||||
if (scaleRatio.X < 0.001f || scaleRatio.Y < 0.001f) DrawText("Scale ratio: INVALID", 15, 60, 10, Color.Black);
|
||||
else DrawText($"Scale ratio: {scaleRatio.X:F2} x {scaleRatio.Y:F2}", 15, 60, 10, Color.Black);
|
||||
|
||||
DrawText($"Source size: {sourceRect.Width:F2} x {-sourceRect.Height:F2}", 15, 75, 10, Color.Black);
|
||||
DrawText($"Destination size: {destRect.Width:F2} x {destRect.Height:F2}", 15, 90, 10, Color.Black);
|
||||
|
||||
// Draw buttons
|
||||
DrawRectangleRec(decreaseTypeButton, Color.SkyBlue);
|
||||
DrawRectangleRec(increaseTypeButton, Color.SkyBlue);
|
||||
DrawRectangleRec(decreaseResolutionButton, Color.SkyBlue);
|
||||
DrawRectangleRec(increaseResolutionButton, Color.SkyBlue);
|
||||
DrawText("<", (int)decreaseTypeButton.X + 3, (int)decreaseTypeButton.Y + 1, 10, Color.Black);
|
||||
DrawText(">", (int)increaseTypeButton.X + 3, (int)increaseTypeButton.Y + 1, 10, Color.Black);
|
||||
DrawText("<", (int)decreaseResolutionButton.X + 3, (int)decreaseResolutionButton.Y + 1, 10, Color.Black);
|
||||
DrawText(">", (int)increaseResolutionButton.X + 3, (int)increaseResolutionButton.Y + 1, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
private static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = (float)gameHeight;
|
||||
sourceRect.Width = (float)gameWidth;
|
||||
sourceRect.Height = (float)-gameHeight;
|
||||
|
||||
int ratioX = (screenWidth / gameWidth);
|
||||
int ratioY = (screenHeight / gameHeight);
|
||||
float resizeRatio = (float)((ratioX < ratioY) ? ratioX : ratioY);
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(gameWidth * resizeRatio);
|
||||
destRect.Height = (float)(int)(gameHeight * resizeRatio);
|
||||
}
|
||||
|
||||
private static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
float resizeRatio = (float)screenHeight / gameHeight;
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = 0.0f;
|
||||
sourceRect.Width = (float)(int)(screenWidth / resizeRatio);
|
||||
sourceRect.Height = (float)-gameHeight;
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (sourceRect.Width * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(sourceRect.Width * resizeRatio);
|
||||
destRect.Height = (float)(int)(gameHeight * resizeRatio);
|
||||
}
|
||||
|
||||
private static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
float resizeRatio = (float)screenWidth / gameWidth;
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = 0.0f;
|
||||
sourceRect.Width = (float)gameWidth;
|
||||
sourceRect.Height = (float)(int)(screenHeight / resizeRatio);
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (sourceRect.Height * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(gameWidth * resizeRatio);
|
||||
destRect.Height = (float)(int)(sourceRect.Height * resizeRatio);
|
||||
|
||||
sourceRect.Height *= -1.0f;
|
||||
}
|
||||
|
||||
private static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = (float)gameHeight;
|
||||
sourceRect.Width = (float)gameWidth;
|
||||
sourceRect.Height = (float)-gameHeight;
|
||||
|
||||
float ratioX = ((float)screenWidth / (float)gameWidth);
|
||||
float ratioY = ((float)screenHeight / (float)gameHeight);
|
||||
float resizeRatio = (ratioX < ratioY ? ratioX : ratioY);
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(gameWidth * resizeRatio);
|
||||
destRect.Height = (float)(int)(gameHeight * resizeRatio);
|
||||
}
|
||||
|
||||
private static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
float resizeRatio = ((float)screenHeight / (float)gameHeight);
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = 0.0f;
|
||||
sourceRect.Width = (float)(int)((float)screenWidth / resizeRatio);
|
||||
sourceRect.Height = (float)-gameHeight;
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (sourceRect.Width * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(sourceRect.Width * resizeRatio);
|
||||
destRect.Height = (float)(int)(gameHeight * resizeRatio);
|
||||
}
|
||||
|
||||
private static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
|
||||
{
|
||||
float resizeRatio = ((float)screenWidth / (float)gameWidth);
|
||||
sourceRect.X = 0.0f;
|
||||
sourceRect.Y = 0.0f;
|
||||
sourceRect.Width = (float)gameWidth;
|
||||
sourceRect.Height = (float)(int)((float)screenHeight / resizeRatio);
|
||||
|
||||
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
|
||||
destRect.Y = (float)(int)((screenHeight - (sourceRect.Height * resizeRatio)) * 0.5f);
|
||||
destRect.Width = (float)(int)(gameWidth * resizeRatio);
|
||||
destRect.Height = (float)(int)(sourceRect.Height * resizeRatio);
|
||||
|
||||
sourceRect.Height *= -1.0f;
|
||||
}
|
||||
|
||||
private static void ResizeRenderSize(ViewportType viewportType, ref int screenWidth, ref int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect, ref RenderTexture2D target)
|
||||
{
|
||||
screenWidth = GetScreenWidth();
|
||||
screenHeight = GetScreenHeight();
|
||||
|
||||
switch (viewportType)
|
||||
{
|
||||
case ViewportType.KeepAspectInteger: KeepAspectCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
case ViewportType.KeepHeightInteger: KeepHeightCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
case ViewportType.KeepWidthInteger: KeepWidthCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
case ViewportType.KeepAspect: KeepAspectCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
case ViewportType.KeepHeight: KeepHeightCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
case ViewportType.KeepWidth: KeepWidthCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
UnloadRenderTexture(target);
|
||||
target = LoadRenderTexture((int)sourceRect.Width, -(int)sourceRect.Height);
|
||||
}
|
||||
|
||||
// Example how to calculate position on RenderTexture
|
||||
private static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle textureRect, Rectangle scaledRect)
|
||||
{
|
||||
Vector2 relativePosition = new Vector2(point.X - scaledRect.X, point.Y - scaledRect.Y);
|
||||
Vector2 ratio = new Vector2(textureRect.Width / scaledRect.Width, -textureRect.Height / scaledRect.Height);
|
||||
|
||||
return new Vector2(relativePosition.X * ratio.X, relativePosition.Y * ratio.X);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//---------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.ResizableWindow);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - viewport scaling");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//----------------------------------------------------------
|
||||
|
||||
var game = new ViewportScaling();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//----------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - VR Simulator (Oculus Rift CV1 parameters)
|
||||
* raylib [core] example - vr simulator
|
||||
*
|
||||
* This example has been created using raylib 1.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 4.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) 2017-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,51 +19,62 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class VrSimulator
|
||||
public partial class VrSimulator : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Core / VR Simulator";
|
||||
|
||||
public string Title => "raylib [core] example - vr simulator";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private VrStereoConfig config;
|
||||
private Shader distortion;
|
||||
private RenderTexture2D target;
|
||||
private Rectangle sourceRec;
|
||||
private Rectangle destRec;
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 1080;
|
||||
const int screenHeight = 600;
|
||||
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator");
|
||||
|
||||
// VR device parameters definition
|
||||
VrDeviceInfo device = new VrDeviceInfo
|
||||
var device = new VrDeviceInfo
|
||||
{
|
||||
// Oculus Rift CV1 parameters for simulator
|
||||
HResolution = 2160,
|
||||
VResolution = 1200,
|
||||
HScreenSize = 0.133793f,
|
||||
VScreenSize = 0.0669f,
|
||||
EyeToScreenDistance = 0.041f,
|
||||
LensSeparationDistance = 0.07f,
|
||||
InterpupillaryDistance = 0.07f,
|
||||
HResolution = 2160, // Horizontal resolution in pixels
|
||||
VResolution = 1200, // Vertical resolution in pixels
|
||||
HScreenSize = 0.133793f, // Horizontal size in meters
|
||||
VScreenSize = 0.0669f, // Vertical size in meters
|
||||
EyeToScreenDistance = 0.041f, // Distance between eye and display in meters
|
||||
LensSeparationDistance = 0.07f, // Lens separation distance in meters
|
||||
InterpupillaryDistance = 0.07f, // IPD (distance between pupils) in meters
|
||||
};
|
||||
|
||||
// NOTE: CV1 uses a Fresnel-hybrid-asymmetric lenses with specific distortion compute shaders.
|
||||
// Following parameters are an approximation to distortion stereo rendering but results differ from actual
|
||||
// device.
|
||||
unsafe
|
||||
{
|
||||
device.LensDistortionValues[0] = 1.0f;
|
||||
device.LensDistortionValues[1] = 0.22f;
|
||||
device.LensDistortionValues[2] = 0.24f;
|
||||
device.LensDistortionValues[3] = 0.0f;
|
||||
device.ChromaAbCorrection[0] = 0.996f;
|
||||
device.ChromaAbCorrection[1] = -0.004f;
|
||||
device.ChromaAbCorrection[2] = 1.014f;
|
||||
device.ChromaAbCorrection[3] = 0.0f;
|
||||
}
|
||||
// NOTE: CV1 uses fresnel-hybrid-asymmetric lenses with specific compute shaders
|
||||
// Following parameters are just an approximation to CV1 distortion stereo rendering
|
||||
device.LensDistortionValues[0] = 1.0f; // Lens distortion constant parameter 0
|
||||
device.LensDistortionValues[1] = 0.22f; // Lens distortion constant parameter 1
|
||||
device.LensDistortionValues[2] = 0.24f; // Lens distortion constant parameter 2
|
||||
device.LensDistortionValues[3] = 0.0f; // Lens distortion constant parameter 3
|
||||
device.ChromaAbCorrection[0] = 0.996f; // Chromatic aberration correction parameter 0
|
||||
device.ChromaAbCorrection[1] = -0.004f; // Chromatic aberration correction parameter 1
|
||||
device.ChromaAbCorrection[2] = 1.014f; // Chromatic aberration correction parameter 2
|
||||
device.ChromaAbCorrection[3] = 0.0f; // Chromatic aberration correction parameter 3
|
||||
|
||||
// Load VR stereo config for VR device parameteres (Oculus Rift CV1 parameters)
|
||||
VrStereoConfig config = LoadVrStereoConfig(device);
|
||||
config = LoadVrStereoConfig(device);
|
||||
|
||||
// Distortion shader (uses device lens distortion and chroma)
|
||||
Shader distortion = LoadShader(null, "resources/distortion330.fs");
|
||||
distortion = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/distortion.fs");
|
||||
|
||||
// Update distortion shader with lens and distortion-scale parameters
|
||||
Raylib.SetShaderValue(
|
||||
|
|
@ -100,88 +115,104 @@ public class VrSimulator
|
|||
ShaderUniformDataType.Vec2
|
||||
);
|
||||
|
||||
unsafe
|
||||
{
|
||||
SetShaderValue(
|
||||
distortion,
|
||||
GetShaderLocation(distortion, "deviceWarpParam"),
|
||||
device.LensDistortionValues,
|
||||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
SetShaderValue(
|
||||
distortion,
|
||||
GetShaderLocation(distortion, "chromaAbParam"),
|
||||
device.ChromaAbCorrection,
|
||||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
}
|
||||
SetShaderValue(
|
||||
distortion,
|
||||
GetShaderLocation(distortion, "deviceWarpParam"),
|
||||
device.LensDistortionValues,
|
||||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
SetShaderValue(
|
||||
distortion,
|
||||
GetShaderLocation(distortion, "chromaAbParam"),
|
||||
device.ChromaAbCorrection,
|
||||
ShaderUniformDataType.Vec4
|
||||
);
|
||||
|
||||
// Initialize framebuffer for stereo rendering
|
||||
// NOTE: Screen size should match HMD aspect ratio
|
||||
RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
|
||||
target = LoadRenderTexture(device.HResolution, device.VResolution);
|
||||
|
||||
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
|
||||
sourceRec = new(0.0f, 0.0f, (float)target.Texture.Width, -(float)target.Texture.Height);
|
||||
destRec = new(0.0f, 0.0f, (float)GetScreenWidth(), (float)GetScreenHeight());
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera.Position = new Vector3(5.0f, 2.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 60.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 2.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector
|
||||
camera.FovY = 60.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
SetTargetFPS(90); // Set our game to run at 90 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
BeginVrStereoMode(config);
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
DrawGrid(40, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
EndVrStereoMode();
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
BeginShaderMode(distortion);
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0.0f, 0.0f), 0.0f, Color.White);
|
||||
EndShaderMode();
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadVrStereoConfig(config); // Unload stereo config
|
||||
|
||||
UnloadRenderTexture(target); // Unload stereo render fbo
|
||||
UnloadShader(distortion); // Unload distortion shader
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// NOTE: screenWidth/screenHeight should match VR device aspect ratio
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new VrSimulator();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginVrStereoMode(config);
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
DrawGrid(40, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
EndVrStereoMode();
|
||||
EndTextureMode();
|
||||
|
||||
BeginShaderMode(distortion);
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, (float)target.Texture.Width, (float)-target.Texture.Height),
|
||||
new Vector2(0.0f, 0.0f),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadVrStereoConfig(config);
|
||||
UnloadRenderTexture(target);
|
||||
UnloadShader(distortion);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
*
|
||||
* raylib [core] example - window flags
|
||||
*
|
||||
* This example has been created using raylib 3.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2020 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 3.5, last time updated with raylib 3.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) 2020-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,15 +19,239 @@ using static Raylib_cs.ConfigFlags;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class WindowFlags
|
||||
[ExcludeFromBrowser("runtime window-state flags don't apply to the emscripten canvas")]
|
||||
public partial class WindowFlags : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Window Flags";
|
||||
|
||||
public string Title => "raylib [core] example - window flags";
|
||||
|
||||
private Vector2 ballPosition;
|
||||
private Vector2 ballSpeed;
|
||||
private float ballRadius;
|
||||
|
||||
private int framesCounter = 0;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
ballPosition = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
|
||||
ballSpeed = new(5.0f, 4.0f);
|
||||
ballRadius = 20;
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//-----------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
// modifies window size when scaling!
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
if (IsWindowState(ResizableWindow))
|
||||
{
|
||||
ClearWindowState(ResizableWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(ResizableWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.D))
|
||||
{
|
||||
if (IsWindowState(UndecoratedWindow))
|
||||
{
|
||||
ClearWindowState(UndecoratedWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(UndecoratedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.H))
|
||||
{
|
||||
if (!IsWindowState(HiddenWindow))
|
||||
{
|
||||
SetWindowState(HiddenWindow);
|
||||
}
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
if (IsWindowState(HiddenWindow))
|
||||
{
|
||||
framesCounter++;
|
||||
if (framesCounter >= 240)
|
||||
{
|
||||
// Show window after 3 seconds
|
||||
ClearWindowState(HiddenWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
if (!IsWindowState(MinimizedWindow))
|
||||
{
|
||||
MinimizeWindow();
|
||||
}
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
if (IsWindowState(MinimizedWindow))
|
||||
{
|
||||
framesCounter++;
|
||||
if (framesCounter >= 240)
|
||||
{
|
||||
// Restore window after 3 seconds
|
||||
RestoreWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.M))
|
||||
{
|
||||
// NOTE: Requires FLAG_WINDOW_RESIZABLE enabled!
|
||||
if (IsWindowState(MaximizedWindow))
|
||||
{
|
||||
RestoreWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
MaximizeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.U))
|
||||
{
|
||||
if (IsWindowState(UnfocusedWindow))
|
||||
{
|
||||
ClearWindowState(UnfocusedWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(UnfocusedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.T))
|
||||
{
|
||||
if (IsWindowState(TopmostWindow))
|
||||
{
|
||||
ClearWindowState(TopmostWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(TopmostWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.A))
|
||||
{
|
||||
if (IsWindowState(AlwaysRunWindow))
|
||||
{
|
||||
ClearWindowState(AlwaysRunWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(AlwaysRunWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.V))
|
||||
{
|
||||
if (IsWindowState(VSyncHint))
|
||||
{
|
||||
ClearWindowState(VSyncHint);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(VSyncHint);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.B))
|
||||
{
|
||||
ToggleBorderlessWindowed();
|
||||
}
|
||||
|
||||
// Bouncing ball logic
|
||||
ballPosition.X += ballSpeed.X;
|
||||
ballPosition.Y += ballSpeed.Y;
|
||||
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
|
||||
{
|
||||
ballSpeed.X *= -1.0f;
|
||||
}
|
||||
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
|
||||
{
|
||||
ballSpeed.Y *= -1.0f;
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//-----------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
if (IsWindowState(TransparentWindow))
|
||||
{
|
||||
ClearBackground(Color.Blank);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearBackground(Color.RayWhite);
|
||||
}
|
||||
|
||||
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
|
||||
DrawRectangleLinesEx(new Rectangle(0, 0, GetScreenWidth(), GetScreenHeight()), 4, Color.RayWhite);
|
||||
|
||||
DrawCircleV(GetMousePosition(), 10, Color.DarkBlue);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText($"Screen Size: [{GetScreenWidth()}, {GetScreenHeight()}]", 10, 40, 10, Color.Green);
|
||||
|
||||
// Draw window state info
|
||||
DrawText("Following flags can be set after window creation:", 10, 60, 10, Color.Gray);
|
||||
|
||||
DrawWindowState(FullscreenMode, "[F] FLAG_FULLSCREEN_MODE: ", 10, 80, 10);
|
||||
DrawWindowState(ResizableWindow, "[R] FLAG_WINDOW_RESIZABLE: ", 10, 100, 10);
|
||||
DrawWindowState(UndecoratedWindow, "[D] FLAG_WINDOW_UNDECORATED: ", 10, 120, 10);
|
||||
DrawWindowState(HiddenWindow, "[H] FLAG_WINDOW_HIDDEN: ", 10, 140, 10);
|
||||
DrawWindowState(MinimizedWindow, "[N] FLAG_WINDOW_MINIMIZED: ", 10, 160, 10);
|
||||
DrawWindowState(MaximizedWindow, "[M] FLAG_WINDOW_MAXIMIZED: ", 10, 180, 10);
|
||||
DrawWindowState(UnfocusedWindow, "[G] FLAG_WINDOW_UNFOCUSED: ", 10, 200, 10);
|
||||
DrawWindowState(TopmostWindow, "[T] FLAG_WINDOW_TOPMOST: ", 10, 220, 10);
|
||||
DrawWindowState(AlwaysRunWindow, "[A] FLAG_WINDOW_ALWAYS_RUN: ", 10, 240, 10);
|
||||
DrawWindowState(VSyncHint, "[V] FLAG_VSYNC_HINT: ", 10, 260, 10);
|
||||
DrawWindowState(BorderlessWindowMode, "[B] FLAG_BORDERLESS_WINDOWED_MODE: ", 10, 280, 10);
|
||||
|
||||
DrawText("Following flags can only be set before window creation:", 10, 320, 10, Color.Gray);
|
||||
|
||||
DrawWindowState(HighDpiWindow, "FLAG_WINDOW_HIGHDPI: ", 10, 340, 10);
|
||||
DrawWindowState(TransparentWindow, "FLAG_WINDOW_TRANSPARENT: ", 10, 360, 10);
|
||||
DrawWindowState(Msaa4xHint, "FLAG_MSAA_4X_HINT: ", 10, 380, 10);
|
||||
|
||||
EndDrawing();
|
||||
//-----------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//---------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Possible window flags
|
||||
/*
|
||||
FLAG_VSYNC_HINT
|
||||
|
|
@ -42,235 +270,43 @@ public class WindowFlags
|
|||
*/
|
||||
|
||||
// Set configuration flags for window creation
|
||||
SetConfigFlags(VSyncHint | Msaa4xHint);
|
||||
//SetConfigFlags(VSyncHint | Msaa4xHint | HighDpiWindow);// | TransparentWindow);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - window flags");
|
||||
|
||||
Vector2 ballPosition = new(GetScreenWidth() / 2, GetScreenHeight() / 2);
|
||||
Vector2 ballSpeed = new(5.0f, 4.0f);
|
||||
int ballRadius = 20;
|
||||
|
||||
int framesCounter = 0;
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//----------------------------------------------------------
|
||||
|
||||
var game = new WindowFlags();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//-----------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
// modifies window size when scaling!
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
if (IsWindowState(ResizableWindow))
|
||||
{
|
||||
ClearWindowState(ResizableWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(ResizableWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.D))
|
||||
{
|
||||
if (IsWindowState(UndecoratedWindow))
|
||||
{
|
||||
ClearWindowState(UndecoratedWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(UndecoratedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.H))
|
||||
{
|
||||
if (!IsWindowState(HiddenWindow))
|
||||
{
|
||||
SetWindowState(HiddenWindow);
|
||||
}
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
if (IsWindowState(HiddenWindow))
|
||||
{
|
||||
framesCounter++;
|
||||
if (framesCounter >= 240)
|
||||
{
|
||||
// Show window after 3 seconds
|
||||
ClearWindowState(HiddenWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
if (!IsWindowState(MinimizedWindow))
|
||||
{
|
||||
MinimizeWindow();
|
||||
}
|
||||
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
if (IsWindowState(MinimizedWindow))
|
||||
{
|
||||
framesCounter++;
|
||||
if (framesCounter >= 240)
|
||||
{
|
||||
// Restore window after 3 seconds
|
||||
RestoreWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.M))
|
||||
{
|
||||
// NOTE: Requires FLAG_WINDOW_RESIZABLE enabled!
|
||||
if (IsWindowState(MaximizedWindow))
|
||||
{
|
||||
RestoreWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
MaximizeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.U))
|
||||
{
|
||||
if (IsWindowState(UnfocusedWindow))
|
||||
{
|
||||
ClearWindowState(UnfocusedWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(UnfocusedWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.T))
|
||||
{
|
||||
if (IsWindowState(TopmostWindow))
|
||||
{
|
||||
ClearWindowState(TopmostWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(TopmostWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.A))
|
||||
{
|
||||
if (IsWindowState(AlwaysRunWindow))
|
||||
{
|
||||
ClearWindowState(AlwaysRunWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(AlwaysRunWindow);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.V))
|
||||
{
|
||||
if (IsWindowState(VSyncHint))
|
||||
{
|
||||
ClearWindowState(VSyncHint);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowState(VSyncHint);
|
||||
}
|
||||
}
|
||||
|
||||
// Bouncing ball logic
|
||||
ballPosition.X += ballSpeed.X;
|
||||
ballPosition.Y += ballSpeed.Y;
|
||||
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
|
||||
{
|
||||
ballSpeed.X *= -1.0f;
|
||||
}
|
||||
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
|
||||
{
|
||||
ballSpeed.Y *= -1.0f;
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//-----------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
if (IsWindowState(TransparentWindow))
|
||||
{
|
||||
ClearBackground(Color.Blank);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearBackground(Color.RayWhite);
|
||||
}
|
||||
|
||||
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
|
||||
DrawRectangleLinesEx(new Rectangle(0, 0, GetScreenWidth(), GetScreenHeight()), 4, Color.RayWhite);
|
||||
|
||||
DrawCircleV(GetMousePosition(), 10, Color.DarkBlue);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText($"Screen Size: [{GetScreenWidth()}, {GetScreenHeight()}]", 10, 40, 10, Color.Green);
|
||||
|
||||
// Draw window state info
|
||||
Color on = Color.Lime;
|
||||
Color off = Color.Maroon;
|
||||
|
||||
DrawText("Following flags can be set after window creation:", 10, 60, 10, Color.Gray);
|
||||
|
||||
DrawWindowState(FullscreenMode, "[F] FLAG_FULLSCREEN_MODE: ", 10, 80, 10);
|
||||
DrawWindowState(ResizableWindow, "[R] FLAG_WINDOW_RESIZABLE: ", 10, 100, 10);
|
||||
DrawWindowState(UndecoratedWindow, "[D] FLAG_WINDOW_UNDECORATED: ", 10, 120, 10);
|
||||
DrawWindowState(HiddenWindow, "[H] FLAG_WINDOW_HIDDEN: ", 10, 140, 10);
|
||||
DrawWindowState(MinimizedWindow, "[N] FLAG_WINDOW_MINIMIZED: ", 10, 160, 10);
|
||||
DrawWindowState(MaximizedWindow, "[M] FLAG_WINDOW_MAXIMIZED: ", 10, 180, 10);
|
||||
DrawWindowState(UnfocusedWindow, "[G] FLAG_WINDOW_UNFOCUSED: ", 10, 200, 10);
|
||||
DrawWindowState(TopmostWindow, "[T] FLAG_WINDOW_TOPMOST: ", 10, 220, 10);
|
||||
DrawWindowState(AlwaysRunWindow, "[A] FLAG_WINDOW_ALWAYS_RUN: ", 10, 240, 10);
|
||||
DrawWindowState(VSyncHint, "[V] FLAG_VSYNC_HINT: ", 10, 260, 10);
|
||||
|
||||
DrawText("Following flags can only be set before window creation:", 10, 300, 10, Color.Gray);
|
||||
|
||||
DrawWindowState(HighDpiWindow, "[F] FLAG_WINDOW_HIGHDPI: ", 10, 320, 10);
|
||||
DrawWindowState(TransparentWindow, "[F] FLAG_WINDOW_TRANSPARENT: ", 10, 340, 10);
|
||||
DrawWindowState(Msaa4xHint, "[F] FLAG_MSAA_4X_HINT: ", 10, 360, 10);
|
||||
|
||||
EndDrawing();
|
||||
//-----------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//---------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//----------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DrawWindowState(ConfigFlags flag, string text, int posX, int posY, int fontSize)
|
||||
private static void DrawWindowState(ConfigFlags flag, string text, int posX, int posY, int fontSize)
|
||||
{
|
||||
Color onColor = Color.Lime;
|
||||
Color offColor = Color.Maroon;
|
||||
var onColor = Color.Lime;
|
||||
var offColor = Color.Maroon;
|
||||
|
||||
if (Raylib.IsWindowState(flag))
|
||||
{
|
||||
DrawText($"{text} on", posX, posY, fontSize, onColor);
|
||||
DrawText($"{text}on", posX, posY, fontSize, onColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($"{text} off", posX, posY, fontSize, offColor);
|
||||
DrawText($"{text}off", posX, posY, fontSize, offColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - window scale letterbox
|
||||
* raylib [core] example - window letterbox
|
||||
*
|
||||
* 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 4.0
|
||||
*
|
||||
* Example contributed by Anata (@anatagawa) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 Anata (@anatagawa) 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 Anata (@anatagawa) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -17,123 +21,153 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class WindowLetterbox
|
||||
public partial class WindowLetterbox : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int windowWidth = 800;
|
||||
private const int windowHeight = 450;
|
||||
|
||||
private const int gamescreenWidth = 640;
|
||||
private const int gamescreenHeight = 480;
|
||||
|
||||
public string Name => "Core / Window Letterbox";
|
||||
|
||||
public string Title => "raylib [core] example - window letterbox";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint;
|
||||
|
||||
private RenderTexture2D target;
|
||||
private Color[] colors;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
const int windowWidth = 800;
|
||||
const int windowHeight = 450;
|
||||
|
||||
// Enable config flags for resizable window and vertical synchro
|
||||
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint);
|
||||
InitWindow(windowWidth, windowHeight, "raylib [core] example - window scale letterbox");
|
||||
SetWindowMinSize(320, 240);
|
||||
|
||||
int gameScreenWidth = 640;
|
||||
int gameScreenHeight = 480;
|
||||
|
||||
// Render texture initialization, used to hold the rendering result so we can easily resize it
|
||||
RenderTexture2D target = LoadRenderTexture(gameScreenWidth, gameScreenHeight);
|
||||
SetTextureFilter(target.Texture, TextureFilter.Bilinear);
|
||||
target = LoadRenderTexture(gamescreenWidth, gamescreenHeight);
|
||||
SetTextureFilter(target.Texture, TextureFilter.Bilinear); // Texture scale filter to use
|
||||
|
||||
Color[] colors = new Color[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
colors = new Color[10];
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
colors[i] = new Color(GetRandomValue(100, 250), GetRandomValue(50, 150), GetRandomValue(10, 100), 255);
|
||||
}
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Compute required framebuffer scaling
|
||||
var scale = MathF.Min(
|
||||
(float)GetScreenWidth() / gamescreenWidth,
|
||||
(float)GetScreenHeight() / gamescreenHeight
|
||||
);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
// Recalculate random colors for the bars
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
colors[i] = new Color(
|
||||
GetRandomValue(100, 250),
|
||||
GetRandomValue(50, 150),
|
||||
GetRandomValue(10, 100),
|
||||
255
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Update virtual mouse (clamped mouse value behind game screen)
|
||||
var mouse = GetMousePosition();
|
||||
var virtualMouse = Vector2.Zero;
|
||||
virtualMouse.X = (mouse.X - (GetScreenWidth() - (gamescreenWidth * scale)) * 0.5f) / scale;
|
||||
virtualMouse.Y = (mouse.Y - (GetScreenHeight() - (gamescreenHeight * scale)) * 0.5f) / scale;
|
||||
|
||||
Vector2 max = new((float)gamescreenWidth, (float)gamescreenHeight);
|
||||
virtualMouse = Vector2.Clamp(virtualMouse, Vector2.Zero, max);
|
||||
|
||||
// Apply the same transformation as the virtual mouse to the real mouse (i.e. to work with raygui)
|
||||
//SetMouseOffset(-(GetScreenWidth() - (gamescreenWidth*scale))*0.5f, -(GetScreenHeight() - (gamescreenHeight*scale))*0.5f);
|
||||
//SetMouseScale(1/scale, 1/scale);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw everything in the render texture, note this will not be rendered on screen, yet
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite); // Clear render texture background color
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
DrawRectangle(0, (gamescreenHeight / 10) * i, gamescreenWidth, gamescreenHeight / 10, colors[i]);
|
||||
}
|
||||
|
||||
DrawText(
|
||||
"If executed inside a window,\nyou can resize the window,\nand see the screen scaling!",
|
||||
10,
|
||||
25,
|
||||
20,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawText($"Default Mouse: [{(int)mouse.X} , {(int)mouse.Y}]", 350, 25, 20, Color.Green);
|
||||
DrawText($"Virtual Mouse: [{(int)virtualMouse.X} , {(int)virtualMouse.Y}]", 350, 55, 20, Color.Yellow);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black); // Clear screen background
|
||||
|
||||
// Draw render texture to screen, properly scaled
|
||||
Rectangle sourceRec = new(
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)target.Texture.Width,
|
||||
(float)-target.Texture.Height
|
||||
);
|
||||
Rectangle destRec = new(
|
||||
(GetScreenWidth() - ((float)gamescreenWidth * scale)) * 0.5f,
|
||||
(GetScreenHeight() - ((float)gamescreenHeight * scale)) * 0.5f,
|
||||
(float)gamescreenWidth * scale,
|
||||
(float)gamescreenHeight * scale
|
||||
);
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0, 0), 0.0f, Color.White);
|
||||
|
||||
EndDrawing();
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Enable config flags for resizable window and vertical synchro
|
||||
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint);
|
||||
InitWindow(windowWidth, windowHeight, "raylib [core] example - window letterbox");
|
||||
SetWindowMinSize(320, 240);
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new WindowLetterbox();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Compute required framebuffer scaling
|
||||
float scale = MathF.Min(
|
||||
(float)GetScreenWidth() / gameScreenWidth,
|
||||
(float)GetScreenHeight() / gameScreenHeight
|
||||
);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
// Recalculate random colors for the bars
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
colors[i] = new Color(
|
||||
GetRandomValue(100, 250),
|
||||
GetRandomValue(50, 150),
|
||||
GetRandomValue(10, 100),
|
||||
255
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Update virtual mouse (clamped mouse value behind game screen)
|
||||
Vector2 mouse = GetMousePosition();
|
||||
Vector2 virtualMouse = Vector2.Zero;
|
||||
virtualMouse.X = (mouse.X - (GetScreenWidth() - (gameScreenWidth * scale)) * 0.5f) / scale;
|
||||
virtualMouse.Y = (mouse.Y - (GetScreenHeight() - (gameScreenHeight * scale)) * 0.5f) / scale;
|
||||
|
||||
Vector2 max = new((float)gameScreenWidth, (float)gameScreenHeight);
|
||||
virtualMouse = Vector2.Clamp(virtualMouse, Vector2.Zero, max);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
// Draw everything in the render texture, note this will not be rendered on screen, yet
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
DrawRectangle(0, (gameScreenHeight / 10) * i, gameScreenWidth, gameScreenHeight / 10, colors[i]);
|
||||
}
|
||||
|
||||
DrawText(
|
||||
"If executed inside a window,\nyou can resize the window,\nand see the screen scaling!",
|
||||
10,
|
||||
25,
|
||||
20,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawText($"Default Mouse: [{(int)mouse.X} {(int)mouse.Y}]", 350, 25, 20, Color.Green);
|
||||
DrawText($"Virtual Mouse: [{(int)virtualMouse.X}, {(int)virtualMouse.Y}]", 350, 55, 20, Color.Yellow);
|
||||
|
||||
EndTextureMode();
|
||||
|
||||
// Draw RenderTexture2D to window, properly scaled
|
||||
Rectangle sourceRec = new(
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)target.Texture.Width,
|
||||
(float)-target.Texture.Height
|
||||
);
|
||||
Rectangle destRec = new(
|
||||
(GetScreenWidth() - ((float)gameScreenWidth * scale)) * 0.5f,
|
||||
(GetScreenHeight() - ((float)gameScreenHeight * scale)) * 0.5f,
|
||||
(float)gameScreenWidth * scale,
|
||||
(float)gameScreenHeight * scale
|
||||
);
|
||||
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0, 0), 0.0f, Color.White);
|
||||
|
||||
EndDrawing();
|
||||
//--------------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadRenderTexture(target);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
130
Examples/Core/WindowShouldClose.cs
Normal file
130
Examples/Core/WindowShouldClose.cs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - window should close
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, 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;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class WindowShouldClose : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Window Should Close";
|
||||
|
||||
public string Title => "raylib [core] example - window should close";
|
||||
|
||||
// The runner drives its loop off this instead of WindowShouldClose(), so the exit
|
||||
// confirmation (polled in Update) can intercept both the X-button and KEY_ESCAPE.
|
||||
public bool ShouldClose => exitWindow;
|
||||
|
||||
private bool exitWindowRequested; // Flag to request window to exit
|
||||
private bool exitWindow; // Flag to set window to exit
|
||||
|
||||
public void Init()
|
||||
{
|
||||
SetExitKey(KeyboardKey.Null); // Disable KEY_ESCAPE to close window, X-button still works
|
||||
|
||||
exitWindowRequested = false;
|
||||
exitWindow = false;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Detect if X-button or KEY_ESCAPE have been pressed to close window
|
||||
bool closeRequested = IsKeyPressed(KeyboardKey.Escape);
|
||||
#if !BROWSER
|
||||
// WindowShouldClose() polls the OS window close button, but on the wasm target it calls
|
||||
// emscripten_sleep (ASYNCIFY is not enabled) and the canvas has no window chrome anyway,
|
||||
// so on web the confirmation is triggered by KEY_ESCAPE only.
|
||||
closeRequested |= Raylib.WindowShouldClose();
|
||||
#endif
|
||||
if (closeRequested)
|
||||
{
|
||||
exitWindowRequested = true;
|
||||
}
|
||||
|
||||
if (exitWindowRequested)
|
||||
{
|
||||
// A request for close window has been issued, we can save data before closing
|
||||
// or just show a message asking for confirmation
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Y))
|
||||
{
|
||||
exitWindow = true;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.N))
|
||||
{
|
||||
exitWindowRequested = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
if (exitWindowRequested)
|
||||
{
|
||||
DrawRectangle(0, 100, screenWidth, 200, Color.Black);
|
||||
DrawText("Are you sure you want to exit program? [Y/N]", 40, 180, 30, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Try to close the window to get confirmation message!", 120, 200, 20, Color.LightGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - window should close");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new WindowShouldClose();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!game.exitWindow)
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - World to screen
|
||||
* raylib [core] example - world screen
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 1.4
|
||||
*
|
||||
* 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,84 +18,113 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class WorldScreen
|
||||
public partial class WorldScreen : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / World to Screen";
|
||||
|
||||
public string Title => "raylib [core] example - world screen";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
private Vector2 cubeScreenPosition = new(0.0f, 0.0f);
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.ThirdPerson);
|
||||
|
||||
// Calculate cube screen space position (with a little offset to be in top)
|
||||
cubeScreenPosition = GetWorldToScreen(
|
||||
new Vector3(cubePosition.X, cubePosition.Y + 2.5f, cubePosition.Z),
|
||||
camera
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
"Enemy: 100/100",
|
||||
(int)cubeScreenPosition.X - MeasureText("Enemy: 100/100", 20) / 2,
|
||||
(int)cubeScreenPosition.Y,
|
||||
20,
|
||||
Color.Black
|
||||
);
|
||||
|
||||
DrawText(
|
||||
$"Cube position in screen space coordinates: [{(int)cubeScreenPosition.X}, {(int)cubeScreenPosition.Y}]",
|
||||
10,
|
||||
10,
|
||||
20,
|
||||
Color.Lime
|
||||
);
|
||||
DrawText("Text 2d should be always on top of the cube", 10, 40, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - world screen");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
// 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.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
Vector2 cubeScreenPosition;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new WorldScreen();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
// Calculate cube screen space position (with a little offset to be in top)
|
||||
cubeScreenPosition = GetWorldToScreen(
|
||||
new Vector3(cubePosition.X, cubePosition.Y + 2.5f, cubePosition.Z),
|
||||
camera
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText(
|
||||
"Enemy: 100 / 100",
|
||||
(int)cubeScreenPosition.X - MeasureText("Enemy: 100 / 100", 20) / 2,
|
||||
(int)cubeScreenPosition.Y,
|
||||
20,
|
||||
Color.Black
|
||||
);
|
||||
DrawText(
|
||||
"Text is always on top of the cube",
|
||||
(screenWidth - MeasureText("Text is always on top of the cube", 20)) / 2,
|
||||
25,
|
||||
20,
|
||||
Color.Gray
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
53
Examples/ExampleRegistry.cs
Normal file
53
Examples/ExampleRegistry.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// Discovers every <see cref="IExample"/> implementation in this assembly via reflection:
|
||||
/// <see cref="DesktopExamples"/> (Program.cs) is all of them, <see cref="BrowserExamples"/>
|
||||
/// (Web/Host.cs) is everything not marked <see cref="ExcludeFromBrowserAttribute"/>.
|
||||
/// Ordering is by category (browser dropdown grouping), then display name.
|
||||
/// </summary>
|
||||
public static class ExampleRegistry
|
||||
{
|
||||
/// <summary>Category order used for the browser dropdown and desktop run-all sequence.</summary>
|
||||
private static readonly string[] CategoryOrder =
|
||||
[
|
||||
"Core",
|
||||
"Shapes",
|
||||
"Models",
|
||||
"Textures",
|
||||
"Text",
|
||||
"Audio",
|
||||
"Shaders",
|
||||
];
|
||||
|
||||
private static readonly IExample[] AllExamples = DiscoverAll();
|
||||
|
||||
public static readonly IExample[] DesktopExamples = AllExamples;
|
||||
|
||||
public static readonly IExample[] BrowserExamples =
|
||||
Array.FindAll(AllExamples, e => !e.GetType().IsDefined(typeof(ExcludeFromBrowserAttribute), inherit: false));
|
||||
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026",
|
||||
Justification = "The Examples assembly is rooted via TrimmerRootAssembly in Examples.csproj.")]
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2067",
|
||||
Justification = "Same as IL2026: all example types and their parameterless constructors are rooted.")]
|
||||
private static IExample[] DiscoverAll()
|
||||
{
|
||||
return typeof(IExample).Assembly
|
||||
.GetTypes()
|
||||
.Where(t => typeof(IExample).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
|
||||
.Select(t => (IExample)Activator.CreateInstance(t))
|
||||
.OrderBy(e => Array.IndexOf(CategoryOrder, Category(e)))
|
||||
.ThenBy(e => e.Name, StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// "Examples.Core" -> "Core"
|
||||
private static string Category(IExample example)
|
||||
{
|
||||
var ns = example.GetType().Namespace ?? "";
|
||||
return ns[(ns.LastIndexOf('.') + 1)..];
|
||||
}
|
||||
}
|
||||
|
|
@ -3,20 +3,54 @@
|
|||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<StartupObject>Examples.Program</StartupObject>
|
||||
<StartupObject Condition="'$(RuntimeIdentifier)' != 'browser-wasm'">Examples.Program</StartupObject>
|
||||
<StartupObject Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">Examples.Web.Host</StartupObject>
|
||||
<RunWorkingDirectory>$(MSBuildThisFileDirectory)</RunWorkingDirectory>
|
||||
<LangVersion>12</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
|
||||
<SelfContained>true</SelfContained>
|
||||
<WasmMainJSPath>Web/main.js</WasmMainJSPath>
|
||||
<Nullable>disable</Nullable>
|
||||
<!-- [JSExport] is browser-only by design; these files only compile for browser-wasm. -->
|
||||
<NoWarn>$(NoWarn);CA1416</NoWarn>
|
||||
<DefineConstants>$(DefineConstants);BROWSER</DefineConstants>
|
||||
|
||||
<!-- Link the native raylib.a (shipped by the Raylib-cs package) into the wasm module. -->
|
||||
<WasmBuildNative>true</WasmBuildNative>
|
||||
<WasmAllowUndefinedSymbols>true</WasmAllowUndefinedSymbols>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<EmccFlags>$(EmccFlags) -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=64MB</EmccFlags>
|
||||
|
||||
<!-- Avoid wasm-opt on SDK/workload combinations where Binaryen rejects bulk-memory-opt. -->
|
||||
<EmccLinkOptimizationFlag Condition="'$(EmccLinkOptimizationFlag)' == ''">-O0</EmccLinkOptimizationFlag>
|
||||
<EmccCompileOptimizationFlag Condition="'$(EmccCompileOptimizationFlag)' == ''">-O0</EmccCompileOptimizationFlag>
|
||||
<WasmNativeStrip Condition="'$(WasmNativeStrip)' == ''">false</WasmNativeStrip>
|
||||
<WasmEmitSymbolMap Condition="'$(WasmEmitSymbolMap)' == ''">false</WasmEmitSymbolMap>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Core/LoadingThread.cs"/>
|
||||
<Compile Remove="Text/Unicode.cs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' != 'browser-wasm'">
|
||||
<Compile Remove="Web/**/*.cs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
|
||||
<Compile Remove="Program.cs"/>
|
||||
<!-- Examples are discovered via reflection (ExampleRegistry);
|
||||
therefore they must be excluded from trimming. -->
|
||||
<TrimmerRootAssembly Include="Examples"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Raylib_cs"/>
|
||||
<Using Include="Raylib_cs.Raylib" Static="true"/>
|
||||
<Using Include="System.Numerics"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(UseRaylibCsPackage)' != 'true'">
|
||||
|
|
@ -27,8 +61,15 @@
|
|||
so the native raylib library is downloaded and copied to the output. -->
|
||||
<Import Project="..\Raylib-cs\Raylib-cs.targets" Condition="'$(UseRaylibCsPackage)' != 'true'"/>
|
||||
|
||||
<ItemGroup Condition="'$(UseRaylibCsPackage)' == 'true'">
|
||||
<PackageReference Include="Raylib-cs" Version="$(RaylibCsVersion)"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
|
||||
<WasmExtraFilesToDeploy Include="Web/index.html" TargetPath="index.html"/>
|
||||
<WasmExtraFilesToDeploy Include="Web/main.js" TargetPath="main.js"/>
|
||||
<WasmExtraFilesToDeploy Include="Web/scaleUtils.js" TargetPath="scaleUtils.js"/>
|
||||
<WasmExtraFilesToDeploy Include="..\Raylib-cs\logo\raylib-cs.ico" TargetPath="favicon.ico"/>
|
||||
|
||||
<!-- Bundle the example assets into the wasm virtual filesystem at /resources/...
|
||||
so examples load from "resources/..." work unchanged. -->
|
||||
<WasmFilesToIncludeInFileSystem Include="resources\**\*.*"
|
||||
TargetPath="resources\%(RecursiveDir)%(Filename)%(Extension)"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
17
Examples/ExcludeFromBrowserAttribute.cs
Normal file
17
Examples/ExcludeFromBrowserAttribute.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// Marks an <see cref="IExample"/> that is omitted from the browser host (Web/Host.cs)
|
||||
/// because of a wasm/WebGL platform limitation. Desktop runs are unaffected.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public sealed class ExcludeFromBrowserAttribute : Attribute
|
||||
{
|
||||
/// <summary>Why the example cannot run in the browser.</summary>
|
||||
public string Reason { get; }
|
||||
|
||||
public ExcludeFromBrowserAttribute(string reason = null)
|
||||
{
|
||||
Reason = reason;
|
||||
}
|
||||
}
|
||||
55
Examples/IExample.cs
Normal file
55
Examples/IExample.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// A runnable raylib example. Loop-spanning state lives in instance fields, (re)initialized in
|
||||
/// <see cref="Init"/> so re-selecting an example resets it.
|
||||
///
|
||||
/// <para>
|
||||
/// Desktop drives examples via <c>Program.cs</c> (each also keeps a thin standalone
|
||||
/// <c>static Main()</c>); in the browser, <c>Web/Host.cs</c> owns the single window and calls
|
||||
/// <see cref="Update"/> one frame at a time from JavaScript. Platform divergences are guarded
|
||||
/// with <c>#if BROWSER</c>, preferably around a single constant.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface IExample
|
||||
{
|
||||
/// <summary>Display name shown in the navigation dropdown.</summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>Window title, matching the example's standalone <c>Main()</c>.</summary>
|
||||
string Title { get; }
|
||||
|
||||
/// <summary>Desktop window size, matching the standalone <c>Main()</c>. The browser canvas is fixed at 800x450.</summary>
|
||||
int Width => 800;
|
||||
|
||||
/// <inheritdoc cref="Width"/>
|
||||
int Height => 450;
|
||||
|
||||
/// <summary>Config flags the desktop runner applies before window creation. Ignored in the browser.</summary>
|
||||
ConfigFlags ConfigFlags => 0;
|
||||
|
||||
/// <summary>Target FPS. The desktop runner always applies it; the browser host paces its frame loop with it.</summary>
|
||||
int TargetFps => 60;
|
||||
|
||||
/// <summary>Whether the desktop runner disables the cursor. Ignored in the browser (the pointer stays visible).</summary>
|
||||
bool CursorDisabled => false;
|
||||
|
||||
/// <summary>Whether the desktop runner hides the cursor. Ignored in the browser.</summary>
|
||||
bool CursorHidden => false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the desktop runner should exit its frame loop; defaults to
|
||||
/// <see cref="Raylib.WindowShouldClose"/>. Examples that intercept the close request
|
||||
/// override this and poll WindowShouldClose in <see cref="Update"/> themselves.
|
||||
/// </summary>
|
||||
bool ShouldClose => WindowShouldClose();
|
||||
|
||||
/// <summary>Set up the Example and preload necessary resources.</summary>
|
||||
void Init();
|
||||
|
||||
/// <summary>Render one frame, including BeginDrawing/EndDrawing.</summary>
|
||||
void Update();
|
||||
|
||||
/// <summary>Free resources.</summary>
|
||||
void Unload();
|
||||
}
|
||||
390
Examples/Models/AnimationBlendCustom.cs
Normal file
390
Examples/Models/AnimationBlendCustom.cs
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation blend custom
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by dmitrii-brand (@dmitrii-brand) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* DETAILS: Example demonstrates per-bone animation blending, allowing smooth transitions
|
||||
* between two animations by interpolating bone transforms. This is useful for:
|
||||
* - Blending movement animations (walk/run) with action animations (jump/attack)
|
||||
* - Creating smooth animation transitions
|
||||
* - Layering animations (e.g., upper body attack while lower body walks)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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) 2026 dmitrii-brand (@dmitrii-brand)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationBlendCustom : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation Blend Custom";
|
||||
|
||||
public string Title => "raylib [models] example - animation blend custom";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex0;
|
||||
private int animIndex1;
|
||||
private int animCurrentFrame0;
|
||||
private int animCurrentFrame1;
|
||||
private bool upperBodyBlend;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(4.0f, 4.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
model = LoadModel("resources/models/gltf/greenman.glb");
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load skinning shader
|
||||
// WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
// if not enabled, CPU skinning will be used instead
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
model.Materials[1].Shader = skinningShader;
|
||||
|
||||
// Load gltf model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animCount);
|
||||
|
||||
// Use specific animation indices: 2-walk/move, 3-attack
|
||||
animIndex0 = 2; // Walk/Move animation (index 2)
|
||||
animIndex1 = 3; // Attack animation (index 3)
|
||||
animCurrentFrame0 = 0;
|
||||
animCurrentFrame1 = 0;
|
||||
|
||||
// Validate indices
|
||||
if (animIndex0 >= animCount)
|
||||
{
|
||||
animIndex0 = 0;
|
||||
}
|
||||
if (animIndex1 >= animCount)
|
||||
{
|
||||
animIndex1 = (animCount > 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
upperBodyBlend = true; // Toggle: true = upper/lower body blending, false = uniform blending (50/50)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Toggle upper/lower body blending mode (SPACE key)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
upperBodyBlend = !upperBodyBlend;
|
||||
}
|
||||
|
||||
// Update animation frames
|
||||
var anim0 = anims[animIndex0];
|
||||
var anim1 = anims[animIndex1];
|
||||
|
||||
animCurrentFrame0 = (animCurrentFrame0 + 1) % anim0.KeyFrameCount;
|
||||
animCurrentFrame1 = (animCurrentFrame1 + 1) % anim1.KeyFrameCount;
|
||||
|
||||
// Blend the two animations
|
||||
// When upperBodyBlend is ON: upper body = attack (1.0), lower body = walk (0.0)
|
||||
// When upperBodyBlend is OFF: uniform blend at 0.5 (50% walk, 50% attack)
|
||||
var blendFactor = upperBodyBlend ? 1.0f : 0.5f;
|
||||
UpdateModelAnimationBones(anim0, animCurrentFrame0, anim1, animCurrentFrame1, blendFactor, upperBodyBlend);
|
||||
|
||||
// raylib provided animation blending function
|
||||
//UpdateModelAnimationEx(model, anim0, (float)animCurrentFrame0,
|
||||
// anim1, (float)animCurrentFrame1, blendFactor);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI
|
||||
DrawText($"ANIM 0: {anim0.NameToString()}", 10, 10, 20, Color.Gray);
|
||||
DrawText($"ANIM 1: {anim1.NameToString()}", 10, 40, 20, Color.Gray);
|
||||
DrawText($"[SPACE] Toggle blending mode: {(upperBodyBlend ? "Upper/Lower Body Blending" : "Uniform Blending")}",
|
||||
10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
// Check if a bone is part of upper body (for selective blending)
|
||||
private static bool IsUpperBodyBone(string boneName)
|
||||
{
|
||||
// Common upper body bone names (adjust based on your model)
|
||||
if (boneName is "spine" or "spine1" or "spine2" or
|
||||
"chest" or "upperChest" or
|
||||
"neck" or "head" or
|
||||
"shoulder" or "shoulder_L" or "shoulder_R" or
|
||||
"upperArm" or "upperArm_L" or "upperArm_R" or
|
||||
"lowerArm" or "lowerArm_L" or "lowerArm_R" or
|
||||
"hand" or "hand_L" or "hand_R" or
|
||||
"clavicle" or "clavicle_L" or "clavicle_R")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if bone name contains upper body keywords
|
||||
if (boneName.Contains("spine") || boneName.Contains("chest") ||
|
||||
boneName.Contains("neck") || boneName.Contains("head") ||
|
||||
boneName.Contains("shoulder") || boneName.Contains("arm") ||
|
||||
boneName.Contains("hand") || boneName.Contains("clavicle"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Blend two animations per-bone with selective upper/lower body blending
|
||||
private unsafe void UpdateModelAnimationBones(ModelAnimation anim0, int frame0,
|
||||
ModelAnimation anim1, int frame1, float blend, bool upperBodyBlend)
|
||||
{
|
||||
// Validate inputs
|
||||
if ((anim0.BoneCount != 0) && (anim0.KeyframePoses != null) &&
|
||||
(anim1.BoneCount != 0) && (anim1.KeyframePoses != null) &&
|
||||
(model.Skeleton.BoneCount != 0) && (model.Skeleton.BindPose != null))
|
||||
{
|
||||
// Clamp blend factor to [0, 1]
|
||||
blend = MathF.Min(1.0f, MathF.Max(0.0f, blend));
|
||||
|
||||
// Ensure frame indices are valid
|
||||
if (frame0 >= anim0.KeyFrameCount)
|
||||
{
|
||||
frame0 = anim0.KeyFrameCount - 1;
|
||||
}
|
||||
if (frame1 >= anim1.KeyFrameCount)
|
||||
{
|
||||
frame1 = anim1.KeyFrameCount - 1;
|
||||
}
|
||||
if (frame0 < 0)
|
||||
{
|
||||
frame0 = 0;
|
||||
}
|
||||
if (frame1 < 0)
|
||||
{
|
||||
frame1 = 0;
|
||||
}
|
||||
|
||||
// Get bone count (use minimum of all to be safe)
|
||||
var boneCount = model.Skeleton.BoneCount;
|
||||
if (anim0.BoneCount < boneCount)
|
||||
{
|
||||
boneCount = anim0.BoneCount;
|
||||
}
|
||||
if (anim1.BoneCount < boneCount)
|
||||
{
|
||||
boneCount = anim1.BoneCount;
|
||||
}
|
||||
|
||||
// Blend each bone
|
||||
for (var boneIndex = 0; boneIndex < boneCount; boneIndex++)
|
||||
{
|
||||
// Determine blend factor for this bone
|
||||
var boneBlendFactor = blend;
|
||||
|
||||
// If upper body blending is enabled, use different blend factors for upper vs lower body
|
||||
if (upperBodyBlend)
|
||||
{
|
||||
var boneName = model.Skeleton.Bones[boneIndex].NameToString();
|
||||
var isUpperBody = IsUpperBodyBone(boneName);
|
||||
|
||||
// Upper body: use anim1 (attack), Lower body: use anim0 (walk)
|
||||
// blend = 0.0 means full anim0 (walk), 1.0 means full anim1 (attack)
|
||||
if (isUpperBody)
|
||||
{
|
||||
boneBlendFactor = blend; // Upper body: blend towards anim1 (attack)
|
||||
}
|
||||
else
|
||||
{
|
||||
boneBlendFactor = 1.0f - blend; // Lower body: blend towards anim0 (walk) - invert the blend
|
||||
}
|
||||
}
|
||||
|
||||
// Get transforms from both animations
|
||||
var bindTransform = model.Skeleton.BindPose[boneIndex];
|
||||
var animTransform0 = anim0.KeyframePoses[frame0][boneIndex];
|
||||
var animTransform1 = anim1.KeyframePoses[frame1][boneIndex];
|
||||
|
||||
// Blend the transforms
|
||||
Transform blended = new();
|
||||
blended.Translation = Vector3Lerp(animTransform0.Translation, animTransform1.Translation, boneBlendFactor);
|
||||
blended.Rotation = QuaternionSlerp(animTransform0.Rotation, animTransform1.Rotation, boneBlendFactor);
|
||||
blended.Scale = Vector3Lerp(animTransform0.Scale, animTransform1.Scale, boneBlendFactor);
|
||||
|
||||
// Convert bind pose to matrix
|
||||
var bindMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(bindTransform.Scale.X, bindTransform.Scale.Y, bindTransform.Scale.Z),
|
||||
QuaternionToMatrix(bindTransform.Rotation)),
|
||||
MatrixTranslate(bindTransform.Translation.X, bindTransform.Translation.Y, bindTransform.Translation.Z));
|
||||
|
||||
// Convert blended transform to matrix
|
||||
var blendedMatrix = MatrixMultiply(MatrixMultiply(
|
||||
MatrixScale(blended.Scale.X, blended.Scale.Y, blended.Scale.Z),
|
||||
QuaternionToMatrix(blended.Rotation)),
|
||||
MatrixTranslate(blended.Translation.X, blended.Translation.Y, blended.Translation.Z));
|
||||
|
||||
// Calculate final bone matrix (similar to UpdateModelAnimationBones)
|
||||
model.BoneMatrices[boneIndex] = MatrixMultiply(MatrixInvert(bindMatrix), blendedMatrix);
|
||||
}
|
||||
|
||||
// CPU skinning, updates CPU buffers and uploads them to GPU (if available)
|
||||
// NOTE: Fallback in case GPU skinning is not supported or enabled
|
||||
for (var m = 0; m < model.MeshCount; m++)
|
||||
{
|
||||
var mesh = model.Meshes[m];
|
||||
Vector3 animVertex;
|
||||
Vector3 animNormal;
|
||||
var vertexValuesCount = mesh.VertexCount * 3;
|
||||
|
||||
var boneCounter = 0;
|
||||
var bufferUpdateRequired = false; // Flag to check when anim vertex information is updated
|
||||
|
||||
// Skip if missing bone data or missing anim buffers initialization
|
||||
if ((mesh.BoneWeights == null) || (mesh.BoneIndices == null) ||
|
||||
(mesh.AnimVertices == null) || (mesh.AnimNormals == null))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var vCounter = 0; vCounter < vertexValuesCount; vCounter += 3)
|
||||
{
|
||||
mesh.AnimVertices[vCounter] = 0;
|
||||
mesh.AnimVertices[vCounter + 1] = 0;
|
||||
mesh.AnimVertices[vCounter + 2] = 0;
|
||||
if (mesh.AnimNormals != null)
|
||||
{
|
||||
mesh.AnimNormals[vCounter] = 0;
|
||||
mesh.AnimNormals[vCounter + 1] = 0;
|
||||
mesh.AnimNormals[vCounter + 2] = 0;
|
||||
}
|
||||
|
||||
// Iterates over 4 bones per vertex
|
||||
for (var j = 0; j < 4; j++, boneCounter++)
|
||||
{
|
||||
var boneWeight = mesh.BoneWeights[boneCounter];
|
||||
var boneIndex = mesh.BoneIndices[boneCounter];
|
||||
|
||||
// Early stop when no transformation will be applied
|
||||
if (boneWeight == 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
animVertex = new Vector3(mesh.Vertices[vCounter], mesh.Vertices[vCounter + 1], mesh.Vertices[vCounter + 2]);
|
||||
animVertex = Vector3Transform(animVertex, model.BoneMatrices[boneIndex]);
|
||||
mesh.AnimVertices[vCounter] += animVertex.X * boneWeight;
|
||||
mesh.AnimVertices[vCounter + 1] += animVertex.Y * boneWeight;
|
||||
mesh.AnimVertices[vCounter + 2] += animVertex.Z * boneWeight;
|
||||
bufferUpdateRequired = true;
|
||||
|
||||
// Normals processing
|
||||
// NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
|
||||
if ((mesh.Normals != null) && (mesh.AnimNormals != null))
|
||||
{
|
||||
animNormal = new Vector3(mesh.Normals[vCounter], mesh.Normals[vCounter + 1], mesh.Normals[vCounter + 2]);
|
||||
animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.BoneMatrices[boneIndex])));
|
||||
mesh.AnimNormals[vCounter] += animNormal.X * boneWeight;
|
||||
mesh.AnimNormals[vCounter + 1] += animNormal.Y * boneWeight;
|
||||
mesh.AnimNormals[vCounter + 2] += animNormal.Z * boneWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bufferUpdateRequired)
|
||||
{
|
||||
// Update GPU vertex buffers with updated data (position + normals)
|
||||
Rlgl.UpdateVertexBuffer(mesh.VboId[(int)ShaderLocationIndex.VertexPosition], mesh.AnimVertices, mesh.VertexCount * 3 * sizeof(float), 0);
|
||||
if (mesh.Normals != null)
|
||||
{
|
||||
Rlgl.UpdateVertexBuffer(mesh.VboId[(int)ShaderLocationIndex.VertexNormal], mesh.AnimNormals, mesh.VertexCount * 3 * sizeof(float), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blend custom");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationBlendCustom();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
474
Examples/Models/AnimationBlending.cs
Normal file
474
Examples/Models/AnimationBlending.cs
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation blending
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Kirandeep (@Kirandeep-Singh-Khehra) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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-2026 Kirandeep (@Kirandeep-Singh-Khehra) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream example uses raygui for its UI controls (dropdowns, sliders, progress bars).
|
||||
// raygui is not part of raylib-cs, so the required controls are reimplemented here with
|
||||
// basic raylib drawing primitives, preserving the original behaviour.
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationBlending : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation Blending";
|
||||
|
||||
public string Title => "raylib [models] example - animation blending";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
|
||||
private int currentAnimPlaying;
|
||||
private int nextAnimToPlay;
|
||||
private bool animTransition;
|
||||
|
||||
private int animIndex0;
|
||||
private float animCurrentFrame0;
|
||||
private float animFrameSpeed0;
|
||||
private int animIndex1;
|
||||
private float animCurrentFrame1;
|
||||
private float animFrameSpeed1;
|
||||
|
||||
private float animBlendFactor;
|
||||
private float animBlendTime;
|
||||
private float animBlendTimeCounter;
|
||||
|
||||
private bool animPause;
|
||||
|
||||
private string[] animNames;
|
||||
private bool dropdownEditMode0;
|
||||
private bool dropdownEditMode1;
|
||||
private float animFrameProgress0;
|
||||
private float animFrameProgress1;
|
||||
private float animBlendProgress;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb"); // Load character model
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load skinning shader
|
||||
// NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
|
||||
// Skinning shader could be required to be assigned to all materials shaders, just to make
|
||||
// sure required uniforms are being updated for the mesh using that material (and shader)
|
||||
for (var i = 0; i < model.MaterialCount; i++)
|
||||
{
|
||||
model.Materials[i].Shader = skinningShader;
|
||||
}
|
||||
|
||||
// Load model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
// NOTE: Two animations are played with a smooth transition between them
|
||||
currentAnimPlaying = 0; // Current animation playing (0 o 1)
|
||||
nextAnimToPlay = 1; // Next animation to play (to transition)
|
||||
animTransition = false; // Flag to register anim transition state
|
||||
|
||||
animIndex0 = 10; // Current animation playing (walking)
|
||||
animCurrentFrame0 = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
animFrameSpeed0 = 0.5f; // Current animation play speed
|
||||
animIndex1 = 6; // Next animation to play (running)
|
||||
animCurrentFrame1 = 0.0f; // Next animation frame (supporting interpolated frames)
|
||||
animFrameSpeed1 = 0.5f; // Next animation play speed
|
||||
|
||||
animBlendFactor = 0.0f; // Blend factor from anim0[frame0] --> anim1[frame1], [0.0f..1.0f]
|
||||
|
||||
animBlendTime = 2.0f; // Time to blend from one playing animation to another (in seconds)
|
||||
animBlendTimeCounter = 0.0f; // Time counter (delta time)
|
||||
|
||||
animPause = false; // Pause animation
|
||||
|
||||
// UI required variables
|
||||
animNames = new string[animCount];
|
||||
for (var i = 0; i < animCount; i++)
|
||||
{
|
||||
animNames[i] = anims[i].NameToString();
|
||||
}
|
||||
|
||||
dropdownEditMode0 = false;
|
||||
dropdownEditMode1 = false;
|
||||
animFrameProgress0 = 0.0f;
|
||||
animFrameProgress1 = 0.0f;
|
||||
animBlendProgress = 0.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
animPause = !animPause;
|
||||
}
|
||||
|
||||
if (!animPause)
|
||||
{
|
||||
// Start transition from anim0[] to anim1[]
|
||||
if (IsKeyPressed(KeyboardKey.Space) && !animTransition)
|
||||
{
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
// Transition anim0 --> anim1
|
||||
nextAnimToPlay = 1;
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transition anim1 --> anim0
|
||||
nextAnimToPlay = 0;
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
|
||||
// Set animation transition
|
||||
animTransition = true;
|
||||
animBlendTimeCounter = 0.0f;
|
||||
animBlendFactor = 0.0f;
|
||||
}
|
||||
|
||||
if (animTransition)
|
||||
{
|
||||
// Playing anim0 and anim1 at the same time
|
||||
animCurrentFrame0 += animFrameSpeed0;
|
||||
if (animCurrentFrame0 >= anims[animIndex0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
animCurrentFrame1 += animFrameSpeed1;
|
||||
if (animCurrentFrame1 >= anims[animIndex1].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
|
||||
// Increment blend factor over time to transition from anim0 --> anim1 over time
|
||||
// NOTE: Time blending could be other than linear, using some easing
|
||||
animBlendFactor = animBlendTimeCounter / animBlendTime;
|
||||
animBlendTimeCounter += GetFrameTime();
|
||||
animBlendProgress = animBlendFactor;
|
||||
|
||||
// Update model with animations blending
|
||||
if (nextAnimToPlay == 1)
|
||||
{
|
||||
// Blend anim0 --> anim1
|
||||
UpdateModelAnimationEx(model, anims[animIndex0], animCurrentFrame0,
|
||||
anims[animIndex1], animCurrentFrame1, animBlendFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blend anim1 --> anim0
|
||||
UpdateModelAnimationEx(model, anims[animIndex1], animCurrentFrame1,
|
||||
anims[animIndex0], animCurrentFrame0, animBlendFactor);
|
||||
}
|
||||
|
||||
// Check if transition completed
|
||||
if (animBlendFactor > 1.0f)
|
||||
{
|
||||
// Reset frame states
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
else if (currentAnimPlaying == 1)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
currentAnimPlaying = nextAnimToPlay; // Update current animation playing
|
||||
|
||||
animBlendFactor = 0.0f; // Reset blend factor
|
||||
animTransition = false; // Exit transition mode
|
||||
animBlendTimeCounter = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play only one anim, the current one
|
||||
if (currentAnimPlaying == 0)
|
||||
{
|
||||
// Playing anim0 at defined speed
|
||||
animCurrentFrame0 += animFrameSpeed0;
|
||||
if (animCurrentFrame0 >= anims[animIndex0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame0 = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex0], animCurrentFrame0);
|
||||
}
|
||||
else if (currentAnimPlaying == 1)
|
||||
{
|
||||
// Playing anim1 at defined speed
|
||||
animCurrentFrame1 += animFrameSpeed1;
|
||||
if (animCurrentFrame1 >= anims[animIndex1].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame1 = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex1], animCurrentFrame1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress bars values with current frame for each animation
|
||||
animFrameProgress0 = animCurrentFrame0;
|
||||
animFrameProgress1 = animCurrentFrame1;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White); // Draw animated model
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
if (animTransition)
|
||||
{
|
||||
DrawText("ANIM TRANSITION BLENDING!", 170, 50, 30, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw UI elements
|
||||
//---------------------------------------------------------------------------------------------
|
||||
GuiSlider(new Rectangle(10, 38, 160, 12), null, $"x{animFrameSpeed0:0.0}", ref animFrameSpeed0, 0.1f, 2.0f);
|
||||
GuiSlider(new Rectangle(GetScreenWidth() - 170.0f, 38, 160, 12), $"{animFrameSpeed1:0.0}x", null, ref animFrameSpeed1, 0.1f, 2.0f);
|
||||
|
||||
// Blending process progress bar
|
||||
GuiProgressBar(new Rectangle(180, 14, 440, 16), null, null, animBlendProgress, 0.0f, 1.0f);
|
||||
|
||||
// Centered "PRESS SPACE" label
|
||||
const string spaceLabel = "PRESS SPACE to START BLENDING";
|
||||
var spaceLabelWidth = MeasureText(spaceLabel, 20);
|
||||
DrawText(spaceLabel, (GetScreenWidth() - spaceLabelWidth) / 2, (int)(GetScreenHeight() - 100.0f + 10), 20, Color.DarkGray);
|
||||
|
||||
// Draw playing timeline with keyframes for anim0[]
|
||||
GuiProgressBar(new Rectangle(60, GetScreenHeight() - 60.0f, GetScreenWidth() - 180.0f, 20), "ANIM 0",
|
||||
$"FRAME: {animFrameProgress0:0.00} / {anims[animIndex0].KeyFrameCount}",
|
||||
animFrameProgress0, 0.0f, anims[animIndex0].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex0].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180) / anims[animIndex0].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 60, 1, 20, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw playing timeline with keyframes for anim1[]
|
||||
GuiProgressBar(new Rectangle(60, GetScreenHeight() - 30.0f, GetScreenWidth() - 180.0f, 20), "ANIM 1",
|
||||
$"FRAME: {animFrameProgress1:0.00} / {anims[animIndex1].KeyFrameCount}",
|
||||
animFrameProgress1, 0.0f, anims[animIndex1].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex1].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(60 + (int)(((float)(GetScreenWidth() - 180) / anims[animIndex1].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 30, 1, 20, Color.Blue);
|
||||
}
|
||||
|
||||
// Draw animation selectors for blending transition (drawn last so open lists render on top)
|
||||
// NOTE: Transition does not start until requested
|
||||
if (GuiDropdownBox(new Rectangle(10, 10, 160, 24), animNames, ref animIndex0, dropdownEditMode0))
|
||||
{
|
||||
dropdownEditMode0 = !dropdownEditMode0;
|
||||
}
|
||||
if (GuiDropdownBox(new Rectangle(GetScreenWidth() - 170.0f, 10, 160, 24), animNames, ref animIndex1, dropdownEditMode1))
|
||||
{
|
||||
dropdownEditMode1 = !dropdownEditMode1;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
// Minimal immediate-mode slider (raygui replacement)
|
||||
private static bool GuiSlider(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
|
||||
{
|
||||
var mouse = GetMousePosition();
|
||||
var dragging = false;
|
||||
if (CheckCollisionPointRec(mouse, bounds) && IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
|
||||
if (value < minValue)
|
||||
{
|
||||
value = minValue;
|
||||
}
|
||||
if (value > maxValue)
|
||||
{
|
||||
value = maxValue;
|
||||
}
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = (value - minValue) / (maxValue - minValue);
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
return dragging;
|
||||
}
|
||||
|
||||
// Minimal immediate-mode progress bar (raygui replacement)
|
||||
private static void GuiProgressBar(Rectangle bounds, string textLeft, string textRight, float value, float minValue, float maxValue)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = maxValue > minValue ? (value - minValue) / (maxValue - minValue) : 0.0f;
|
||||
if (pct < 0)
|
||||
{
|
||||
pct = 0;
|
||||
}
|
||||
if (pct > 1)
|
||||
{
|
||||
pct = 1;
|
||||
}
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal immediate-mode dropdown box (raygui replacement)
|
||||
private static bool GuiDropdownBox(Rectangle bounds, string[] items, ref int active, bool editMode)
|
||||
{
|
||||
var result = false;
|
||||
var mouse = GetMousePosition();
|
||||
|
||||
// Draw main box
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (active >= 0 && active < items.Length)
|
||||
{
|
||||
DrawText(items[active], (int)bounds.X + 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
DrawText(editMode ? "^" : "v", (int)(bounds.X + bounds.Width - 12), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
|
||||
// Draw items when open
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
var hover = CheckCollisionPointRec(mouse, item);
|
||||
DrawRectangleRec(item, hover ? Color.SkyBlue : Color.LightGray);
|
||||
DrawRectangleLinesEx(item, 1, Color.Gray);
|
||||
DrawText(items[i], (int)item.X + 5, (int)(item.Y + item.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
if (CheckCollisionPointRec(mouse, item))
|
||||
{
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = true; // any click closes the dropdown
|
||||
}
|
||||
else if (CheckCollisionPointRec(mouse, bounds))
|
||||
{
|
||||
result = true; // open the dropdown
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation blending");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationBlending();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
160
Examples/Models/AnimationGpuSkinning.cs
Normal file
160
Examples/Models/AnimationGpuSkinning.cs
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation gpu skinning
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* WARNING: GPU skinning must be enabled in raylib with a compilation flag,
|
||||
* if not enabled, CPU skinning will be used instead
|
||||
*
|
||||
* 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 Daniel Holden (@orangeduck)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationGpuSkinning : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Animation GPU Skinning";
|
||||
|
||||
public string Title => "raylib [models] example - animation gpu skinning";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private Shader skinningShader;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private int animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
model = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load skinning shader
|
||||
// NOTE: It must be a valid shader, following raylib attribs/uniform conventions for GPU skinning
|
||||
skinningShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skinning.fs"
|
||||
);
|
||||
|
||||
// Skinning shader could be required to be assigned to all materials shaders, just to make
|
||||
// sure required uniforms are being updated for the mesh using that material (and shader)
|
||||
model.Materials[1].Shader = skinningShader; // Just assigning to materials[1] for this model
|
||||
|
||||
// Load gltf model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0; // Current animation frame
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
UnloadShader(skinningShader); // Unload GPU skinning shader
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation gpu skinning");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationGpuSkinning();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
292
Examples/Models/AnimationTiming.cs
Normal file
292
Examples/Models/AnimationTiming.cs
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - animation timing
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2026 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
// NOTE: The upstream example uses raygui for its UI controls (dropdown, slider, progress bar).
|
||||
// raygui is not part of raylib-cs, so the required controls are reimplemented here with
|
||||
// basic raylib drawing primitives, preserving the original behaviour.
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class AnimationTiming : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Animation Timing";
|
||||
|
||||
public string Title => "raylib [models] example - animation timing";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
private float animFrameSpeed;
|
||||
private bool animPause;
|
||||
private string[] animNames;
|
||||
private bool dropdownEditMode;
|
||||
private float animFrameProgress;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb");
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load model animations
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 10; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
animFrameSpeed = 0.5f; // Animation play speed
|
||||
animPause = false; // Pause animation
|
||||
|
||||
// UI required variables
|
||||
animNames = new string[animCount];
|
||||
for (var i = 0; i < animCount; i++)
|
||||
{
|
||||
animNames[i] = anims[i].NameToString();
|
||||
}
|
||||
|
||||
dropdownEditMode = false;
|
||||
animFrameProgress = 0.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
animPause = !animPause;
|
||||
}
|
||||
|
||||
if (!animPause && (animIndex < animCount))
|
||||
{
|
||||
// Update model animation
|
||||
animCurrentFrame += animFrameSpeed;
|
||||
if (animCurrentFrame >= anims[animIndex].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
}
|
||||
|
||||
// NOTE: Animation and playing speed selected through UI
|
||||
|
||||
// Update progressbar value with current frame
|
||||
animFrameProgress = animCurrentFrame;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI, select anim and playing speed
|
||||
GuiSlider(new Rectangle(260, 10, 500, 24), "FRAME SPEED: ", $"x{animFrameSpeed:0.0}", ref animFrameSpeed, 0.1f, 2.0f);
|
||||
|
||||
// Draw playing timeline with keyframes
|
||||
DrawText($"CURRENT FRAME: {animFrameProgress:0.00} / {anims[animIndex].KeyFrameCount}",
|
||||
10, (int)(GetScreenHeight() - 64.0f), 10, Color.DarkGray);
|
||||
GuiProgressBar(new Rectangle(10, GetScreenHeight() - 40.0f, GetScreenWidth() - 20.0f, 24), null, null,
|
||||
animFrameProgress, 0.0f, anims[animIndex].KeyFrameCount);
|
||||
for (var i = 0; i < anims[animIndex].KeyFrameCount; i++)
|
||||
{
|
||||
DrawRectangle(10 + (int)(((float)(GetScreenWidth() - 20) / anims[animIndex].KeyFrameCount) * i),
|
||||
GetScreenHeight() - 40, 1, 24, Color.Blue);
|
||||
}
|
||||
|
||||
// NOTE: Dropdown drawn last so its open item list renders on top
|
||||
if (GuiDropdownBox(new Rectangle(10, 10, 140, 24), animNames, ref animIndex, dropdownEditMode))
|
||||
{
|
||||
dropdownEditMode = !dropdownEditMode;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animation
|
||||
UnloadModel(model); // Unload model and meshes/material
|
||||
}
|
||||
|
||||
// Minimal immediate-mode slider (raygui replacement)
|
||||
private static bool GuiSlider(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
|
||||
{
|
||||
var mouse = GetMousePosition();
|
||||
var dragging = false;
|
||||
if (CheckCollisionPointRec(mouse, bounds) && IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
|
||||
if (value < minValue)
|
||||
{
|
||||
value = minValue;
|
||||
}
|
||||
if (value > maxValue)
|
||||
{
|
||||
value = maxValue;
|
||||
}
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = (value - minValue) / (maxValue - minValue);
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
return dragging;
|
||||
}
|
||||
|
||||
// Minimal immediate-mode progress bar (raygui replacement)
|
||||
private static void GuiProgressBar(Rectangle bounds, string textLeft, string textRight, float value, float minValue, float maxValue)
|
||||
{
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
var pct = maxValue > minValue ? (value - minValue) / (maxValue - minValue) : 0.0f;
|
||||
if (pct < 0)
|
||||
{
|
||||
pct = 0;
|
||||
}
|
||||
if (pct > 1)
|
||||
{
|
||||
pct = 1;
|
||||
}
|
||||
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (!string.IsNullOrEmpty(textLeft))
|
||||
{
|
||||
DrawText(textLeft, (int)(bounds.X - MeasureText(textLeft, 10) - 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(textRight))
|
||||
{
|
||||
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimal immediate-mode dropdown box (raygui replacement)
|
||||
private static bool GuiDropdownBox(Rectangle bounds, string[] items, ref int active, bool editMode)
|
||||
{
|
||||
var result = false;
|
||||
var mouse = GetMousePosition();
|
||||
|
||||
// Draw main box
|
||||
DrawRectangleRec(bounds, Color.LightGray);
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
if (active >= 0 && active < items.Length)
|
||||
{
|
||||
DrawText(items[active], (int)bounds.X + 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
DrawText(editMode ? "^" : "v", (int)(bounds.X + bounds.Width - 12), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
|
||||
|
||||
// Draw items when open
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
var hover = CheckCollisionPointRec(mouse, item);
|
||||
DrawRectangleRec(item, hover ? Color.SkyBlue : Color.LightGray);
|
||||
DrawRectangleLinesEx(item, 1, Color.Gray);
|
||||
DrawText(items[i], (int)item.X + 5, (int)(item.Y + item.Height / 2 - 5), 10, Color.DarkGray);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
if (editMode)
|
||||
{
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
Rectangle item = new(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
|
||||
if (CheckCollisionPointRec(mouse, item))
|
||||
{
|
||||
active = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = true; // any click closes the dropdown
|
||||
}
|
||||
else if (CheckCollisionPointRec(mouse, bounds))
|
||||
{
|
||||
result = true; // open the dropdown
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - animation timing");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AnimationTiming();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
202
Examples/Models/BasicVoxel.cs
Normal file
202
Examples/Models/BasicVoxel.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - basic voxel
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Tim Little (@timlittle) 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 Tim Little (@timlittle)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class BasicVoxel : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int WorldSize = 8; // Size of our voxel world (8x8x8 cubes)
|
||||
|
||||
public string Name => "Models / Basic Voxel";
|
||||
|
||||
public string Title => "raylib [models] example - basic voxel";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model cubeModel;
|
||||
private bool[,,] voxels;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world (first person)
|
||||
camera = new();
|
||||
camera.Position = new Vector3(-2.0f, 0.0f, -2.0f); // Camera position at ground level
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Create a cube model
|
||||
var cubeMesh = GenMeshCube(1.0f, 1.0f, 1.0f); // Create a unit cube mesh
|
||||
cubeModel = LoadModelFromMesh(cubeMesh); // Convert mesh to a model
|
||||
cubeModel.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Beige;
|
||||
|
||||
// Initialize voxel world - fill with voxels
|
||||
voxels = new bool[WorldSize, WorldSize, WorldSize];
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
voxels[x, y, z] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
// Handle voxel removal with mouse click
|
||||
// This method is quite inefficient. Ray marching through the voxel grid using DDA would be faster, but more complex.
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Cast a ray from the screen center (where crosshair would be)
|
||||
Vector2 screenCenter = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
|
||||
var ray = GetScreenToWorldRay(screenCenter, camera);
|
||||
|
||||
// Check ray collision with all voxels
|
||||
var closestDistance = 99999.0f;
|
||||
Vector3 closestVoxelPosition = new(-1, -1, -1);
|
||||
var voxelFound = false;
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
if (!voxels[x, y, z])
|
||||
{
|
||||
continue; // Skip empty voxels
|
||||
}
|
||||
|
||||
// Build a bounding box for this voxel
|
||||
Vector3 position = new(x, y, z);
|
||||
BoundingBox box = new(
|
||||
new Vector3(position.X - 0.5f, position.Y - 0.5f, position.Z - 0.5f),
|
||||
new Vector3(position.X + 0.5f, position.Y + 0.5f, position.Z + 0.5f)
|
||||
);
|
||||
|
||||
// Check ray-box collision
|
||||
var collision = GetRayCollisionBox(ray, box);
|
||||
if (collision.Hit && (collision.Distance < closestDistance))
|
||||
{
|
||||
closestDistance = collision.Distance;
|
||||
closestVoxelPosition = new Vector3(x, y, z);
|
||||
voxelFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the closest voxel if one was hit
|
||||
if (voxelFound)
|
||||
{
|
||||
voxels[(int)closestVoxelPosition.X,
|
||||
(int)closestVoxelPosition.Y,
|
||||
(int)closestVoxelPosition.Z] = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw all voxels
|
||||
for (var x = 0; x < WorldSize; x++)
|
||||
{
|
||||
for (var y = 0; y < WorldSize; y++)
|
||||
{
|
||||
for (var z = 0; z < WorldSize; z++)
|
||||
{
|
||||
if (!voxels[x, y, z])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 position = new(x, y, z);
|
||||
DrawModel(cubeModel, position, 1.0f, Color.Beige);
|
||||
DrawCubeWires(position, 1.0f, 1.0f, 1.0f, Color.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw reference point for raycasting to delete blocks
|
||||
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 4, Color.Red);
|
||||
|
||||
DrawText("Left-click a voxel to remove it!", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("WASD to move, mouse to look around", 10, 35, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(cubeModel);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - basic voxel");
|
||||
|
||||
DisableCursor(); // Lock mouse to window center
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicVoxel();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Drawing billboards
|
||||
* raylib [models] example - billboard rendering
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 3.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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,121 +18,131 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class BillboardDemo
|
||||
public partial class BillboardDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Billboard Demo";
|
||||
|
||||
public string Title => "raylib [models] example - billboard rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D bill;
|
||||
private Vector3 billPositionStatic;
|
||||
private Vector3 billPositionRotating;
|
||||
private Rectangle source;
|
||||
private Vector3 billUp;
|
||||
private Vector2 size;
|
||||
private Vector2 origin;
|
||||
private float distanceStatic;
|
||||
private float distanceRotating;
|
||||
private float rotation;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
bill = LoadTexture("resources/billboard.png"); // Our billboard texture
|
||||
billPositionStatic = new(0.0f, 2.0f, 0.0f); // Position of static billboard
|
||||
billPositionRotating = new(1.0f, 2.0f, 1.0f); // Position of rotating billboard
|
||||
|
||||
// Entire billboard texture, source is used to take a segment from a larger texture
|
||||
source = new(0.0f, 0.0f, (float)bill.Width, (float)bill.Height);
|
||||
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
billUp = new(0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Set the height of the rotating billboard to 1.0 with the aspect ratio fixed
|
||||
size = new(source.Width / source.Height, 1.0f);
|
||||
|
||||
// Rotate around origin
|
||||
// Here we choose to rotate around the image center
|
||||
origin = size * 0.5f;
|
||||
|
||||
// Distance is needed for the correct billboard draw order
|
||||
// Larger distance (further away from the camera) should be drawn prior to smaller distance
|
||||
distanceStatic = 0.0f;
|
||||
distanceRotating = 0.0f;
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
rotation += 0.4f;
|
||||
distanceStatic = Vector3.Distance(camera.Position, billPositionStatic);
|
||||
distanceRotating = Vector3.Distance(camera.Position, billPositionRotating);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
// Draw order matters!
|
||||
if (distanceStatic > distanceRotating)
|
||||
{
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, Color.White);
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(bill); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - billboard rendering");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(5.0f, 4.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Our texture billboard
|
||||
Texture2D bill = LoadTexture("resources/billboard.png");
|
||||
|
||||
// Position of billboard billboard
|
||||
Vector3 billPositionStatic = new(0.0f, 2.0f, 0.0f);
|
||||
Vector3 billPositionRotating = new(1.0f, 2.0f, 1.0f);
|
||||
|
||||
// Entire billboard texture, source is used to take a segment from a larger texture.
|
||||
Rectangle source = new(0.0f, 0.0f, (float)bill.Width, (float)bill.Height);
|
||||
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
Vector3 billUp = new(0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Rotate around origin
|
||||
// Here we choose to rotate around the image center
|
||||
// NOTE: (-1, 1) is the range where origin.X, origin.Y is inside the texture
|
||||
Vector2 rotateOrigin = Vector2.Zero;
|
||||
|
||||
// Distance is needed for the correct billboard draw order
|
||||
// Larger distance (further away from the camera) should be drawn prior to smaller distance.
|
||||
float distanceStatic = 0.0f;
|
||||
float distanceRotating = 0.0f;
|
||||
|
||||
float rotation = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BillboardDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
rotation += 0.4f;
|
||||
distanceStatic = Vector3.Distance(camera.Position, billPositionStatic);
|
||||
distanceRotating = Vector3.Distance(camera.Position, billPositionRotating);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw order matters!
|
||||
if (distanceStatic > distanceRotating)
|
||||
{
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
DrawBillboardPro(
|
||||
camera,
|
||||
bill,
|
||||
source,
|
||||
billPositionRotating,
|
||||
billUp,
|
||||
new Vector2(1.0f, 1.0f),
|
||||
rotateOrigin,
|
||||
rotation,
|
||||
Color.White
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBillboardPro(
|
||||
camera,
|
||||
bill,
|
||||
source,
|
||||
billPositionRotating,
|
||||
billUp,
|
||||
new Vector2(1.0f, 1.0f),
|
||||
rotateOrigin,
|
||||
rotation,
|
||||
Color.White
|
||||
);
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, Color.White);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(bill);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
246
Examples/Models/BoneSocket.cs
Normal file
246
Examples/Models/BoneSocket.cs
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - bone socket
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.5
|
||||
*
|
||||
* Example contributed by iP (@ipzaur) 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) 2024-2025 iP (@ipzaur)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class BoneSocket : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BoneSockets = 3;
|
||||
private const int BoneSocketHat = 0;
|
||||
private const int BoneSocketHandR = 1;
|
||||
private const int BoneSocketHandL = 2;
|
||||
|
||||
public string Name => "Models / Bone Socket";
|
||||
|
||||
public string Title => "raylib [models] example - bone socket";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model characterModel;
|
||||
private Model[] equipModel;
|
||||
private bool[] showEquip;
|
||||
private int animsCount;
|
||||
private int animIndex;
|
||||
private int animCurrentFrame;
|
||||
private unsafe ModelAnimation* modelAnimations;
|
||||
private int[] boneSocketIndex;
|
||||
private Vector3 position;
|
||||
private int angle;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load gltf model
|
||||
characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
|
||||
equipModel = new Model[BoneSockets]
|
||||
{
|
||||
LoadModel("resources/models/gltf/greenman_hat.glb"), // Index for the hat model is the same as BONE_SOCKET_HAT
|
||||
LoadModel("resources/models/gltf/greenman_sword.glb"), // Index for the sword model is the same as BONE_SOCKET_HAND_R
|
||||
LoadModel("resources/models/gltf/greenman_shield.glb") // Index for the shield model is the same as BONE_SOCKET_HAND_L
|
||||
};
|
||||
|
||||
showEquip = new bool[3] { true, true, true }; // Toggle on/off equip
|
||||
|
||||
// Load gltf model animations
|
||||
animsCount = 0;
|
||||
animIndex = 0;
|
||||
animCurrentFrame = 0;
|
||||
modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", ref animsCount);
|
||||
|
||||
// Indices of bones for sockets
|
||||
boneSocketIndex = new int[BoneSockets] { -1, -1, -1 };
|
||||
|
||||
// Search bones for sockets
|
||||
for (var i = 0; i < characterModel.Skeleton.BoneCount; i++)
|
||||
{
|
||||
var boneName = characterModel.Skeleton.Bones[i].NameToString();
|
||||
|
||||
if (boneName == "socket_hat")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHat] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boneName == "socket_hand_R")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHandR] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boneName == "socket_hand_L")
|
||||
{
|
||||
boneSocketIndex[BoneSocketHandL] = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
angle = 0; // Set angle for rotate character
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.ThirdPerson);
|
||||
|
||||
// Rotate character
|
||||
if (IsKeyDown(KeyboardKey.F))
|
||||
{
|
||||
angle = (angle + 1) % 360;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.H))
|
||||
{
|
||||
angle = (360 + angle - 1) % 360;
|
||||
}
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.T))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animsCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
animIndex = (animIndex + animsCount - 1) % animsCount;
|
||||
}
|
||||
|
||||
// Toggle shown of equip
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
showEquip[BoneSocketHat] = !showEquip[BoneSocketHat];
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
showEquip[BoneSocketHandR] = !showEquip[BoneSocketHandR];
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
showEquip[BoneSocketHandL] = !showEquip[BoneSocketHandL];
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
var anim = modelAnimations[animIndex];
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anim.KeyFrameCount;
|
||||
UpdateModelAnimation(characterModel, anim, animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw character
|
||||
var characterRotate = QuaternionFromAxisAngle(new Vector3(0.0f, 1.0f, 0.0f), angle * DEG2RAD);
|
||||
characterModel.Transform = MatrixMultiply(QuaternionToMatrix(characterRotate), MatrixTranslate(position.X, position.Y, position.Z));
|
||||
UpdateModelAnimation(characterModel, anim, animCurrentFrame);
|
||||
DrawMesh(characterModel.Meshes[0], characterModel.Materials[1], characterModel.Transform);
|
||||
|
||||
// Draw equipments (hat, sword, shield)
|
||||
for (var i = 0; i < BoneSockets; i++)
|
||||
{
|
||||
if (!showEquip[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var transform = &anim.KeyframePoses[animCurrentFrame][boneSocketIndex[i]];
|
||||
var inRotation = characterModel.Skeleton.BindPose[boneSocketIndex[i]].Rotation;
|
||||
var outRotation = transform->Rotation;
|
||||
|
||||
// Calculate socket rotation (angle between bone in initial pose and same bone in current animation frame)
|
||||
var rotate = QuaternionMultiply(outRotation, QuaternionInvert(inRotation));
|
||||
var matrixTransform = QuaternionToMatrix(rotate);
|
||||
// Translate socket to its position in the current animation
|
||||
matrixTransform = MatrixMultiply(matrixTransform, MatrixTranslate(transform->Translation.X, transform->Translation.Y, transform->Translation.Z));
|
||||
// Transform the socket using the transform of the character (angle and translate)
|
||||
matrixTransform = MatrixMultiply(matrixTransform, characterModel.Transform);
|
||||
|
||||
// Draw mesh at socket position with socket angle rotation
|
||||
DrawMesh(equipModel[i].Meshes[0], equipModel[i].Materials[1], matrixTransform);
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Use the T/G to switch animation", 10, 10, 20, Color.Gray);
|
||||
DrawText("Use the F/H to rotate character left/right", 10, 35, 20, Color.Gray);
|
||||
DrawText("Use the 1,2,3 to toggle shown of hat, sword and shield", 10, 60, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(modelAnimations, animsCount);
|
||||
UnloadModel(characterModel); // Unload character model and meshes/material
|
||||
|
||||
// Unload equipment model and meshes/material
|
||||
for (var i = 0; i < BoneSockets; i++)
|
||||
{
|
||||
UnloadModel(equipModel[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - bone socket");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BoneSocket();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Detect basic 3d collisions (box vs sphere vs box)
|
||||
* raylib [models] example - box collisions
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 3.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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,129 +18,165 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class BoxCollisions
|
||||
public partial class BoxCollisions : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Box Collisions";
|
||||
|
||||
public string Title => "raylib [models] example - box collisions";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private Vector3 playerPosition;
|
||||
private Vector3 playerSize;
|
||||
private Color playerColor;
|
||||
|
||||
private Vector3 enemyBoxPos;
|
||||
private Vector3 enemyBoxSize;
|
||||
|
||||
private Vector3 enemySpherePos;
|
||||
private float enemySphereSize;
|
||||
|
||||
private bool collision;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 playerPosition = new(0.0f, 1.0f, 2.0f);
|
||||
Vector3 playerSize = new(1.0f, 2.0f, 1.0f);
|
||||
Color playerColor = Color.Green;
|
||||
playerPosition = new(0.0f, 1.0f, 2.0f);
|
||||
playerSize = new(1.0f, 2.0f, 1.0f);
|
||||
playerColor = Color.Green;
|
||||
|
||||
Vector3 enemyBoxPos = new(-4.0f, 1.0f, 0.0f);
|
||||
Vector3 enemyBoxSize = new(2.0f, 2.0f, 2.0f);
|
||||
enemyBoxPos = new(-4.0f, 1.0f, 0.0f);
|
||||
enemyBoxSize = new(2.0f, 2.0f, 2.0f);
|
||||
|
||||
Vector3 enemySpherePos = new(4.0f, 0.0f, 0.0f);
|
||||
float enemySphereSize = 1.5f;
|
||||
enemySpherePos = new(4.0f, 0.0f, 0.0f);
|
||||
enemySphereSize = 1.5f;
|
||||
|
||||
bool collision = false;
|
||||
collision = false;
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Move player
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
playerPosition.X += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
playerPosition.X -= 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
playerPosition.Z += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
playerPosition.Z -= 0.2f;
|
||||
}
|
||||
|
||||
collision = false;
|
||||
|
||||
// Check collisions player vs enemy-box
|
||||
BoundingBox box1 = new(
|
||||
playerPosition - (playerSize / 2),
|
||||
playerPosition + (playerSize / 2)
|
||||
);
|
||||
BoundingBox box2 = new(
|
||||
enemyBoxPos - (enemyBoxSize / 2),
|
||||
enemyBoxPos + (enemyBoxSize / 2)
|
||||
);
|
||||
|
||||
if (CheckCollisionBoxes(box1, box2))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
// Check collisions player vs enemy-sphere
|
||||
if (CheckCollisionBoxSphere(box1, enemySpherePos, enemySphereSize))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
if (collision)
|
||||
{
|
||||
playerColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
playerColor = Color.Green;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw enemy-box
|
||||
DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.Gray);
|
||||
DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.DarkGray);
|
||||
|
||||
// Draw enemy-sphere
|
||||
DrawSphere(enemySpherePos, enemySphereSize, Color.Gray);
|
||||
DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, Color.DarkGray);
|
||||
|
||||
// Draw player
|
||||
DrawCubeV(playerPosition, playerSize, playerColor);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Move player with arrow keys to collide", 220, 40, 20, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BoxCollisions();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Move player
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
playerPosition.X += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
playerPosition.X -= 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
playerPosition.Z += 0.2f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
playerPosition.Z -= 0.2f;
|
||||
}
|
||||
|
||||
collision = false;
|
||||
|
||||
// Check collisions player vs enemy-box
|
||||
BoundingBox box1 = new(
|
||||
playerPosition - (playerSize / 2),
|
||||
playerPosition + (playerSize / 2)
|
||||
);
|
||||
BoundingBox box2 = new(
|
||||
enemyBoxPos - (enemyBoxSize / 2),
|
||||
enemyBoxPos + (enemyBoxSize / 2)
|
||||
);
|
||||
|
||||
if (CheckCollisionBoxes(box1, box2))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
// Check collisions player vs enemy-sphere
|
||||
if (CheckCollisionBoxSphere(box1, enemySpherePos, enemySphereSize))
|
||||
{
|
||||
collision = true;
|
||||
}
|
||||
|
||||
if (collision)
|
||||
{
|
||||
playerColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
playerColor = Color.Green;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw enemy-box
|
||||
DrawCube(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.Gray);
|
||||
DrawCubeWires(enemyBoxPos, enemyBoxSize.X, enemyBoxSize.Y, enemyBoxSize.Z, Color.DarkGray);
|
||||
|
||||
// Draw enemy-sphere
|
||||
DrawSphere(enemySpherePos, enemySphereSize, Color.Gray);
|
||||
DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, Color.DarkGray);
|
||||
|
||||
// Draw player
|
||||
DrawCubeV(playerPosition, playerSize, playerColor);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Move player with cursors to collide", 220, 40, 20, Color.Gray);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Cubicmap loading and drawing
|
||||
* raylib [models] example - cubicmap rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 3.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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,91 +18,128 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class CubicmapDemo
|
||||
public partial class CubicmapDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Cubicmap Demo";
|
||||
|
||||
public string Title => "raylib [models] example - cubicmap rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D cubicmap;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Vector3 mapPosition;
|
||||
private bool pause;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(16.0f, 14.0f, 16.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(16.0f, 14.0f, 16.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image image = LoadImage("resources/cubicmap.png");
|
||||
Texture2D cubicmap = LoadTextureFromImage(image);
|
||||
var image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM)
|
||||
cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM)
|
||||
|
||||
Mesh mesh = GenMeshCubicmap(image, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var mesh = GenMeshCubicmap(image, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
model = LoadModelFromMesh(mesh);
|
||||
|
||||
// NOTE: By default each cube is mapped to one part of texture atlas
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 mapPosition = new(-16.0f, 0.0f, -8.0f);
|
||||
UnloadImage(image);
|
||||
mapPosition = new(-16.0f, 0.0f, -8.0f); // Set model position
|
||||
|
||||
SetTargetFPS(60);
|
||||
UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM
|
||||
|
||||
pause = false; // Pause camera orbital rotation (and zoom)
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
}
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Vector2 position = new(screenWidth - cubicmap.Width * 4 - 20, 20);
|
||||
DrawTextureEx(cubicmap, position, 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(
|
||||
screenWidth - cubicmap.Width * 4 - 20,
|
||||
20,
|
||||
cubicmap.Width * 4,
|
||||
cubicmap.Height * 4,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
DrawText("cubicmap image used to", 658, 90, 10, Color.Gray);
|
||||
DrawText("generate map 3d model", 658, 104, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(cubicmap); // Unload cubicmap texture
|
||||
UnloadTexture(texture); // Unload map texture
|
||||
UnloadModel(model); // Unload map model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - cubicmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CubicmapDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Vector2 position = new(screenWidth - cubicmap.Width * 4 - 20, 20);
|
||||
DrawTextureEx(cubicmap, position, 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(
|
||||
screenWidth - cubicmap.Width * 4 - 20,
|
||||
20,
|
||||
cubicmap.Width * 4,
|
||||
cubicmap.Height * 4,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
DrawText("cubicmap image used to", 658, 90, 10, Color.Gray);
|
||||
DrawText("generate map 3d model", 658, 104, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(cubicmap);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
592
Examples/Models/Decals.cs
Normal file
592
Examples/Models/Decals.cs
Normal file
|
|
@ -0,0 +1,592 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - decals
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Based on previous work by @mrdoob
|
||||
*
|
||||
* 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 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class Decals : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxDecals = 256;
|
||||
|
||||
public string Name => "Models / Decals";
|
||||
|
||||
public string Title => "raylib [models] example - decals";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D modelTexture;
|
||||
private BoundingBox modelBBox;
|
||||
private float decalSize;
|
||||
private float decalOffset;
|
||||
private Model placementCube;
|
||||
private Material decalMaterial;
|
||||
private Texture2D decalTexture;
|
||||
private bool showModel;
|
||||
private readonly List<Model> decalModels = new();
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.6f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load character model
|
||||
model = LoadModel("resources/models/obj/character.obj");
|
||||
|
||||
// Apply character skin
|
||||
modelTexture = LoadTexture("resources/models/obj/character_diffuse.png");
|
||||
SetTextureFilter(modelTexture, TextureFilter.Bilinear);
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = modelTexture;
|
||||
|
||||
modelBBox = GetMeshBoundingBox(model.Meshes[0]); // Get mesh bounding box
|
||||
|
||||
camera.Target = Vector3Lerp(modelBBox.Min, modelBBox.Max, 0.5f);
|
||||
camera.Position = modelBBox.Max * 1.0f;
|
||||
camera.Position.X *= 0.1f;
|
||||
|
||||
var modelSize = MathF.Min(
|
||||
MathF.Min(MathF.Abs(modelBBox.Max.X - modelBBox.Min.X), MathF.Abs(modelBBox.Max.Y - modelBBox.Min.Y)),
|
||||
MathF.Abs(modelBBox.Max.Z - modelBBox.Min.Z));
|
||||
|
||||
camera.Position = new Vector3(0.0f, modelBBox.Max.Y * 1.2f, modelSize * 3.0f);
|
||||
|
||||
decalSize = modelSize * 0.25f;
|
||||
decalOffset = 0.01f;
|
||||
|
||||
placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
|
||||
placementCube.Materials[0].Maps[0].Color = Color.Lime;
|
||||
|
||||
decalMaterial = LoadMaterialDefault();
|
||||
decalMaterial.Maps[0].Color = Color.Yellow;
|
||||
|
||||
var decalImage = LoadImage("resources/raylib_logo.png");
|
||||
ImageResizeNN(ref decalImage, decalImage.Width / 4, decalImage.Height / 4);
|
||||
decalTexture = LoadTextureFromImage(decalImage);
|
||||
UnloadImage(decalImage);
|
||||
|
||||
SetTextureFilter(decalTexture, TextureFilter.Bilinear);
|
||||
decalMaterial.Maps[(int)MaterialMapIndex.Diffuse].Texture = decalTexture;
|
||||
decalMaterial.Maps[(int)MaterialMapIndex.Diffuse].Color = Color.RayWhite;
|
||||
|
||||
showModel = true;
|
||||
decalModels.Clear();
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.ThirdPerson);
|
||||
}
|
||||
|
||||
// Display information about closest hit
|
||||
RayCollision collision = new();
|
||||
collision.Distance = float.MaxValue;
|
||||
collision.Hit = false;
|
||||
|
||||
// Get mouse ray
|
||||
var ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||
var boxHitInfo = GetRayCollisionBox(ray, modelBBox);
|
||||
|
||||
RayCollision meshHitInfo = new();
|
||||
if (boxHitInfo.Hit && (decalModels.Count < MaxDecals))
|
||||
{
|
||||
// Check ray collision against model meshes
|
||||
for (var m = 0; m < model.MeshCount; m++)
|
||||
{
|
||||
// NOTE: We consider the model.transform for the collision check but
|
||||
// it can be checked against any transform Matrix, used when checking against same
|
||||
// model drawn multiple times with multiple transforms
|
||||
meshHitInfo = GetRayCollisionMesh(ray, model.Meshes[m], model.Transform);
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
// Save the closest hit mesh
|
||||
if (!collision.Hit || (collision.Distance > meshHitInfo.Distance))
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Add decal to mesh on hit point
|
||||
if (collision.Hit && IsMouseButtonPressed(MouseButton.Left) && (decalModels.Count < MaxDecals))
|
||||
{
|
||||
// Create the transformation to project the decal
|
||||
var origin = collision.Point + (collision.Normal * 1.0f);
|
||||
var splat = MatrixLookAt(collision.Point, origin, new Vector3(0.0f, 1.0f, 0.0f));
|
||||
|
||||
// Spin the placement around a bit
|
||||
splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD * GetRandomValue(-180, 180)));
|
||||
|
||||
var decalMesh = GenMeshDecal(model, splat, decalSize, decalOffset);
|
||||
|
||||
if (decalMesh.VertexCount > 0)
|
||||
{
|
||||
var decalModel = LoadModelFromMesh(decalMesh);
|
||||
decalModel.Materials[0].Maps[0] = decalMaterial.Maps[0];
|
||||
decalModels.Add(decalModel);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the model at the origin and default scale
|
||||
if (showModel)
|
||||
{
|
||||
DrawModel(model, new Vector3(0.0f, 0.0f, 0.0f), 1.0f, Color.White);
|
||||
}
|
||||
|
||||
// Draw the decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
DrawModel(decalModels[i], Vector3.Zero, 1.0f, Color.White);
|
||||
}
|
||||
|
||||
// If we hit the mesh, draw the box for the decal
|
||||
if (collision.Hit)
|
||||
{
|
||||
var origin = collision.Point + (collision.Normal * 1.0f);
|
||||
var splat = MatrixLookAt(collision.Point, origin, new Vector3(0, 1, 0));
|
||||
placementCube.Transform = MatrixInvert(splat);
|
||||
DrawModel(placementCube, Vector3.Zero, 1.0f, Fade(Color.White, 0.5f));
|
||||
}
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
EndMode3D();
|
||||
|
||||
float yPos = 10;
|
||||
var x0 = GetScreenWidth() - 300.0f;
|
||||
var x1 = x0 + 100;
|
||||
var x2 = x1 + 100;
|
||||
|
||||
DrawText("Vertices", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText("Triangles", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
var vertexCount = 0;
|
||||
var triangleCount = 0;
|
||||
|
||||
for (var i = 0; i < model.MeshCount; i++)
|
||||
{
|
||||
vertexCount += model.Meshes[i].VertexCount;
|
||||
triangleCount += model.Meshes[i].TriangleCount;
|
||||
}
|
||||
|
||||
DrawText("Main model", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{vertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{triangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
if (i == 20)
|
||||
{
|
||||
DrawText("...", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
}
|
||||
|
||||
if (i < 20)
|
||||
{
|
||||
DrawText($"Decal #{i + 1}", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{decalModels[i].Meshes[0].VertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{decalModels[i].Meshes[0].TriangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
}
|
||||
|
||||
vertexCount += decalModels[i].Meshes[0].VertexCount;
|
||||
triangleCount += decalModels[i].Meshes[0].TriangleCount;
|
||||
}
|
||||
|
||||
DrawText("TOTAL", (int)x0, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{vertexCount}", (int)x1, (int)yPos, 10, Color.Lime);
|
||||
DrawText($"{triangleCount}", (int)x2, (int)yPos, 10, Color.Lime);
|
||||
yPos += 15;
|
||||
|
||||
DrawText("Hold RMB to move camera", 10, 430, 10, Color.Gray);
|
||||
DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
// UI elements
|
||||
if (GuiButton(new Rectangle(10, screenHeight - 1000.0f, 100, 60), showModel ? "Hide Model" : "Show Model"))
|
||||
{
|
||||
showModel = !showModel;
|
||||
}
|
||||
|
||||
if (GuiButton(new Rectangle(10 + 110, screenHeight - 100.0f, 100, 60), "Clear Decals"))
|
||||
{
|
||||
// Clear decals, unload all decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
UnloadModel(decalModels[i]);
|
||||
}
|
||||
decalModels.Clear();
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
UnloadTexture(modelTexture);
|
||||
|
||||
// Unload decal models
|
||||
for (var i = 0; i < decalModels.Count; i++)
|
||||
{
|
||||
UnloadModel(decalModels[i]);
|
||||
}
|
||||
decalModels.Clear();
|
||||
|
||||
UnloadTexture(decalTexture);
|
||||
UnloadModel(placementCube);
|
||||
}
|
||||
|
||||
// Clip segment
|
||||
private static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
|
||||
{
|
||||
var d0 = Vector3.Dot(v0, p) - s;
|
||||
var d1 = Vector3.Dot(v1, p) - s;
|
||||
var s0 = d0 / (d0 - d1);
|
||||
|
||||
return Vector3.Lerp(v0, v1, s0);
|
||||
}
|
||||
|
||||
// Generate mesh decals for provided model
|
||||
private static unsafe Mesh GenMeshDecal(Model target, Matrix4x4 projection, float decalSize, float decalOffset)
|
||||
{
|
||||
// We're going to use these to build up our decal meshes
|
||||
var meshBuilders = new List<Vector3>[2] { new(), new() };
|
||||
|
||||
// We're going to need the inverse matrix
|
||||
var invProj = MatrixInvert(projection);
|
||||
|
||||
// We'll be flip-flopping between the two mesh builders
|
||||
// Reading from one and writing to the other, then swapping
|
||||
var mbIndex = 0;
|
||||
|
||||
// First pass, just get any triangle inside the bounding box (for each mesh of the model)
|
||||
for (var meshIndex = 0; meshIndex < target.MeshCount; meshIndex++)
|
||||
{
|
||||
var mesh = target.Meshes[meshIndex];
|
||||
for (var tri = 0; tri < mesh.TriangleCount; tri++)
|
||||
{
|
||||
var vertices = new Vector3[3];
|
||||
|
||||
// The way we calculate the vertices of the mesh triangle
|
||||
// depend on whether the mesh vertices are indexed or not
|
||||
if (mesh.Indices == null)
|
||||
{
|
||||
for (var v = 0; v < 3; v++)
|
||||
{
|
||||
vertices[v] = new Vector3(
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 0],
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 1],
|
||||
mesh.Vertices[3 * 3 * tri + 3 * v + 2]
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var v = 0; v < 3; v++)
|
||||
{
|
||||
vertices[v] = new Vector3(
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 0] + v],
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 1] + v],
|
||||
mesh.Vertices[3 * mesh.Indices[3 * tri + 2] + v]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Transform all 3 vertices of the triangle
|
||||
// and check if they are inside our decal box
|
||||
var insideCount = 0;
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
// To projection space
|
||||
var v = Vector3Transform(vertices[i], projection);
|
||||
|
||||
if ((MathF.Abs(v.X) < decalSize) || (MathF.Abs(v.Y) <= decalSize) || (MathF.Abs(v.Z) <= decalSize))
|
||||
{
|
||||
insideCount++;
|
||||
}
|
||||
|
||||
// We need to keep the transformed vertex
|
||||
vertices[i] = v;
|
||||
}
|
||||
|
||||
// If any of them are inside, we add the triangle - we'll clip it later
|
||||
if (insideCount > 0)
|
||||
{
|
||||
meshBuilders[mbIndex].Add(vertices[0]);
|
||||
meshBuilders[mbIndex].Add(vertices[1]);
|
||||
meshBuilders[mbIndex].Add(vertices[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clipping time! We need to clip against all 6 directions
|
||||
Vector3[] planes =
|
||||
{
|
||||
new(1, 0, 0),
|
||||
new(-1, 0, 0),
|
||||
new(0, 1, 0),
|
||||
new(0, -1, 0),
|
||||
new(0, 0, 1),
|
||||
new(0, 0, -1)
|
||||
};
|
||||
|
||||
for (var face = 0; face < 6; face++)
|
||||
{
|
||||
// Swap current model builder (so we read from the one we just wrote to)
|
||||
mbIndex = 1 - mbIndex;
|
||||
|
||||
var inMesh = meshBuilders[1 - mbIndex];
|
||||
var outMesh = meshBuilders[mbIndex];
|
||||
|
||||
// Reset write builder
|
||||
outMesh.Clear();
|
||||
|
||||
var s = 0.5f * decalSize;
|
||||
|
||||
for (var i = 0; i < inMesh.Count; i += 3)
|
||||
{
|
||||
Vector3 nV1, nV2, nV3, nV4;
|
||||
|
||||
var d1 = Vector3.Dot(inMesh[i + 0], planes[face]) - s;
|
||||
var d2 = Vector3.Dot(inMesh[i + 1], planes[face]) - s;
|
||||
var d3 = Vector3.Dot(inMesh[i + 2], planes[face]) - s;
|
||||
|
||||
var v1Out = d1 > 0;
|
||||
var v2Out = d2 > 0;
|
||||
var v3Out = d3 > 0;
|
||||
|
||||
// Calculate, how many vertices of the face lie outside of the clipping plane
|
||||
var total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
|
||||
|
||||
switch (total)
|
||||
{
|
||||
case 0:
|
||||
// The entire face lies inside of the plane, no clipping needed
|
||||
outMesh.Add(inMesh[i]);
|
||||
outMesh.Add(inMesh[i + 1]);
|
||||
outMesh.Add(inMesh[i + 2]);
|
||||
break;
|
||||
case 1:
|
||||
// One vertex lies outside of the plane, perform clipping
|
||||
if (v2Out)
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = inMesh[i + 2];
|
||||
nV3 = ClipSegment(inMesh[i + 1], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i + 1], nV2, planes[face], s);
|
||||
|
||||
outMesh.Add(nV3); outMesh.Add(nV2); outMesh.Add(nV1);
|
||||
outMesh.Add(nV2); outMesh.Add(nV3); outMesh.Add(nV4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v1Out)
|
||||
{
|
||||
nV1 = inMesh[i + 1];
|
||||
nV2 = inMesh[i + 2];
|
||||
nV3 = ClipSegment(inMesh[i], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i], nV2, planes[face], s);
|
||||
}
|
||||
else // v3Out
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = inMesh[i + 1];
|
||||
nV3 = ClipSegment(inMesh[i + 2], nV1, planes[face], s);
|
||||
nV4 = ClipSegment(inMesh[i + 2], nV2, planes[face], s);
|
||||
}
|
||||
|
||||
outMesh.Add(nV1); outMesh.Add(nV2); outMesh.Add(nV3);
|
||||
outMesh.Add(nV4); outMesh.Add(nV3); outMesh.Add(nV2);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Two vertices lies outside of the plane, perform clipping
|
||||
if (!v1Out)
|
||||
{
|
||||
nV1 = inMesh[i];
|
||||
nV2 = ClipSegment(nV1, inMesh[i + 1], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i + 2], planes[face], s);
|
||||
outMesh.Add(nV1); outMesh.Add(nV2); outMesh.Add(nV3);
|
||||
}
|
||||
|
||||
if (!v2Out)
|
||||
{
|
||||
nV1 = inMesh[i + 1];
|
||||
nV2 = ClipSegment(nV1, inMesh[i + 2], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i], planes[face], s);
|
||||
outMesh.Add(nV1); outMesh.Add(nV2); outMesh.Add(nV3);
|
||||
}
|
||||
|
||||
if (!v3Out)
|
||||
{
|
||||
nV1 = inMesh[i + 2];
|
||||
nV2 = ClipSegment(nV1, inMesh[i], planes[face], s);
|
||||
nV3 = ClipSegment(nV1, inMesh[i + 1], planes[face], s);
|
||||
outMesh.Add(nV1); outMesh.Add(nV2); outMesh.Add(nV3);
|
||||
}
|
||||
break;
|
||||
default: // The entire face lies outside of the plane, so let's discard the corresponding vertices
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we just need to re-transform the vertices
|
||||
var theMesh = meshBuilders[mbIndex];
|
||||
|
||||
// Allocate room for UVs
|
||||
if (theMesh.Count > 0)
|
||||
{
|
||||
var uvs = new Vector2[theMesh.Count];
|
||||
|
||||
for (var i = 0; i < theMesh.Count; i++)
|
||||
{
|
||||
var vert = theMesh[i];
|
||||
|
||||
// Calculate the UVs based on the projected coords
|
||||
// They are clipped to (-decalSize .. decalSize) and we want them (0..1)
|
||||
uvs[i] = new Vector2(vert.X / decalSize + 0.5f, vert.Y / decalSize + 0.5f);
|
||||
|
||||
// Tiny nudge in the normal direction so it renders properly over the mesh
|
||||
vert.Z -= decalOffset;
|
||||
|
||||
// From projection space to world space
|
||||
theMesh[i] = Vector3Transform(vert, invProj);
|
||||
}
|
||||
|
||||
// Decal model data ready, create the mesh and return it
|
||||
return BuildMesh(theMesh, uvs);
|
||||
}
|
||||
|
||||
// Return a blank mesh as there's nothing to add
|
||||
return new Mesh();
|
||||
}
|
||||
|
||||
// Build a Mesh from builder data
|
||||
private static unsafe Mesh BuildMesh(List<Vector3> builderVertices, Vector2[] uvs)
|
||||
{
|
||||
Mesh outMesh = new(builderVertices.Count, builderVertices.Count / 3);
|
||||
outMesh.AllocVertices();
|
||||
outMesh.AllocTexCoords();
|
||||
|
||||
var vertices = outMesh.VerticesAs<Vector3>();
|
||||
var texcoords = outMesh.TexCoordsAs<Vector2>();
|
||||
|
||||
for (var i = 0; i < builderVertices.Count; i++)
|
||||
{
|
||||
vertices[i] = builderVertices[i];
|
||||
texcoords[i] = uvs[i];
|
||||
}
|
||||
|
||||
UploadMesh(ref outMesh, false);
|
||||
|
||||
return outMesh;
|
||||
}
|
||||
|
||||
// Button UI element
|
||||
private static bool GuiButton(Rectangle rec, string label)
|
||||
{
|
||||
var bgColor = Color.Gray;
|
||||
var pressed = false;
|
||||
|
||||
if (CheckCollisionPointRec(GetMousePosition(), rec))
|
||||
{
|
||||
bgColor = Color.LightGray;
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
DrawRectangleRec(rec, bgColor);
|
||||
DrawRectangleLinesEx(rec, 2.0f, Color.DarkGray);
|
||||
|
||||
var fontSize = 10;
|
||||
var textWidth = MeasureText(label, fontSize);
|
||||
|
||||
DrawText(label, (int)(rec.X + rec.Width * 0.5f - textWidth * 0.5f), (int)(rec.Y + rec.Height * 0.5f - fontSize * 0.5f), fontSize, Color.DarkGray);
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - decals");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Decals();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
148
Examples/Models/DirectionalBillboard.cs
Normal file
148
Examples/Models/DirectionalBillboard.cs
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - directional billboard
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, 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)
|
||||
* Killbot art by patvanmackelberg https://opengameart.org/content/killbot-8-directional under CC0
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class DirectionalBillboard : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Directional Billboard";
|
||||
|
||||
public string Title => "raylib [models] example - directional billboard";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D skillbot;
|
||||
private float animTimer;
|
||||
private uint anim;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Set up the camera
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 1.0f, 2.0f); // Starting position
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f); // Target position
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Up vector
|
||||
camera.FovY = 45.0f; // FOV
|
||||
camera.Projection = CameraProjection.Perspective; // Projection type (Standard 3D perspective)
|
||||
|
||||
// Load billboard texture
|
||||
skillbot = LoadTexture("resources/skillbot.png");
|
||||
|
||||
// Timer to update animation
|
||||
animTimer = 0.0f;
|
||||
// Animation frame
|
||||
anim = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update timer with delta time
|
||||
animTimer += GetFrameTime();
|
||||
|
||||
// Update frame index after a certain amount of time (half a second)
|
||||
if (animTimer > 0.5f)
|
||||
{
|
||||
animTimer = 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
|
||||
var dir = (float)Math.Floor(((Vector2Angle(new Vector2(2.0f, 0.0f), new Vector2(camera.Position.X, camera.Position.Z)) / MathF.PI) * 4.0f) + 0.25f);
|
||||
|
||||
// Correct frame index if angle is negative
|
||||
if (dir < 0.0f)
|
||||
{
|
||||
dir = 8.0f - Math.Abs((int)dir);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.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, new Rectangle(0.0f + (anim * 24.0f), 0.0f + (dir * 24.0f), 24.0f, 24.0f),
|
||||
Vector3.Zero, new Vector3(0.0f, 1.0f, 0.0f), Vector2.One, new Vector2(0.5f, 0.0f), 0, Color.White);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Render various variables for reference
|
||||
DrawText($"animation: {anim}", 10, 10, 20, Color.DarkGray);
|
||||
DrawText($"direction frame: {dir:0}", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload billboard texture
|
||||
UnloadTexture(skillbot);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - directional billboard");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DirectionalBillboard();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,19 +3,28 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class DynamicMesh
|
||||
public partial class DynamicMesh : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int triangleRows = 48;
|
||||
private const int vertexRows = triangleRows + 1;
|
||||
|
||||
public string Name => "Models / Dynamic Mesh";
|
||||
|
||||
public string Title => "raylib [models] example - dynamic mesh";
|
||||
|
||||
private Camera3D camera;
|
||||
private Mesh dynamicMesh;
|
||||
private Texture2D texture;
|
||||
private Color[] pixels;
|
||||
private Material material;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - dynamic mesh");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = Vector3.One * 1.5f;
|
||||
camera.Target = camera.Position + new Vector3(1f, -0.25f, 1f);
|
||||
camera.Up = Vector3.UnitY;
|
||||
|
|
@ -23,18 +32,14 @@ public class DynamicMesh
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Generate a dynamic mesh using utils to allocate/access mesh attribute data
|
||||
const int triangleRows = 48;
|
||||
const int vertexRows = triangleRows + 1;
|
||||
Mesh dynamicMesh = new(vertexRows * vertexRows, triangleRows * triangleRows * 2);
|
||||
dynamicMesh = new(vertexRows * vertexRows, triangleRows * triangleRows * 2);
|
||||
dynamicMesh.AllocVertices();
|
||||
dynamicMesh.AllocTexCoords();
|
||||
dynamicMesh.AllocIndices();
|
||||
Span<Vector3> vertices = dynamicMesh.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = dynamicMesh.TexCoordsAs<Vector2>();
|
||||
Span<ushort> indices = dynamicMesh.IndicesAs<ushort>();
|
||||
var indices = dynamicMesh.IndicesAs<ushort>();
|
||||
for (int z = 0, i = 0; z < triangleRows; z++)
|
||||
{
|
||||
for (int x = 0; x < triangleRows; x++, i += 6)
|
||||
for (var x = 0; x < triangleRows; x++, i += 6)
|
||||
{
|
||||
indices[i + 0] = (ushort)(x + (z * vertexRows));
|
||||
indices[i + 1] = (ushort)(indices[i] + vertexRows);
|
||||
|
|
@ -47,73 +52,96 @@ public class DynamicMesh
|
|||
UploadMesh(ref dynamicMesh, true);
|
||||
|
||||
// Allocate the texture
|
||||
Image image = GenImageColor(triangleRows, triangleRows, Color.Blank);
|
||||
Texture2D texture = LoadTextureFromImage(image);
|
||||
Color[] pixels = new Color[texture.Width * texture.Height];
|
||||
var image = GenImageColor(triangleRows, triangleRows, Color.Blank);
|
||||
texture = LoadTextureFromImage(image);
|
||||
pixels = new Color[texture.Width * texture.Height];
|
||||
UnloadImage(image);
|
||||
|
||||
// Load the material
|
||||
Material material = LoadMaterialDefault();
|
||||
material = LoadMaterialDefault();
|
||||
SetMaterialTexture(ref material, MaterialMapIndex.Diffuse, texture);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var time = (float)GetTime();
|
||||
Random random = new(42);
|
||||
|
||||
var vertices = dynamicMesh.VerticesAs<Vector3>();
|
||||
var texcoords = dynamicMesh.TexCoordsAs<Vector2>();
|
||||
|
||||
for (int z = 0, i = 0; z < vertexRows; z++)
|
||||
{
|
||||
for (var x = 0; x < vertexRows; x++, i++)
|
||||
{
|
||||
var noiseX = SmoothNoise(time + random.Next(10000));
|
||||
var noiseZ = SmoothNoise(time + random.Next(10000));
|
||||
vertices[i].X = x + noiseX - .5f;
|
||||
vertices[i].Y = (noiseX + noiseZ) / 2;
|
||||
vertices[i].Z = z + noiseZ - .5f;
|
||||
texcoords[i].X = (x - noiseZ) / triangleRows;
|
||||
texcoords[i].Y = (z - noiseX) / triangleRows;
|
||||
}
|
||||
}
|
||||
UpdateMeshBuffer<Vector3>(dynamicMesh, Mesh.VboIdIndexVertices, vertices, 0);
|
||||
UpdateMeshBuffer<Vector2>(dynamicMesh, Mesh.VboIdIndexTexCoords, texcoords, 0);
|
||||
|
||||
for (int y = 0, i = 0; y < texture.Height; y++)
|
||||
{
|
||||
for (var x = 0; x < texture.Width; x++, i++)
|
||||
{
|
||||
pixels[i] = new(32, 178, 170, 255);
|
||||
pixels[i] = ColorBrightness(pixels[i], (SmoothNoise(time + random.Next(10000)) / 8) - (1 / 16f));
|
||||
pixels[i] = ColorAlpha(pixels[i], (triangleRows - new Vector2(x, y).Length()) / triangleRows);
|
||||
}
|
||||
}
|
||||
UpdateTexture(texture, pixels);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(dynamicMesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMaterial(material);
|
||||
// Raylib.UnloadTexture(texture); <- No need to unload the texture. UnloadMaterial(Material) already unloaded it for us
|
||||
UnloadMesh(dynamicMesh);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - dynamic mesh");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new DynamicMesh();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float time = (float)GetTime();
|
||||
Random random = new(42);
|
||||
|
||||
for (int z = 0, i = 0; z < vertexRows; z++)
|
||||
{
|
||||
for (int x = 0; x < vertexRows; x++, i++)
|
||||
{
|
||||
float noiseX = SmoothNoise(time + random.Next(10000));
|
||||
float noiseZ = SmoothNoise(time + random.Next(10000));
|
||||
vertices[i].X = x + noiseX - .5f;
|
||||
vertices[i].Y = (noiseX + noiseZ) / 2;
|
||||
vertices[i].Z = z + noiseZ - .5f;
|
||||
texcoords[i].X = (x - noiseZ) / triangleRows;
|
||||
texcoords[i].Y = (z - noiseX) / triangleRows;
|
||||
}
|
||||
}
|
||||
UpdateMeshBuffer<Vector3>(dynamicMesh, Mesh.VboIdIndexVertices, vertices, 0);
|
||||
UpdateMeshBuffer<Vector2>(dynamicMesh, Mesh.VboIdIndexTexCoords, texcoords, 0);
|
||||
|
||||
for (int y = 0, i = 0; y < texture.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < texture.Width; x++, i++)
|
||||
{
|
||||
pixels[i] = new(32, 178, 170, 255);
|
||||
pixels[i] = ColorBrightness(pixels[i], (SmoothNoise(time + random.Next(10000)) / 8) - (1 / 16f));
|
||||
pixels[i] = ColorAlpha(pixels[i], (triangleRows - new Vector2(x, y).Length()) / triangleRows);
|
||||
}
|
||||
}
|
||||
UpdateTexture(texture, pixels);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawMesh(dynamicMesh, material, Matrix4x4.Identity);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMaterial(material);
|
||||
// Raylib.UnloadTexture(texture); <- No need to unload the texture. UnloadMaterial(Material) already unloaded it for us
|
||||
UnloadMesh(dynamicMesh);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
*
|
||||
* raylib [models] example - first person maze
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Copyright (c) 2019 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.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) 2019-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,140 +18,163 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class FirstPersonMaze
|
||||
public unsafe partial class FirstPersonMaze : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / First Person Maze";
|
||||
|
||||
public string Title => "raylib [models] example - first person maze";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D cubicmap;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Color* mapPixels;
|
||||
private Vector3 mapPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.2f, 0.4f, 0.2f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.2f, 0.4f, 0.2f); // Camera position
|
||||
camera.Target = new Vector3(0.185f, 0.4f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image imMap = LoadImage("resources/cubicmap.png");
|
||||
Texture2D cubicmap = LoadTextureFromImage(imMap);
|
||||
Mesh mesh = GenMeshCubicmap(imMap, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var imMap = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM)
|
||||
cubicmap = LoadTextureFromImage(imMap); // Convert image to texture to display (VRAM)
|
||||
var mesh = GenMeshCubicmap(imMap, new Vector3(1.0f, 1.0f, 1.0f));
|
||||
model = LoadModelFromMesh(mesh);
|
||||
|
||||
// NOTE: By default each cube is mapped to one part of texture atlas
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
// Get map image data to be used for collision detection
|
||||
Color* mapPixels = LoadImageColors(imMap);
|
||||
UnloadImage(imMap);
|
||||
mapPixels = LoadImageColors(imMap);
|
||||
UnloadImage(imMap); // Unload image from RAM
|
||||
|
||||
Vector3 mapPosition = new(-16.0f, 0.0f, -8.0f);
|
||||
Vector3 playerPosition = camera.Position;
|
||||
mapPosition = new(-16.0f, 0.0f, -8.0f); // Set model position
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var oldCamPos = camera.Position; // Store old camera position
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
// Check player collision (we simplify to 2D collision detection)
|
||||
Vector2 playerPos = new(camera.Position.X, camera.Position.Z);
|
||||
var playerRadius = 0.1f; // Collision radius (player is modelled as a cilinder for collision)
|
||||
|
||||
var playerCellX = (int)(playerPos.X - mapPosition.X + 0.5f);
|
||||
var playerCellY = (int)(playerPos.Y - mapPosition.Z + 0.5f);
|
||||
|
||||
// Out-of-limits security check
|
||||
if (playerCellX < 0)
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
Vector3 oldCamPos = camera.Position;
|
||||
playerCellX = 0;
|
||||
}
|
||||
else if (playerCellX >= cubicmap.Width)
|
||||
{
|
||||
playerCellX = cubicmap.Width - 1;
|
||||
}
|
||||
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
if (playerCellY < 0)
|
||||
{
|
||||
playerCellY = 0;
|
||||
}
|
||||
else if (playerCellY >= cubicmap.Height)
|
||||
{
|
||||
playerCellY = cubicmap.Height - 1;
|
||||
}
|
||||
|
||||
// Check player collision (we simplify to 2D collision detection)
|
||||
Vector2 playerPos = new(camera.Position.X, camera.Position.Z);
|
||||
|
||||
// Collision radius (player is modelled as a cilinder for collision)
|
||||
float playerRadius = 0.1f;
|
||||
|
||||
int playerCellX = (int)(playerPos.X - mapPosition.X + 0.5f);
|
||||
int playerCellY = (int)(playerPos.Y - mapPosition.Z + 0.5f);
|
||||
|
||||
// Out-of-limits security check
|
||||
if (playerCellX < 0)
|
||||
// Check map collisions using image data and player position against surrounding cells only
|
||||
for (var y = playerCellY - 1; y <= playerCellY + 1; y++)
|
||||
{
|
||||
// Avoid map accessing out of bounds
|
||||
if ((y >= 0) && (y < cubicmap.Height))
|
||||
{
|
||||
playerCellX = 0;
|
||||
}
|
||||
else if (playerCellX >= cubicmap.Width)
|
||||
{
|
||||
playerCellX = cubicmap.Width - 1;
|
||||
}
|
||||
|
||||
if (playerCellY < 0)
|
||||
{
|
||||
playerCellY = 0;
|
||||
}
|
||||
else if (playerCellY >= cubicmap.Height)
|
||||
{
|
||||
playerCellY = cubicmap.Height - 1;
|
||||
}
|
||||
|
||||
// Check map collisions using image data and player position
|
||||
// TODO: Improvement: Just check player surrounding cells for collision
|
||||
for (int y = 0; y < cubicmap.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < cubicmap.Width; x++)
|
||||
for (var x = playerCellX - 1; x <= playerCellX + 1; x++)
|
||||
{
|
||||
Color* mapPixelsData = mapPixels;
|
||||
|
||||
// Collision: Color.white pixel, only check R channel
|
||||
Rectangle rec = new(
|
||||
mapPosition.X - 0.5f + x * 1.0f,
|
||||
mapPosition.Z - 0.5f + y * 1.0f,
|
||||
1.0f,
|
||||
1.0f
|
||||
);
|
||||
|
||||
bool collision = CheckCollisionCircleRec(playerPos, playerRadius, rec);
|
||||
if ((mapPixelsData[y * cubicmap.Width + x].R == 255) && collision)
|
||||
// NOTE: Collision: Only checking R channel for white pixel
|
||||
if (((x >= 0) && (x < cubicmap.Width)) &&
|
||||
(mapPixels[y * cubicmap.Width + x].R == 255) &&
|
||||
(CheckCollisionCircleRec(playerPos, playerRadius,
|
||||
new Rectangle(mapPosition.X - 0.5f + x * 1.0f, mapPosition.Z - 0.5f + y * 1.0f, 1.0f, 1.0f))))
|
||||
{
|
||||
// Collision detected, reset camera position
|
||||
camera.Position = oldCamPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw maze map
|
||||
BeginMode3D(camera);
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
DrawTextureEx(cubicmap, new Vector2(GetScreenWidth() - cubicmap.Width * 4 - 20, 20), 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(GetScreenWidth() - cubicmap.Width * 4 - 20, 20, cubicmap.Width * 4, cubicmap.Height * 4, Color.Green);
|
||||
|
||||
// Draw player position radar
|
||||
DrawRectangle(GetScreenWidth() - cubicmap.Width * 4 - 20 + playerCellX * 4, 20 + playerCellY * 4, 4, 4, Color.Red);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawModel(model, mapPosition, 1.0f, Color.White); // Draw maze map
|
||||
EndMode3D();
|
||||
|
||||
DrawTextureEx(cubicmap, new Vector2(GetScreenWidth() - cubicmap.Width * 4 - 20, 20), 0.0f, 4.0f, Color.White);
|
||||
DrawRectangleLines(GetScreenWidth() - cubicmap.Width * 4 - 20, 20, cubicmap.Width * 4, cubicmap.Height * 4, Color.Green);
|
||||
|
||||
// Draw player position radar
|
||||
DrawRectangle(GetScreenWidth() - cubicmap.Width * 4 - 20 + playerCellX * 4, 20 + playerCellY * 4, 4, 4, Color.Red);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadImageColors(mapPixels); // Unload color array
|
||||
|
||||
UnloadTexture(cubicmap); // Unload cubicmap texture
|
||||
UnloadTexture(texture); // Unload map texture
|
||||
UnloadModel(model); // Unload map model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new FirstPersonMaze();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadImageColors(mapPixels);
|
||||
|
||||
UnloadTexture(cubicmap);
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Draw some basic geometric shapes (cube, sphere, cylinder...)
|
||||
* raylib [models] example - geometric shapes
|
||||
*
|
||||
* 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 3.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)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,70 +18,91 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class GeometricShapes
|
||||
public partial class GeometricShapes : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Geometric Shapes";
|
||||
|
||||
public string Title => "raylib [models] example - geometric shapes";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawCapsule(new Vector3(-3.0f, 1.5f, -4.0f), new Vector3(-4.0f, -1.0f, -4.0f), 1.2f, 8, 8, Color.Violet);
|
||||
DrawCapsuleWires(new Vector3(-3.0f, 1.5f, -4.0f), new Vector3(-4.0f, -1.0f, -4.0f), 1.2f, 8, 8, Color.Purple);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new GeometricShapes();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Heightmap loading and drawing
|
||||
* raylib [models] example - heightmap rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 3.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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,77 +18,102 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class HeightmapDemo
|
||||
public partial class HeightmapDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Heightmap Demo";
|
||||
|
||||
public string Title => "raylib [models] example - heightmap rendering";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D texture;
|
||||
private Model model;
|
||||
private Vector3 mapPosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing");
|
||||
|
||||
// Define our custom camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(18.0f, 16.0f, 18.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(18.0f, 21.0f, 18.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
Image image = LoadImage("resources/heightmap.png");
|
||||
Texture2D texture = LoadTextureFromImage(image);
|
||||
var image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM)
|
||||
texture = LoadTextureFromImage(image); // Convert image to texture (VRAM)
|
||||
|
||||
Mesh mesh = GenMeshHeightmap(image, new Vector3(16, 8, 16));
|
||||
Model model = LoadModelFromMesh(mesh);
|
||||
var mesh = GenMeshHeightmap(image, new Vector3(16, 8, 16)); // Generate heightmap mesh (RAM and VRAM)
|
||||
model = LoadModelFromMesh(mesh); // Load model from generated mesh
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 mapPosition = new(-8.0f, 0.0f, -8.0f);
|
||||
mapPosition = new(-8.0f, 0.0f, -8.0f); // Define model position
|
||||
|
||||
UnloadImage(image);
|
||||
UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.Red);
|
||||
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawTexture(texture, screenWidth - texture.Width - 20, 20, Color.White);
|
||||
DrawRectangleLines(screenWidth - texture.Width - 20, 20, texture.Width, texture.Height, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new HeightmapDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, mapPosition, 1.0f, Color.Red);
|
||||
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawTexture(texture, screenWidth - texture.Width - 20, 20, Color.White);
|
||||
DrawRectangleLines(screenWidth - texture.Width - 20, 20, texture.Width, texture.Height, Color.Green);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -25,93 +25,122 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class LoadingGltf
|
||||
public partial class LoadingGltf : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading GLTF";
|
||||
|
||||
public string Title => "raylib [models] example - loading gltf";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/gltf/robot.glb");
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model world position
|
||||
|
||||
// Load model animations
|
||||
anims = LoadModelAnimations("resources/models/gltf/robot.glb", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(
|
||||
model,
|
||||
position,
|
||||
1f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading gltf");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(6.0f, 6.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.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/gltf/robot.glb");
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Load animation data
|
||||
var anims = LoadModelAnimations("resources/models/gltf/robot.glb");
|
||||
|
||||
// Animation playing variables
|
||||
int animIndex = 0;
|
||||
float animCurrentFrame = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingGltf();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % anims.Length;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + anims.Length - 1) % anims.Length;
|
||||
}
|
||||
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame = (animCurrentFrame + 1) % anims[animIndex].KeyFrameCount;
|
||||
UpdateModelAnimation(model, anims[animIndex], (float)animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(
|
||||
model,
|
||||
position,
|
||||
1f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 40, 20, Color.Maroon);
|
||||
DrawText("Use the LEFT/RIGHT keys to switch animation", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModelAnimations(anims);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,93 +25,121 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class LoadingIqm
|
||||
public partial class LoadingIqm : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading IQM";
|
||||
|
||||
public string Title => "raylib [models] example - loading iqm";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 4.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
model = LoadModel("resources/models/iqm/guy.iqm"); // Load the animated model mesh and basic data
|
||||
texture = LoadTexture("resources/models/iqm/guytex.png"); // Load model texture and set material
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture); // Set model material map texture
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load animation data
|
||||
anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
animCurrentFrame += 1.0f;
|
||||
UpdateModelAnimation(model, anims[0], animCurrentFrame);
|
||||
|
||||
if (animCurrentFrame >= anims[0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(
|
||||
model,
|
||||
position,
|
||||
new Vector3(1.0f, 0.0f, 0.0f),
|
||||
-90.0f,
|
||||
new Vector3(1.0f, 1.0f, 1.0f),
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
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();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading iqm");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation");
|
||||
|
||||
// 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, 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.Diffuse, ref texture);
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Load animation data
|
||||
var anims = LoadModelAnimations("resources/models/iqm/guyanim.iqm");
|
||||
|
||||
// Animation playing variables
|
||||
int animIndex = 0;
|
||||
float animCurrentFrame = 0.0f;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingIqm();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Play animation when spacebar is held down
|
||||
animCurrentFrame += 1.0f;
|
||||
UpdateModelAnimation(model, anims[0], animCurrentFrame);
|
||||
|
||||
if (animCurrentFrame >= anims[0].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModelEx(
|
||||
model,
|
||||
position,
|
||||
new Vector3(1.0f, 0.0f, 0.0f),
|
||||
-90.0f,
|
||||
new Vector3(1.0f, 1.0f, 1.0f),
|
||||
Color.White
|
||||
);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
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();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModelAnimations(anims);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
173
Examples/Models/LoadingM3d.cs
Normal file
173
Examples/Models/LoadingM3d.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - loading m3d
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* 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-2025 bzt (@bztsrc)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class LoadingM3d : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Loading M3D";
|
||||
|
||||
public string Title => "raylib [models] example - loading m3d";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Vector3 position;
|
||||
private unsafe ModelAnimation* anims;
|
||||
private int animCount;
|
||||
private int animIndex;
|
||||
private float animCurrentFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(1.5f, 1.5f, 1.5f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.4f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/m3d/cesium_man.m3d"); // Load the animated model mesh and basic data
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f); // Set model position
|
||||
|
||||
// Load animation data
|
||||
animCount = 0;
|
||||
anims = LoadModelAnimations("resources/models/m3d/cesium_man.m3d", ref animCount);
|
||||
|
||||
// Animation playing variables
|
||||
animIndex = 0; // Current animation playing
|
||||
animCurrentFrame = 0.0f; // Current animation frame (supporting interpolated frames)
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Select current animation
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
animIndex = (animIndex + 1) % animCount;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
animIndex = (animIndex + animCount - 1) % animCount;
|
||||
}
|
||||
|
||||
// Update model animation
|
||||
animCurrentFrame += 1.0f;
|
||||
if (animCurrentFrame >= anims[animIndex].KeyFrameCount)
|
||||
{
|
||||
animCurrentFrame = 0.0f;
|
||||
}
|
||||
UpdateModelAnimation(model, anims[animIndex], animCurrentFrame);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
if (!IsKeyDown(KeyboardKey.Space))
|
||||
{
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the animated skeleton
|
||||
DrawModelSkeleton(model.Skeleton, anims[animIndex].KeyframePoses[(int)animCurrentFrame], 1.0f, Color.Red);
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText($"Current animation: {anims[animIndex].NameToString()}", 10, 10, 20, Color.LightGray);
|
||||
DrawText("Press SPACE to draw skeleton", 10, 40, 20, Color.Maroon);
|
||||
DrawText("(c) CesiumMan model by KhronosGroup", GetScreenWidth() - 210, GetScreenHeight() - 20, 10, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
UnloadModelAnimations(anims, animCount); // Unload model animations data
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
// Draw model skeleton
|
||||
private static unsafe void DrawModelSkeleton(ModelSkeleton skeleton, Transform* pose, float scale, Color color)
|
||||
{
|
||||
// Loop to (boneCount - 1) because the last one is a special "no bone" bone,
|
||||
// needed to workaround buggy models without a -1, a cube is always drawn at the origin
|
||||
for (var i = 0; i < skeleton.BoneCount - 1; i++)
|
||||
{
|
||||
// Display the frame-pose skeleton
|
||||
DrawCube(pose[i].Translation, scale * 0.05f, scale * 0.05f, scale * 0.05f, color);
|
||||
|
||||
if (skeleton.Bones[i].Parent >= 0)
|
||||
{
|
||||
DrawLine3D(pose[i].Translation, pose[skeleton.Bones[i].Parent].Translation, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading m3d");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingM3d();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
246
Examples/Models/LoadingVox.cs
Normal file
246
Examples/Models/LoadingVox.cs
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - loading vox
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 4.0, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Johann Nadalutti (@procfxgen) 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) 2021-2025 Johann Nadalutti (@procfxgen) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class LoadingVox : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxVoxFiles = 4;
|
||||
private const int MaxLights = 4;
|
||||
|
||||
#if BROWSER
|
||||
private const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Loading VOX";
|
||||
|
||||
public string Title => "raylib [models] example - loading vox";
|
||||
|
||||
private static readonly string[] VoxFileNames =
|
||||
{
|
||||
"resources/models/vox/chr_knight.vox",
|
||||
"resources/models/vox/chr_sword.vox",
|
||||
"resources/models/vox/monu9.vox",
|
||||
"resources/models/vox/fez.vox"
|
||||
};
|
||||
|
||||
private Camera3D camera;
|
||||
private Model[] models;
|
||||
private int currentModel;
|
||||
private Vector3 modelpos;
|
||||
private Vector3 camerarot;
|
||||
private Shader shader;
|
||||
private Light[] lights;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load MagicaVoxel files
|
||||
models = new Model[MaxVoxFiles];
|
||||
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
// Load VOX file and measure time
|
||||
var t0 = GetTime() * 1000.0;
|
||||
models[i] = LoadModel(VoxFileNames[i]);
|
||||
var t1 = GetTime() * 1000.0;
|
||||
|
||||
TraceLog(TraceLogLevel.Info, $"[{VoxFileNames[i]}] Model file loaded in {t1 - t0:0.000} ms");
|
||||
|
||||
// Compute model translation matrix to center model on draw position (0, 0 , 0)
|
||||
var bb = GetModelBoundingBox(models[i]);
|
||||
Vector3 center = new();
|
||||
center.X = bb.Min.X + ((bb.Max.X - bb.Min.X) / 2);
|
||||
center.Z = bb.Min.Z + ((bb.Max.Z - bb.Min.Z) / 2);
|
||||
|
||||
var matTranslate = MatrixTranslate(-center.X, 0, -center.Z);
|
||||
models[i].Transform = matTranslate;
|
||||
}
|
||||
|
||||
currentModel = 0;
|
||||
modelpos = new Vector3(0, 0, 0);
|
||||
camerarot = new Vector3(0, 0, 0);
|
||||
|
||||
// Load voxel shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/voxel_lighting.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/voxel_lighting.fs"
|
||||
);
|
||||
|
||||
// Get some required shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
// NOTE: "matModel" location name is automatically assigned on shader loading,
|
||||
// no need to get the location again if using that uniform name
|
||||
//shader.Locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocation(shader, "matModel");
|
||||
|
||||
// Ambient light level (some basic lighting)
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
Raylib.SetShaderValue(shader, ambientLoc, new[] { 0.1f, 0.1f, 0.1f, 1.0f }, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Assign out lighting shader to model
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
for (var j = 0; j < models[i].MaterialCount; j++)
|
||||
{
|
||||
models[i].Materials[j].Shader = shader;
|
||||
}
|
||||
}
|
||||
|
||||
// Create lights
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(0, LightType.Point, new Vector3(-20, 20, -20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[1] = Rlights.CreateLight(1, LightType.Point, new Vector3(20, -20, 20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[2] = Rlights.CreateLight(2, LightType.Point, new Vector3(-20, 20, 20), Vector3.Zero, Color.Gray, shader);
|
||||
lights[3] = Rlights.CreateLight(3, LightType.Point, new Vector3(20, -20, -20), Vector3.Zero, Color.Gray, shader);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsMouseButtonDown(MouseButton.Middle))
|
||||
{
|
||||
var mouseDelta = GetMouseDelta();
|
||||
camerarot.X = mouseDelta.X * 0.05f;
|
||||
camerarot.Y = mouseDelta.Y * 0.05f;
|
||||
}
|
||||
else
|
||||
{
|
||||
camerarot.X = 0;
|
||||
camerarot.Y = 0;
|
||||
}
|
||||
|
||||
// Update camere movement, custom controls
|
||||
UpdateCameraPro(ref camera,
|
||||
new Vector3(
|
||||
(IsKeyDown(KeyboardKey.W) || IsKeyDown(KeyboardKey.Up) ? 0.1f : 0.0f) - (IsKeyDown(KeyboardKey.S) || IsKeyDown(KeyboardKey.Down) ? 0.1f : 0.0f), // Move forward-backward
|
||||
(IsKeyDown(KeyboardKey.D) || IsKeyDown(KeyboardKey.Right) ? 0.1f : 0.0f) - (IsKeyDown(KeyboardKey.A) || IsKeyDown(KeyboardKey.Left) ? 0.1f : 0.0f), // Move right-left
|
||||
0.0f), // Move up-down
|
||||
camerarot, // Camera rotation
|
||||
GetMouseWheelMove() * -2.0f); // Move to target (zoom)
|
||||
|
||||
// Cycle between models on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
currentModel = (currentModel + 1) % MaxVoxFiles;
|
||||
}
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
Raylib.SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], camera.Position, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], modelpos, 1.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw spheres to show where the lights are
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lights[i].Color);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lights[i].Color, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Display info
|
||||
DrawRectangle(10, 40, 340, 70, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 40, 340, 70, Fade(Color.DarkBlue, 0.5f));
|
||||
DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, Color.Blue);
|
||||
DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, Color.Blue);
|
||||
DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, Color.Blue);
|
||||
DrawText($"VOX model file: {GetFileName(VoxFileNames[currentModel])}", 10, 10, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// Unload models data (GPU VRAM)
|
||||
for (var i = 0; i < MaxVoxFiles; i++)
|
||||
{
|
||||
UnloadModel(models[i]);
|
||||
}
|
||||
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading vox");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new LoadingVox();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,19 +3,24 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshDemo
|
||||
public partial class MeshDemo : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Demo";
|
||||
|
||||
public string Title => "raylib [models] example - mesh demo";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private float rotationAngle;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh demo");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = Vector3.One * 1.5f;
|
||||
camera.Target = Vector3.Zero;
|
||||
camera.Up = Vector3.UnitY;
|
||||
|
|
@ -28,10 +33,10 @@ public class MeshDemo
|
|||
tetrahedron.AllocTexCoords();
|
||||
tetrahedron.AllocColors();
|
||||
tetrahedron.AllocIndices();
|
||||
Span<Vector3> vertices = tetrahedron.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = tetrahedron.TexCoordsAs<Vector2>();
|
||||
Span<Color> colors = tetrahedron.ColorsAs<Color>();
|
||||
Span<ushort> indices = tetrahedron.IndicesAs<ushort>();
|
||||
var vertices = tetrahedron.VerticesAs<Vector3>();
|
||||
var texcoords = tetrahedron.TexCoordsAs<Vector2>();
|
||||
var colors = tetrahedron.ColorsAs<Color>();
|
||||
var indices = tetrahedron.IndicesAs<ushort>();
|
||||
|
||||
// Coordinates for a regular tetrahedron
|
||||
vertices[0] = new(MathF.Sqrt(8f / 9f), 0f, -1f / 3f);
|
||||
|
|
@ -65,49 +70,69 @@ public class MeshDemo
|
|||
indices[10] = 3;
|
||||
indices[11] = 2;
|
||||
|
||||
float rotationAngle = 0f;
|
||||
rotationAngle = 0f;
|
||||
Raylib.UploadMesh(ref tetrahedron, false);
|
||||
Model model = Raylib.LoadModelFromMesh(tetrahedron);
|
||||
model = Raylib.LoadModelFromMesh(tetrahedron);
|
||||
|
||||
Image image = Raylib.GenImagePerlinNoise(16, 16, 0, 0, 1000f);
|
||||
var image = Raylib.GenImagePerlinNoise(16, 16, 0, 0, 1000f);
|
||||
Raylib.ImageBlurGaussian(ref image, 2);
|
||||
Raylib.ImageColorBrightness(ref image, 100);
|
||||
Raylib.ImageDither(ref image, 4, 4, 4, 4);
|
||||
Texture2D texture = Raylib.LoadTextureFromImage(image);
|
||||
texture = Raylib.LoadTextureFromImage(image);
|
||||
Raylib.UnloadImage(image);
|
||||
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Diffuse, ref texture);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
rotationAngle = Raymath.Wrap(rotationAngle += 1f, 0f, 360f);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Raylib.DrawModelEx(model, Vector3.Zero, Vector3.UnitX, rotationAngle, Vector3.One, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh demo");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
rotationAngle = Raymath.Wrap(rotationAngle += 1f, 0f, 360f);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Raylib.DrawModelEx(model, Vector3.Zero, Vector3.UnitX, rotationAngle, Vector3.One, Color.White);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib example - procedural mesh generation
|
||||
* raylib [models] example - mesh generation
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (Ray San)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 4.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) 2017-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,25 +18,31 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshGeneration
|
||||
public partial class MeshGeneration : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Generation";
|
||||
|
||||
public string Title => "raylib [models] example - mesh generation";
|
||||
|
||||
private Texture2D texture;
|
||||
private Model[] models;
|
||||
private Camera3D camera;
|
||||
private Vector3 position;
|
||||
private int currentModel;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation");
|
||||
|
||||
// We generate a isChecked image for texturing
|
||||
Image isChecked = GenImageChecked(2, 2, 1, 1, Color.Red, Color.Green);
|
||||
Texture2D texture = LoadTextureFromImage(isChecked);
|
||||
// We generate a checked image for texturing
|
||||
var isChecked = GenImageChecked(2, 2, 1, 1, Color.Red, Color.Green);
|
||||
texture = LoadTextureFromImage(isChecked);
|
||||
UnloadImage(isChecked);
|
||||
|
||||
Model[] models = new Model[9];
|
||||
models = new Model[9];
|
||||
|
||||
models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 5, 5));
|
||||
models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 4, 3));
|
||||
models[1] = LoadModelFromMesh(GenMeshCube(2.0f, 1.0f, 2.0f));
|
||||
models[2] = LoadModelFromMesh(GenMeshSphere(2, 32, 32));
|
||||
models[3] = LoadModelFromMesh(GenMeshHemiSphere(2, 16, 16));
|
||||
|
|
@ -42,15 +52,17 @@ public class MeshGeneration
|
|||
models[7] = LoadModelFromMesh(GenMeshPoly(5, 2.0f));
|
||||
models[8] = LoadModelFromMesh(GenMeshCustom());
|
||||
|
||||
// Set isChecked texture as default diffuse component for all models material
|
||||
for (int i = 0; i < models.Length; i++)
|
||||
// NOTE: Generated meshes could be exported using ExportMesh()
|
||||
|
||||
// Set checked texture as default diffuse component for all models material
|
||||
for (var i = 0; i < models.Length; i++)
|
||||
{
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref models[i], 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(5.0f, 5.0f, 5.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -58,92 +70,102 @@ public class MeshGeneration
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Model drawing position
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
position = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
int currentModel = 0;
|
||||
currentModel = 0;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Cycle between the textures
|
||||
currentModel = (currentModel + 1) % models.Length;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(30, 400, 310, 30, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(30, 400, 310, 30, ColorAlpha(Color.DarkBlue, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, Color.Blue);
|
||||
|
||||
switch (currentModel)
|
||||
{
|
||||
case 0:
|
||||
DrawText("PLANE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 1:
|
||||
DrawText("CUBE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 2:
|
||||
DrawText("SPHERE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 3:
|
||||
DrawText("HEMISPHERE", 640, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 4:
|
||||
DrawText("CYLINDER", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 5:
|
||||
DrawText("TORUS", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 6:
|
||||
DrawText("KNOT", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 7:
|
||||
DrawText("POLY", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 8:
|
||||
DrawText("Custom (triagnle)", 580, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
currentModel = (currentModel + 1) % models.Length; // Cycle between the textures
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
for (int i = 0; i < models.Length; i++)
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
currentModel++;
|
||||
if (currentModel >= models.Length)
|
||||
{
|
||||
currentModel = 0;
|
||||
}
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
currentModel--;
|
||||
if (currentModel < 0)
|
||||
{
|
||||
currentModel = models.Length - 1;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(models[currentModel], position, 1.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(30, 400, 310, 30, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(30, 400, 310, 30, Fade(Color.DarkBlue, 0.5f));
|
||||
DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, Color.Blue);
|
||||
|
||||
switch (currentModel)
|
||||
{
|
||||
case 0:
|
||||
DrawText("PLANE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 1:
|
||||
DrawText("CUBE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 2:
|
||||
DrawText("SPHERE", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 3:
|
||||
DrawText("HEMISPHERE", 640, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 4:
|
||||
DrawText("CYLINDER", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 5:
|
||||
DrawText("TORUS", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 6:
|
||||
DrawText("KNOT", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 7:
|
||||
DrawText("POLY", 680, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
case 8:
|
||||
DrawText("Custom (triangle)", 580, 10, 20, Color.DarkBlue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
|
||||
// Unload models data (GPU VRAM)
|
||||
for (var i = 0; i < models.Length; i++)
|
||||
{
|
||||
UnloadModel(models[i]);
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate a simple triangle mesh from code
|
||||
|
|
@ -153,9 +175,9 @@ public class MeshGeneration
|
|||
mesh.AllocVertices();
|
||||
mesh.AllocTexCoords();
|
||||
mesh.AllocNormals();
|
||||
Span<Vector3> vertices = mesh.VerticesAs<Vector3>();
|
||||
Span<Vector2> texcoords = mesh.TexCoordsAs<Vector2>();
|
||||
Span<Vector3> normals = mesh.NormalsAs<Vector3>();
|
||||
var vertices = mesh.VerticesAs<Vector3>();
|
||||
var texcoords = mesh.TexCoordsAs<Vector2>();
|
||||
var normals = mesh.NormalsAs<Vector3>();
|
||||
|
||||
// Vertex at (0, 0, 0)
|
||||
vertices[0] = new(0, 0, 0);
|
||||
|
|
@ -177,4 +199,32 @@ public class MeshGeneration
|
|||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshGeneration();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Mesh picking in 3d mode, ground plane, triangle, mesh
|
||||
* raylib [models] example - mesh picking
|
||||
*
|
||||
* This example has been created using raylib 1.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Joel Davis (@joeld42)
|
||||
* Example originally created with raylib 1.7, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Joel Davis (@joeld42) 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) 2017-2025 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,19 +21,36 @@ using static Raylib_cs.Raymath;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class MeshPicking
|
||||
public partial class MeshPicking : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Mesh Picking";
|
||||
|
||||
public string Title => "raylib [models] example - mesh picking";
|
||||
|
||||
private Camera3D camera;
|
||||
private Ray ray;
|
||||
private Model tower;
|
||||
private Texture2D texture;
|
||||
private Vector3 towerPos;
|
||||
private BoundingBox towerBBox;
|
||||
private Vector3 g0;
|
||||
private Vector3 g1;
|
||||
private Vector3 g2;
|
||||
private Vector3 g3;
|
||||
private Vector3 ta;
|
||||
private Vector3 tb;
|
||||
private Vector3 tc;
|
||||
private Vector3 bary;
|
||||
private Vector3 sp;
|
||||
private float sr;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(20.0f, 20.0f, 20.0f);
|
||||
camera.Target = new Vector3(0.0f, 8.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.6f, 0.0f);
|
||||
|
|
@ -36,210 +58,232 @@ public class MeshPicking
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Picking ray
|
||||
Ray ray = new();
|
||||
ray = new();
|
||||
|
||||
Model tower = LoadModel("resources/models/obj/turret.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/turret_diffuse.png");
|
||||
tower = LoadModel("resources/models/obj/turret.obj");
|
||||
texture = LoadTexture("resources/models/obj/turret_diffuse.png");
|
||||
Raylib.SetMaterialTexture(ref tower, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 towerPos = new(0.0f, 0.0f, 0.0f);
|
||||
BoundingBox towerBBox = GetMeshBoundingBox(tower.Meshes[0]);
|
||||
towerPos = new(0.0f, 0.0f, 0.0f);
|
||||
towerBBox = GetMeshBoundingBox(tower.Meshes[0]);
|
||||
|
||||
// Ground quad
|
||||
Vector3 g0 = new(-50.0f, 0.0f, -50.0f);
|
||||
Vector3 g1 = new(-50.0f, 0.0f, 50.0f);
|
||||
Vector3 g2 = new(50.0f, 0.0f, 50.0f);
|
||||
Vector3 g3 = new(50.0f, 0.0f, -50.0f);
|
||||
g0 = new(-50.0f, 0.0f, -50.0f);
|
||||
g1 = new(-50.0f, 0.0f, 50.0f);
|
||||
g2 = new(50.0f, 0.0f, 50.0f);
|
||||
g3 = new(50.0f, 0.0f, -50.0f);
|
||||
|
||||
// Test triangle
|
||||
Vector3 ta = new(-25.0f, 0.5f, 0.0f);
|
||||
Vector3 tb = new(-4.0f, 2.5f, 1.0f);
|
||||
Vector3 tc = new(-8.0f, 6.5f, 0.0f);
|
||||
ta = new(-25.0f, 0.5f, 0.0f);
|
||||
tb = new(-4.0f, 2.5f, 1.0f);
|
||||
tc = new(-8.0f, 6.5f, 0.0f);
|
||||
|
||||
Vector3 bary = new(0.0f, 0.0f, 0.0f);
|
||||
bary = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// Test sphere
|
||||
Vector3 sp = new(-30.0f, 5.0f, 5.0f);
|
||||
float sr = 4.0f;
|
||||
sp = new(-30.0f, 5.0f, 5.0f);
|
||||
sr = 4.0f;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
//----------------------------------------------------------------------------------
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
}
|
||||
|
||||
// Toggle camera controls
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
EnableCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableCursor();
|
||||
}
|
||||
}
|
||||
|
||||
// Display information about closest hit
|
||||
RayCollision collision = new();
|
||||
var hitObjectName = "None";
|
||||
collision.Distance = float.MaxValue;
|
||||
collision.Hit = false;
|
||||
var cursorColor = Color.White;
|
||||
|
||||
// Get ray and test against objects
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision against ground quad
|
||||
var groundHitInfo = GetRayCollisionQuad(ray, g0, g1, g2, g3);
|
||||
if (groundHitInfo.Hit && (groundHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = groundHitInfo;
|
||||
cursorColor = Color.Green;
|
||||
hitObjectName = "Ground";
|
||||
}
|
||||
|
||||
// Check ray collision against test triangle
|
||||
var triHitInfo = GetRayCollisionTriangle(ray, ta, tb, tc);
|
||||
if (triHitInfo.Hit && (triHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = triHitInfo;
|
||||
cursorColor = Color.Purple;
|
||||
hitObjectName = "Triangle";
|
||||
|
||||
bary = Vector3Barycenter(collision.Point, ta, tb, tc);
|
||||
}
|
||||
|
||||
// Check ray collision against test sphere
|
||||
var sphereHitInfo = GetRayCollisionSphere(ray, sp, sr);
|
||||
if ((sphereHitInfo.Hit) && (sphereHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = sphereHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Sphere";
|
||||
}
|
||||
|
||||
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||
var boxHitInfo = GetRayCollisionBox(ray, towerBBox);
|
||||
if (boxHitInfo.Hit && boxHitInfo.Distance < collision.Distance)
|
||||
{
|
||||
collision = boxHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Box";
|
||||
|
||||
// Check ray collision against model meshes
|
||||
RayCollision meshHitInfo = new();
|
||||
for (var m = 0; m < tower.MeshCount; m++)
|
||||
{
|
||||
// NOTE: We consider the model.Transform for the collision check but
|
||||
// it can be checked against any transform matrix, used when checking against same
|
||||
// model drawn multiple times with multiple transforms
|
||||
meshHitInfo = GetRayCollisionMesh(ray, tower.Meshes[m], tower.Transform);
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
// Save the closest hit mesh
|
||||
if ((!collision.Hit) || (collision.Distance > meshHitInfo.Distance))
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Mesh";
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the tower
|
||||
// WARNING: If scale is different than 1.0f,
|
||||
// not considered by GetRayCollisionModel()
|
||||
DrawModel(tower, towerPos, 1.0f, Color.White);
|
||||
|
||||
// Draw the test triangle
|
||||
DrawLine3D(ta, tb, Color.Purple);
|
||||
DrawLine3D(tb, tc, Color.Purple);
|
||||
DrawLine3D(tc, ta, Color.Purple);
|
||||
|
||||
// Draw the test sphere
|
||||
DrawSphereWires(sp, sr, 8, 8, Color.Purple);
|
||||
|
||||
// Draw the mesh bbox if we hit it
|
||||
if (boxHitInfo.Hit)
|
||||
{
|
||||
DrawBoundingBox(towerBBox, Color.Lime);
|
||||
}
|
||||
|
||||
// If we hit something, draw the cursor at the hit point
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(collision.Point, 0.3f, 0.3f, 0.3f, cursorColor);
|
||||
DrawCubeWires(collision.Point, 0.3f, 0.3f, 0.3f, Color.Red);
|
||||
|
||||
var normalEnd = collision.Point + collision.Normal;
|
||||
DrawLine3D(collision.Point, normalEnd, Color.Red);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw some debug GUI text
|
||||
DrawText($"Hit Object: {hitObjectName}", 10, 50, 10, Color.Black);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
var ypos = 70;
|
||||
|
||||
DrawText($"Distance: {collision.Distance}", 10, ypos, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Pos: {collision.Point}", 10, ypos + 15, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Norm: {collision.Normal}", 10, ypos + 30, 10, Color.Black);
|
||||
|
||||
if (triHitInfo.Hit && hitObjectName == "Triangle")
|
||||
{
|
||||
DrawText($"Barycenter: {bary}", 10, ypos + 45, 10, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
|
||||
|
||||
DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(tower);
|
||||
UnloadTexture(texture);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MeshPicking();
|
||||
game.Init();
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Main game loop
|
||||
//--------------------------------------------------------------------------------------
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
//----------------------------------------------------------------------------------
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
}
|
||||
|
||||
// Toggle camera controls
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
if (IsCursorHidden())
|
||||
{
|
||||
EnableCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableCursor();
|
||||
}
|
||||
}
|
||||
|
||||
// Display information about closest hit
|
||||
RayCollision collision = new();
|
||||
string hitObjectName = "None";
|
||||
collision.Distance = float.MaxValue;
|
||||
collision.Hit = false;
|
||||
Color cursorColor = Color.White;
|
||||
|
||||
// Get ray and test against objects
|
||||
ray = GetScreenToWorldRay(GetMousePosition(), camera);
|
||||
|
||||
// Check ray collision aginst ground quad
|
||||
RayCollision groundHitInfo = GetRayCollisionQuad(ray, g0, g1, g2, g3);
|
||||
if (groundHitInfo.Hit && (groundHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = groundHitInfo;
|
||||
cursorColor = Color.Green;
|
||||
hitObjectName = "Ground";
|
||||
}
|
||||
|
||||
// Check ray collision against test triangle
|
||||
RayCollision triHitInfo = GetRayCollisionTriangle(ray, ta, tb, tc);
|
||||
if (triHitInfo.Hit && (triHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = triHitInfo;
|
||||
cursorColor = Color.Purple;
|
||||
hitObjectName = "Triangle";
|
||||
|
||||
bary = Vector3Barycenter(collision.Point, ta, tb, tc);
|
||||
}
|
||||
|
||||
// Check ray collision against test sphere
|
||||
RayCollision sphereHitInfo = GetRayCollisionSphere(ray, sp, sr);
|
||||
if ((sphereHitInfo.Hit) && (sphereHitInfo.Distance < collision.Distance))
|
||||
{
|
||||
collision = sphereHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Sphere";
|
||||
}
|
||||
|
||||
// Check ray collision against bounding box first, before trying the full ray-mesh test
|
||||
RayCollision boxHitInfo = GetRayCollisionBox(ray, towerBBox);
|
||||
if (boxHitInfo.Hit && boxHitInfo.Distance < collision.Distance)
|
||||
{
|
||||
collision = boxHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Box";
|
||||
|
||||
// Check ray collision against model meshes
|
||||
RayCollision meshHitInfo = new();
|
||||
for (int m = 0; m < tower.MeshCount; m++)
|
||||
{
|
||||
// NOTE: We consider the model.Transform for the collision check but
|
||||
// it can be checked against any transform matrix, used when checking against same
|
||||
// model drawn multiple times with multiple transforms
|
||||
meshHitInfo = GetRayCollisionMesh(ray, tower.Meshes[m], tower.Transform);
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
// Save the closest hit mesh
|
||||
if ((!collision.Hit) || (collision.Distance > meshHitInfo.Distance))
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshHitInfo.Hit)
|
||||
{
|
||||
collision = meshHitInfo;
|
||||
cursorColor = Color.Orange;
|
||||
hitObjectName = "Mesh";
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw the tower
|
||||
DrawModel(tower, towerPos, 1.0f, Color.White);
|
||||
|
||||
// Draw the test triangle
|
||||
DrawLine3D(ta, tb, Color.Purple);
|
||||
DrawLine3D(tb, tc, Color.Purple);
|
||||
DrawLine3D(tc, ta, Color.Purple);
|
||||
|
||||
// Draw the test sphere
|
||||
DrawSphereWires(sp, sr, 8, 8, Color.Purple);
|
||||
|
||||
// Draw the mesh bbox if we hit it
|
||||
if (boxHitInfo.Hit)
|
||||
{
|
||||
DrawBoundingBox(towerBBox, Color.Lime);
|
||||
}
|
||||
|
||||
// If we hit something, draw the cursor at the hit point
|
||||
if (collision.Hit)
|
||||
{
|
||||
DrawCube(collision.Point, 0.3f, 0.3f, 0.3f, cursorColor);
|
||||
DrawCubeWires(collision.Point, 0.3f, 0.3f, 0.3f, Color.Red);
|
||||
|
||||
Vector3 normalEnd = collision.Point + collision.Normal;
|
||||
DrawLine3D(collision.Point, normalEnd, Color.Red);
|
||||
}
|
||||
|
||||
DrawRay(ray, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw some debug GUI text
|
||||
DrawText($"Hit Object: {hitObjectName}", 10, 50, 10, Color.Black);
|
||||
|
||||
if (collision.Hit)
|
||||
{
|
||||
int ypos = 70;
|
||||
|
||||
DrawText($"Distance: {collision.Distance}", 10, ypos, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Pos: {collision.Point}", 10, ypos + 15, 10, Color.Black);
|
||||
|
||||
DrawText($"Hit Norm: {collision.Normal}", 10, ypos + 30, 10, Color.Black);
|
||||
|
||||
if (triHitInfo.Hit)
|
||||
{
|
||||
DrawText($"Barycenter: {bary}", 10, ypos + 45, 10, Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
|
||||
|
||||
DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(tower);
|
||||
UnloadTexture(texture);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Draw textured cube
|
||||
* raylib [models] example - textured cube
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 4.5, last time updated with raylib 4.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) 2022-2023 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2022-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,19 +18,22 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class ModelCubeTexture
|
||||
public partial class ModelCubeTexture : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Model Cube Texture";
|
||||
|
||||
public string Title => "raylib [models] example - textured cube";
|
||||
|
||||
private Camera3D camera;
|
||||
private Texture2D texture;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - draw cube texture");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -36,60 +41,48 @@ public class ModelCubeTexture
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load texture to be applied to the cubes sides
|
||||
Texture2D texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
texture = LoadTexture("resources/cubicmap_atlas.png");
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
// Draw cube with an applied texture
|
||||
DrawCubeTexture(texture, new Vector3(-2.0f, 2.0f, 0.0f), 2.0f, 4.0f, 2.0f, Color.White);
|
||||
|
||||
BeginMode3D(camera);
|
||||
// Draw cube with an applied texture, but only a defined rectangle piece of the texture
|
||||
DrawCubeTextureRec(
|
||||
texture,
|
||||
new Rectangle(0, texture.Height / 2, texture.Width / 2, texture.Height / 2),
|
||||
new Vector3(2.0f, 1.0f, 0.0f),
|
||||
2.0f,
|
||||
2.0f,
|
||||
2.0f,
|
||||
Color.White
|
||||
);
|
||||
|
||||
// Draw cube with an applied texture
|
||||
DrawCubeTexture(texture, new Vector3(-2.0f, 2.0f, 0.0f), 2.0f, 4.0f, 2.0f, Color.White);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
// Draw cube with an applied texture, but only a defined rectangle piece of the texture
|
||||
DrawCubeTextureRec(
|
||||
texture,
|
||||
new Rectangle(0, texture.Height / 2, texture.Width / 2, texture.Height / 2),
|
||||
new Vector3(2.0f, 1.0f, 0.0f),
|
||||
2.0f,
|
||||
2.0f,
|
||||
2.0f,
|
||||
Color.White
|
||||
);
|
||||
EndMode3D();
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw cube textured
|
||||
// NOTE: Cube position is the center position
|
||||
static void DrawCubeTexture(
|
||||
private static void DrawCubeTexture(
|
||||
Texture2D texture,
|
||||
Vector3 position,
|
||||
float width,
|
||||
|
|
@ -98,9 +91,9 @@ public class ModelCubeTexture
|
|||
Color color
|
||||
)
|
||||
{
|
||||
float x = position.X;
|
||||
float y = position.Y;
|
||||
float z = position.Z;
|
||||
var x = position.X;
|
||||
var y = position.Y;
|
||||
var z = position.Z;
|
||||
|
||||
// Set desired texture to be enabled while drawing following vertex data
|
||||
Rlgl.SetTexture(texture.Id);
|
||||
|
|
@ -218,7 +211,7 @@ public class ModelCubeTexture
|
|||
}
|
||||
|
||||
// Draw cube with texture piece applied to all faces
|
||||
static void DrawCubeTextureRec(
|
||||
private static void DrawCubeTextureRec(
|
||||
Texture2D texture,
|
||||
Rectangle source,
|
||||
Vector3 position,
|
||||
|
|
@ -228,11 +221,11 @@ public class ModelCubeTexture
|
|||
Color color
|
||||
)
|
||||
{
|
||||
float x = position.X;
|
||||
float y = position.Y;
|
||||
float z = position.Z;
|
||||
float texWidth = (float)texture.Width;
|
||||
float texHeight = (float)texture.Height;
|
||||
var x = position.X;
|
||||
var y = position.Y;
|
||||
var z = position.Z;
|
||||
var texWidth = (float)texture.Width;
|
||||
var texHeight = (float)texture.Height;
|
||||
|
||||
// Set desired texture to be enabled while drawing following vertex data
|
||||
Rlgl.SetTexture(texture.Id);
|
||||
|
|
@ -312,5 +305,32 @@ public class ModelCubeTexture
|
|||
|
||||
Rlgl.SetTexture(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - textured cube");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModelCubeTexture();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,28 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Models loading
|
||||
* raylib [models] example - loading
|
||||
*
|
||||
* raylib supports multiple models file formats:
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* - OBJ > Text file, must include vertex position-texcoords-normals information,
|
||||
* if files references some .mtl materials file, it will be loaded (or try to)
|
||||
* - GLTF > Modern text/binary file format, includes lot of information and it could
|
||||
* also reference external files, raylib will try loading mesh and materials data
|
||||
* - IQM > Binary file format including mesh vertex data but also animation data,
|
||||
* raylib can load .iqm animations.
|
||||
* NOTE: raylib supports multiple models file formats:
|
||||
*
|
||||
* This example has been created using raylib 2.6 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* - OBJ > Text file format. Must include vertex position-texcoords-normals information,
|
||||
* if .obj references some .mtl materials file, it will be tried to be loaded
|
||||
* - GLTF/GLB > Text/binary file formats. Includes lot of information and it could
|
||||
* also reference external files, mesh and materials data will be tried to be loaded
|
||||
* - IQM > Binary file format. Includes mesh vertex data but also animation data,
|
||||
* meshes and animation data can be loaded
|
||||
* - VOX > Binary file format. MagikaVoxel mesh format:
|
||||
* https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt
|
||||
* - M3D > Binary file format. Model 3D format:
|
||||
* https://bztsrc.gitlab.io/model3d
|
||||
*
|
||||
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.0, 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) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -23,135 +31,170 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class ModelLoading
|
||||
public partial class ModelLoading : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Model Loading";
|
||||
|
||||
public string Title => "raylib [models] example - loading";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private Vector3 position;
|
||||
private BoundingBox bounds;
|
||||
private bool selected;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - models loading");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(50.0f, 50.0f, 50.0f);
|
||||
camera.Target = new Vector3(0.0f, 10.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(50.0f, 50.0f, 50.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 12.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
Model model = LoadModel("resources/models/obj/castle.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/castle_diffuse.png");
|
||||
model = LoadModel("resources/models/obj/castle.obj"); // Load model
|
||||
texture = LoadTexture("resources/models/obj/castle_diffuse.png"); // Load model texture
|
||||
|
||||
// Set map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
Vector3 position = new(0.0f, 0.0f, 0.0f);
|
||||
BoundingBox bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
position = new(0.0f, 0.0f, 0.0f); // Set model position
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]); // Set model bounds
|
||||
|
||||
// NOTE: bounds are calculated from the original size of the model,
|
||||
// if model is scaled on drawing, bounds must be also scaled
|
||||
|
||||
bool selected = false;
|
||||
selected = false;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
#if BROWSER
|
||||
// NOTE: drag-and-drop model loading is not supported in the browser host; default loaded model is kept.
|
||||
#else
|
||||
// Load new models/textures on drag&drop
|
||||
if (IsFileDropped())
|
||||
{
|
||||
var droppedFiles = Raylib.GetDroppedFiles();
|
||||
|
||||
if (droppedFiles.Length == 1) // Only support one file dropped
|
||||
{
|
||||
if (IsFileExtension(droppedFiles[0], ".obj") ||
|
||||
IsFileExtension(droppedFiles[0], ".gltf") ||
|
||||
IsFileExtension(droppedFiles[0], ".glb") ||
|
||||
IsFileExtension(droppedFiles[0], ".vox") ||
|
||||
IsFileExtension(droppedFiles[0], ".iqm") ||
|
||||
IsFileExtension(droppedFiles[0], ".m3d") // Model file formats supported
|
||||
)
|
||||
{
|
||||
UnloadModel(model); // Unload previous model
|
||||
model = LoadModel(droppedFiles[0]); // Load new model
|
||||
|
||||
// Set current map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
|
||||
// Move camera position from target enough distance to visualize model properly
|
||||
camera.Position.X = bounds.Max.X + 10.0f;
|
||||
camera.Position.Y = bounds.Max.Y + 10.0f;
|
||||
camera.Position.Z = bounds.Max.Z + 10.0f;
|
||||
}
|
||||
else if (IsFileExtension(droppedFiles[0], ".png")) // Texture file formats supported
|
||||
{
|
||||
// Unload current model texture and load new one
|
||||
UnloadTexture(texture);
|
||||
texture = LoadTexture(droppedFiles[0]);
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Select model on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Check collision between ray and box
|
||||
if (GetRayCollisionBox(GetScreenToWorldRay(GetMousePosition(), camera), bounds).Hit)
|
||||
{
|
||||
selected = !selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White); // Draw 3d model with texture
|
||||
|
||||
DrawGrid(20, 10.0f); // Draw a grid
|
||||
|
||||
if (selected)
|
||||
{
|
||||
DrawBoundingBox(bounds, Color.Green); // Draw selection box
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Drag & drop model to load mesh/texture.", 10, GetScreenHeight() - 20, 10, Color.DarkGray);
|
||||
if (selected)
|
||||
{
|
||||
DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, Color.Green);
|
||||
}
|
||||
|
||||
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - loading");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModelLoading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsFileDropped())
|
||||
{
|
||||
string[] droppedFiles = Raylib.GetDroppedFiles();
|
||||
|
||||
if (droppedFiles.Length == 1)
|
||||
{
|
||||
if (IsFileExtension(droppedFiles[0], ".obj") ||
|
||||
IsFileExtension(droppedFiles[0], ".gltf") ||
|
||||
IsFileExtension(droppedFiles[0], ".glb") ||
|
||||
IsFileExtension(droppedFiles[0], ".vox") ||
|
||||
IsFileExtension(droppedFiles[0], ".iqm") ||
|
||||
IsFileExtension(droppedFiles[0], ".m3d")
|
||||
)
|
||||
{
|
||||
UnloadModel(model);
|
||||
model = LoadModel(droppedFiles[0]);
|
||||
|
||||
// Set current map diffuse texture
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
|
||||
bounds = GetMeshBoundingBox(model.Meshes[0]);
|
||||
|
||||
// TODO: Move camera position from target enough distance to visualize model properly
|
||||
}
|
||||
else if (IsFileExtension(droppedFiles[0], ".png"))
|
||||
{
|
||||
// Unload model texture and load new one
|
||||
UnloadTexture(texture);
|
||||
texture = LoadTexture(droppedFiles[0]);
|
||||
Raylib.SetMaterialTexture(ref model, 0, MaterialMapIndex.Albedo, ref texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select model on mouse click
|
||||
if (IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
// Check collision between ray and box
|
||||
if (GetRayCollisionBox(GetScreenToWorldRay(GetMousePosition(), camera), bounds).Hit)
|
||||
{
|
||||
selected = !selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, position, 1.0f, Color.White);
|
||||
|
||||
DrawGrid(20, 10.0f);
|
||||
|
||||
if (selected)
|
||||
{
|
||||
DrawBoundingBox(bounds, Color.Green);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Drag & drop model to load mesh/texture.", 10, GetScreenHeight() - 20, 10, Color.DarkGray);
|
||||
if (selected)
|
||||
{
|
||||
DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, Color.Green);
|
||||
}
|
||||
|
||||
DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, Color.Gray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadTexture(texture);
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Show the difference between perspective and orthographic projection
|
||||
* raylib [models] example - orthographic projection
|
||||
*
|
||||
* This program is heavily based on the geometric objects example
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* This example has been created using raylib 1.9.7 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 2.0, last time updated with raylib 3.7
|
||||
*
|
||||
* Copyright (c) 2018 Max Danielsson ref Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Max Danielsson (@autious) 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) 2018-2025 Max Danielsson (@autious) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,96 +20,119 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class OrthographicProjection
|
||||
public partial class OrthographicProjection : IExample
|
||||
{
|
||||
public const float FOVY_PERSPECTIVE = 45.0f;
|
||||
public const float WIDTH_ORTHOGRAPHIC = 10.0f;
|
||||
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Orthographic Projection";
|
||||
|
||||
public string Title => "raylib [models] example - orthographic projection";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
camera.FovY = WIDTH_ORTHOGRAPHIC;
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f); // Draw a grid
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Press Spacebar to switch camera type", 10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
DrawText("ORTHOGRAPHIC", 10, 40, 20, Color.Black);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
DrawText("PERSPECTIVE", 10, 40, 20, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - orthographic projection");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new OrthographicProjection();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
camera.FovY = WIDTH_ORTHOGRAPHIC;
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
}
|
||||
else
|
||||
{
|
||||
camera.FovY = FOVY_PERSPECTIVE;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, 2.0f), 2.0f, 5.0f, 2.0f, Color.Gold);
|
||||
DrawCubeWires(new Vector3(-4.0f, 0.0f, -2.0f), 3.0f, 6.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawSphere(new Vector3(-1.0f, 0.0f, -2.0f), 1.0f, Color.Green);
|
||||
DrawSphereWires(new Vector3(1.0f, 0.0f, 2.0f), 2.0f, 16, 16, Color.Lime);
|
||||
|
||||
DrawCylinder(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.SkyBlue);
|
||||
DrawCylinderWires(new Vector3(4.0f, 0.0f, -2.0f), 1.0f, 2.0f, 3.0f, 4, Color.DarkBlue);
|
||||
DrawCylinderWires(new Vector3(4.5f, -1.0f, 2.0f), 1.0f, 1.0f, 2.0f, 6, Color.Brown);
|
||||
|
||||
DrawCylinder(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Gold);
|
||||
DrawCylinderWires(new Vector3(1.0f, 0.0f, -4.0f), 0.0f, 1.5f, 3.0f, 8, Color.Pink);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Press Spacebar to switch camera type", 10, GetScreenHeight() - 30, 20, Color.DarkGray);
|
||||
|
||||
if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
DrawText("ORTHOGRAPHIC", 10, 40, 20, Color.Black);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
DrawText("PERSPECTIVE", 10, 40, 20, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
235
Examples/Models/PointRendering.cs
Normal file
235
Examples/Models/PointRendering.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - point rendering
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example contributed by Reese Gallagher (@satchelfrost) 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) 2024-2025 Reese Gallagher (@satchelfrost)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
[ExcludeFromBrowser("rlEnablePointMode needs glPolygonMode, which OpenGL ES/WebGL lacks (renders as triangles)")]
|
||||
public partial class PointRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxPoints = 10000000; // 10 million
|
||||
private const int MinPoints = 1000; // 1 thousand
|
||||
|
||||
public string Name => "Models / Point Rendering";
|
||||
|
||||
public string Title => "raylib [models] example - point rendering";
|
||||
|
||||
private static readonly Random Rand = new();
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 position;
|
||||
private bool useDrawModelPoints;
|
||||
private bool numPointsChanged;
|
||||
private int numPoints;
|
||||
private Mesh mesh;
|
||||
private Model model;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
camera = new()
|
||||
{
|
||||
Position = new Vector3(3.0f, 3.0f, 3.0f),
|
||||
Target = new Vector3(0.0f, 0.0f, 0.0f),
|
||||
Up = new Vector3(0.0f, 1.0f, 0.0f),
|
||||
FovY = 45.0f,
|
||||
Projection = CameraProjection.Perspective
|
||||
};
|
||||
|
||||
position = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
useDrawModelPoints = true;
|
||||
numPointsChanged = false;
|
||||
numPoints = 1000;
|
||||
|
||||
mesh = GenMeshPoints(numPoints);
|
||||
model = LoadModelFromMesh(mesh);
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
useDrawModelPoints = !useDrawModelPoints;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Up))
|
||||
{
|
||||
numPoints = (numPoints * 10 > MaxPoints) ? MaxPoints : numPoints * 10;
|
||||
numPointsChanged = true;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Down))
|
||||
{
|
||||
numPoints = (numPoints / 10 < MinPoints) ? MinPoints : numPoints / 10;
|
||||
numPointsChanged = true;
|
||||
}
|
||||
|
||||
// Upload a different point cloud size
|
||||
if (numPointsChanged)
|
||||
{
|
||||
UnloadModel(model);
|
||||
mesh = GenMeshPoints(numPoints);
|
||||
model = LoadModelFromMesh(mesh);
|
||||
numPointsChanged = false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// The new method only uploads the points once to the GPU
|
||||
if (useDrawModelPoints)
|
||||
{
|
||||
DrawModelPoints(model, position, 1.0f, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The old method must continually draw the "points" (lines)
|
||||
for (var i = 0; i < numPoints; i++)
|
||||
{
|
||||
Vector3 pos = new(
|
||||
mesh.Vertices[i * 3 + 0],
|
||||
mesh.Vertices[i * 3 + 1],
|
||||
mesh.Vertices[i * 3 + 2]
|
||||
);
|
||||
Color color = new(
|
||||
mesh.Colors[i * 4 + 0],
|
||||
mesh.Colors[i * 4 + 1],
|
||||
mesh.Colors[i * 4 + 2],
|
||||
mesh.Colors[i * 4 + 3]
|
||||
);
|
||||
|
||||
DrawPoint3D(pos, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a unit sphere for reference
|
||||
DrawSphereWires(position, 1.0f, 10, 10, Color.Yellow);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw UI text
|
||||
DrawText($"Point Count: {numPoints}", 10, screenHeight - 50, 40, Color.White);
|
||||
DrawText("UP - Increase points", 10, 40, 20, Color.White);
|
||||
DrawText("DOWN - Decrease points", 10, 70, 20, Color.White);
|
||||
DrawText("SPACE - Drawing function", 10, 100, 20, Color.White);
|
||||
|
||||
if (useDrawModelPoints)
|
||||
{
|
||||
DrawText("Using: DrawModelPoints()", 10, 130, 20, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Using: DrawPoint3D()", 10, 130, 20, Color.Red);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
// Generate a spherical point cloud
|
||||
private static unsafe Mesh GenMeshPoints(int numPoints)
|
||||
{
|
||||
Mesh mesh = new(numPoints, 1);
|
||||
mesh.AllocVertices();
|
||||
mesh.AllocColors();
|
||||
|
||||
// REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
|
||||
for (var i = 0; i < numPoints; i++)
|
||||
{
|
||||
var theta = MathF.PI * (float)Rand.NextDouble();
|
||||
var phi = 2.0f * MathF.PI * (float)Rand.NextDouble();
|
||||
var r = 10.0f * (float)Rand.NextDouble();
|
||||
|
||||
mesh.Vertices[i * 3 + 0] = r * MathF.Sin(theta) * MathF.Cos(phi);
|
||||
mesh.Vertices[i * 3 + 1] = r * MathF.Sin(theta) * MathF.Sin(phi);
|
||||
mesh.Vertices[i * 3 + 2] = r * MathF.Cos(theta);
|
||||
|
||||
var color = ColorFromHSV(r * 360.0f, 1.0f, 1.0f);
|
||||
|
||||
mesh.Colors[i * 4 + 0] = color.R;
|
||||
mesh.Colors[i * 4 + 1] = color.G;
|
||||
mesh.Colors[i * 4 + 2] = color.B;
|
||||
mesh.Colors[i * 4 + 3] = color.A;
|
||||
}
|
||||
|
||||
// Upload mesh data from CPU (RAM) to GPU (VRAM) memory
|
||||
UploadMesh(ref mesh, false);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// Draw a model points
|
||||
// WARNING: OpenGL ES 2.0 does not support point mode drawing
|
||||
private static void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
Rlgl.EnablePointMode();
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
|
||||
DrawModel(model, position, scale, tint);
|
||||
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.DisablePointMode();
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new PointRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
122
Examples/Models/RotatingCube.cs
Normal file
122
Examples/Models/RotatingCube.cs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - rotating cube
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Jopestpe (@jopestpe)
|
||||
*
|
||||
* 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 Jopestpe (@jopestpe)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class RotatingCube : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Rotating Cube";
|
||||
|
||||
public string Title => "raylib [models] example - rotating cube";
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
private float rotation;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 3.0f, 3.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load image to create texture for the cube
|
||||
model = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f));
|
||||
var img = LoadImage("resources/cubicmap_atlas.png");
|
||||
var crop = ImageFromImage(img, new Rectangle(0, img.Height / 2.0f, img.Width / 2.0f, img.Height / 2.0f));
|
||||
texture = LoadTextureFromImage(crop);
|
||||
UnloadImage(img);
|
||||
UnloadImage(crop);
|
||||
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture;
|
||||
|
||||
rotation = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation += 1.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw model defining: position, size, rotation-axis, rotation (degrees), size, and tint-color
|
||||
DrawModelEx(model, new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.5f, 1.0f, 0.0f),
|
||||
rotation, new Vector3(1.0f, 1.0f, 1.0f), Color.White);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadTexture(texture); // Unload texture
|
||||
UnloadModel(model); // Unload model
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rotating cube");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new RotatingCube();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,54 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Skybox loading and drawing
|
||||
* raylib [models] example - skybox rendering
|
||||
*
|
||||
* This example has been created using raylib 1.8 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2017 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.8, last time updated with raylib 4.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) 2017-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class SkyboxDemo
|
||||
[ExcludeFromBrowser("cubemap generation is too memory-heavy on web (upstream note)")]
|
||||
public partial class SkyboxDemo : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// GLSL version used for shaders (330 desktop, 100 web/GLES)
|
||||
#if BROWSER
|
||||
public const int GlslVersion = 100;
|
||||
#else
|
||||
public const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Models / Skybox Demo";
|
||||
|
||||
public string Title => "raylib [models] example - skybox rendering";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model skybox;
|
||||
private bool useHdr;
|
||||
private Shader shdrCubemap;
|
||||
private string skyboxFileName;
|
||||
private Texture2D panorama;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox loading and drawing");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera = new();
|
||||
camera.Position = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
camera.Target = new Vector3(4.0f, 1.0f, 4.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
|
@ -34,14 +56,19 @@ public class SkyboxDemo
|
|||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load skybox model
|
||||
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
Model skybox = LoadModelFromMesh(cube);
|
||||
var cube = GenMeshCube(1.0f, 1.0f, 1.0f);
|
||||
skybox = LoadModelFromMesh(cube);
|
||||
|
||||
bool useHdr = false;
|
||||
// Set this to true to use an HDR Texture
|
||||
// NOTE: raylib must be built with HDR Support for this to work: SUPPORT_FILEFORMAT_HDR
|
||||
useHdr = false;
|
||||
|
||||
// Load skybox shader and set required locations
|
||||
// NOTE: Some locations are automatically set at shader loading
|
||||
Shader shdrSkybox = LoadShader("resources/shaders/glsl330/skybox.vs", "resources/shaders/glsl330/skybox.fs");
|
||||
var shdrSkybox = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/skybox.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/skybox.fs"
|
||||
);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
shdrSkybox,
|
||||
|
|
@ -67,9 +94,9 @@ public class SkyboxDemo
|
|||
Raylib.SetMaterialShader(ref skybox, 0, ref shdrSkybox);
|
||||
|
||||
// Load cubemap shader and setup required shader locations
|
||||
Shader shdrCubemap = LoadShader(
|
||||
"resources/shaders/glsl330/cubemap.vs",
|
||||
"resources/shaders/glsl330/cubemap.fs"
|
||||
shdrCubemap = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/cubemap.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/cubemap.fs"
|
||||
);
|
||||
Raylib.SetShaderValue(
|
||||
shdrCubemap,
|
||||
|
|
@ -79,14 +106,12 @@ public class SkyboxDemo
|
|||
);
|
||||
|
||||
// Load skybox
|
||||
string skyboxFileName = "resources/dresden_square_2k.hdr";
|
||||
|
||||
Texture2D panorama;
|
||||
skyboxFileName = "resources/dresden_square_2k.hdr";
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
panorama = LoadTexture(skyboxFileName);
|
||||
Texture2D cubemap = GenTextureCubemap(
|
||||
var cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
|
|
@ -97,108 +122,130 @@ public class SkyboxDemo
|
|||
}
|
||||
else
|
||||
{
|
||||
Image img = LoadImage("resources/skybox.png");
|
||||
Texture2D cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
// TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image
|
||||
// and generate the required cubemap image to be passed to rlLoadTextureCubemap()
|
||||
var img = LoadImage("resources/skybox.png");
|
||||
var cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
}
|
||||
|
||||
DisableCursor();
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
// Load new cubemap texture on drag & drop
|
||||
if (IsFileDropped())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
||||
var files = Raylib.GetDroppedFiles();
|
||||
|
||||
// Load new cubemap texture on drag & drop
|
||||
if (IsFileDropped())
|
||||
if (files.Length == 1)
|
||||
{
|
||||
string[] files = Raylib.GetDroppedFiles();
|
||||
|
||||
if (files.Length == 1)
|
||||
if (IsFileExtension(files[0], ".png;.jpg;.hdr;.bmp;.tga"))
|
||||
{
|
||||
if (IsFileExtension(files[0], ".png;.jpg;.hdr;.bmp;.tga"))
|
||||
// Unload cubemap texture and load new one
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
// Unload cubemap texture and load new one
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
panorama = LoadTexture(files[0]);
|
||||
Texture2D cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
PixelFormat.UncompressedR8G8B8A8
|
||||
);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadTexture(panorama);
|
||||
}
|
||||
else
|
||||
{
|
||||
Image img = LoadImage(files[0]);
|
||||
Texture2D cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
|
||||
skyboxFileName = files[0];
|
||||
panorama = LoadTexture(files[0]);
|
||||
var cubemap = GenTextureCubemap(
|
||||
shdrCubemap,
|
||||
panorama,
|
||||
1024,
|
||||
PixelFormat.UncompressedR8G8B8A8
|
||||
);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadTexture(panorama);
|
||||
}
|
||||
else
|
||||
{
|
||||
var img = LoadImage(files[0]);
|
||||
var cubemap = LoadTextureCubemap(img, CubemapLayout.AutoDetect);
|
||||
SetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap, ref cubemap);
|
||||
UnloadImage(img);
|
||||
}
|
||||
|
||||
skyboxFileName = files[0];
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
BeginMode3D(camera);
|
||||
|
||||
// We are inside the cube, we need to disable backface culling!
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
Rlgl.DisableDepthMask();
|
||||
DrawModel(skybox, Vector3.Zero, 1.0f, Color.White);
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.EnableDepthMask();
|
||||
// We are inside the cube, we need to disable backface culling!
|
||||
Rlgl.DisableBackfaceCulling();
|
||||
Rlgl.DisableDepthMask();
|
||||
DrawModel(skybox, Vector3.Zero, 1.0f, Color.White);
|
||||
Rlgl.EnableBackfaceCulling();
|
||||
Rlgl.EnableDepthMask();
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
EndMode3D();
|
||||
|
||||
if (useHdr)
|
||||
{
|
||||
DrawText(
|
||||
$"Panorama image from hdrihaven.com: {skyboxFileName}",
|
||||
10,
|
||||
GetScreenHeight() - 20,
|
||||
10,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($": {skyboxFileName}", 10, GetScreenHeight() - 20, 10, Color.Black);
|
||||
}
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
if (useHdr)
|
||||
{
|
||||
DrawText(
|
||||
$"Panorama image from hdrihaven.com: {skyboxFileName}",
|
||||
10,
|
||||
GetScreenHeight() - 20,
|
||||
10,
|
||||
Color.Black
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText($": {skyboxFileName}", 10, GetScreenHeight() - 20, 10, Color.Black);
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(Raylib.GetMaterial(ref skybox, 0).Shader);
|
||||
UnloadTexture(Raylib.GetMaterialTexture(ref skybox, 0, MaterialMapIndex.Cubemap));
|
||||
|
||||
UnloadModel(skybox);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox rendering");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SkyboxDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -215,10 +262,10 @@ public class SkyboxDemo
|
|||
|
||||
// STEP 1: Setup framebuffer
|
||||
//------------------------------------------------------------------------------------------
|
||||
uint rbo = Rlgl.LoadTextureDepth(size, size, true);
|
||||
var rbo = Rlgl.LoadTextureDepth(size, size, true);
|
||||
cubemap.Id = Rlgl.LoadTextureCubemap(null, size, format, 1);
|
||||
|
||||
uint fbo = Rlgl.LoadFramebuffer();
|
||||
var fbo = Rlgl.LoadFramebuffer();
|
||||
Rlgl.FramebufferAttach(
|
||||
fbo,
|
||||
rbo,
|
||||
|
|
@ -235,7 +282,7 @@ public class SkyboxDemo
|
|||
);
|
||||
|
||||
// Check if framebuffer is complete with attachments (valid)
|
||||
if (Rlgl.FramebufferComplete(fbo))
|
||||
if (Rlgl.FramebufferComplete(fbo) != 0)
|
||||
{
|
||||
Console.WriteLine($"FBO: [ID {fbo}] Framebuffer object created successfully");
|
||||
}
|
||||
|
|
@ -247,7 +294,7 @@ public class SkyboxDemo
|
|||
Rlgl.EnableShader(shader.Id);
|
||||
|
||||
// Define projection matrix and send it to shader
|
||||
Matrix4x4 matFboProjection = Raymath.MatrixPerspective(
|
||||
var matFboProjection = Raymath.MatrixPerspective(
|
||||
90.0f * DEG2RAD,
|
||||
1.0f,
|
||||
Rlgl.CULL_DISTANCE_NEAR,
|
||||
|
|
@ -256,14 +303,14 @@ public class SkyboxDemo
|
|||
Rlgl.SetUniformMatrix(shader.Locs[(int)ShaderLocationIndex.MatrixProjection], matFboProjection);
|
||||
|
||||
// Define view matrix for every side of the cubemap
|
||||
Matrix4x4[] fboViews = new[]
|
||||
var fboViews = new[]
|
||||
{
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3(-1.0f, 0.0f, 0.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 1.0f, 0.0f), new Vector3( 0.0f, 0.0f, 1.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, -1.0f, 0.0f), new Vector3( 0.0f, 0.0f, -1.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, 1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
Raymath.MatrixLookAt(Vector3.Zero, new Vector3( 0.0f, 0.0f, -1.0f), new Vector3( 0.0f, -1.0f, 0.0f)),
|
||||
};
|
||||
|
||||
// Set viewport to current fbo dimensions
|
||||
|
|
@ -273,7 +320,7 @@ public class SkyboxDemo
|
|||
Rlgl.ActiveTextureSlot(0);
|
||||
Rlgl.EnableTexture(panorama.Id);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
// Set the view matrix for the current cube face
|
||||
Rlgl.SetUniformMatrix(shader.Locs[(int)ShaderLocationIndex.MatrixView], fboViews[i]);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - rlgl module usage with push/pop matrix transformations
|
||||
* raylib [models] example - rlgl solar system
|
||||
*
|
||||
* This example uses [rlgl] module funtionality (pseudo-OpenGL 1.1 style coding)
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* 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)
|
||||
* NOTE: This example uses [rlgl] module functionality (pseudo-OpenGL 1.1 style coding)
|
||||
*
|
||||
* Copyright (c) 2018 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 4.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) 2018-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -17,145 +21,137 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class SolarSystem
|
||||
public partial class SolarSystem : IExample
|
||||
{
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const float sunRadius = 4.0f;
|
||||
private const float earthRadius = 0.6f;
|
||||
private const float earthOrbitRadius = 8.0f;
|
||||
private const float moonRadius = 0.16f;
|
||||
private const float moonOrbitRadius = 1.5f;
|
||||
|
||||
public string Name => "Models / Solar System";
|
||||
|
||||
public string Title => "raylib [models] example - rlgl solar system";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private float rotationSpeed;
|
||||
|
||||
private float earthRotation;
|
||||
private float earthOrbitRotation;
|
||||
private float moonRotation;
|
||||
private float moonOrbitRotation;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
const float sunRadius = 4.0f;
|
||||
const float earthRadius = 0.6f;
|
||||
const float earthOrbitRadius = 8.0f;
|
||||
const float moonRadius = 0.16f;
|
||||
const float moonOrbitRadius = 1.5f;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl module usage with push/pop matrix transformations");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(16.0f, 16.0f, 16.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(16.0f, 16.0f, 16.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// General system rotation speed
|
||||
float rotationSpeed = 0.2f;
|
||||
// Rotation of earth around itself (days) in degrees
|
||||
float earthRotation = 0.0f;
|
||||
// Rotation of earth around the Sun (years) in degrees
|
||||
float earthOrbitRotation = 0.0f;
|
||||
// Rotation of moon around itself
|
||||
float moonRotation = 0.0f;
|
||||
// Rotation of moon around earth in degrees
|
||||
float moonOrbitRotation = 0.0f;
|
||||
rotationSpeed = 0.2f; // General system rotation speed
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
earthRotation = 0.0f; // Rotation of earth around itself (days) in degrees
|
||||
earthOrbitRotation = 0.0f; // Rotation of earth around the Sun (years) in degrees
|
||||
moonRotation = 0.0f; // Rotation of moon around itself
|
||||
moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees
|
||||
}
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
earthRotation += (5.0f * rotationSpeed);
|
||||
earthOrbitRotation += (365 / 360.0f * (5.0f * rotationSpeed) * rotationSpeed);
|
||||
moonRotation += (2.0f * rotationSpeed);
|
||||
moonOrbitRotation += (8.0f * rotationSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
earthRotation += (5.0f * rotationSpeed);
|
||||
earthOrbitRotation += (365 / 360.0f * (5.0f * rotationSpeed) * rotationSpeed);
|
||||
moonRotation += (2.0f * rotationSpeed);
|
||||
moonOrbitRotation += (8.0f * rotationSpeed);
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginMode3D(camera);
|
||||
Rlgl.PushMatrix();
|
||||
// Scale Sun
|
||||
Rlgl.Scalef(sunRadius, sunRadius, sunRadius);
|
||||
// Draw the Sun
|
||||
DrawSphereBasic(Color.Gold);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Scale Sun
|
||||
Rlgl.Scalef(sunRadius, sunRadius, sunRadius);
|
||||
// Draw the Sun
|
||||
DrawSphereBasic(Color.Gold);
|
||||
Rlgl.PopMatrix();
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth orbit around Sun
|
||||
Rlgl.Rotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Earth orbit
|
||||
Rlgl.Translatef(earthOrbitRadius, 0.0f, 0.0f);
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth orbit around Sun
|
||||
Rlgl.Rotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Earth orbit
|
||||
Rlgl.Translatef(earthOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Earth orbit around Sun inverted
|
||||
Rlgl.Rotatef(-earthOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth itself
|
||||
Rlgl.Rotatef(earthRotation, 0.25f, 1.0f, 0.0f);
|
||||
// Scale Earth
|
||||
Rlgl.Scalef(earthRadius, earthRadius, earthRadius);
|
||||
|
||||
Rlgl.PushMatrix();
|
||||
// Rotation for Earth itself
|
||||
Rlgl.Rotatef(earthRotation, 0.25f, 1.0f, 0.0f);
|
||||
// Scale Earth
|
||||
Rlgl.Scalef(earthRadius, earthRadius, earthRadius);
|
||||
// Draw the Earth
|
||||
DrawSphereBasic(Color.Blue);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw the Earth
|
||||
DrawSphereBasic(Color.Blue);
|
||||
Rlgl.PopMatrix();
|
||||
// Rotation for Moon orbit around Earth
|
||||
Rlgl.Rotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Moon orbit
|
||||
Rlgl.Translatef(moonOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Moon itself
|
||||
Rlgl.Rotatef(moonRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Scale Moon
|
||||
Rlgl.Scalef(moonRadius, moonRadius, moonRadius);
|
||||
|
||||
// Rotation for Moon orbit around Earth
|
||||
Rlgl.Rotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Translation for Moon orbit
|
||||
Rlgl.Translatef(moonOrbitRadius, 0.0f, 0.0f);
|
||||
// Rotation for Moon orbit around Earth inverted
|
||||
Rlgl.Rotatef(-moonOrbitRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Rotation for Moon itself
|
||||
Rlgl.Rotatef(moonRotation, 0.0f, 1.0f, 0.0f);
|
||||
// Scale Moon
|
||||
Rlgl.Scalef(moonRadius, moonRadius, moonRadius);
|
||||
// Draw the Moon
|
||||
DrawSphereBasic(Color.LightGray);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw the Moon
|
||||
DrawSphereBasic(Color.LightGray);
|
||||
Rlgl.PopMatrix();
|
||||
// Some reference elements (not affected by previous matrix transformations)
|
||||
DrawCircle3D(
|
||||
new Vector3(0.0f, 0.0f, 0.0f),
|
||||
earthOrbitRadius,
|
||||
new Vector3(1, 0, 0),
|
||||
90.0f,
|
||||
Fade(Color.Red, 0.5f)
|
||||
);
|
||||
DrawGrid(20, 1.0f);
|
||||
|
||||
// Some reference elements (not affected by previous matrix transformations)
|
||||
DrawCircle3D(
|
||||
new Vector3(0.0f, 0.0f, 0.0f),
|
||||
earthOrbitRadius,
|
||||
new Vector3(1, 0, 0),
|
||||
90.0f,
|
||||
ColorAlpha(Color.Red, 0.5f)
|
||||
);
|
||||
DrawGrid(20, 1.0f);
|
||||
EndMode3D();
|
||||
|
||||
EndMode3D();
|
||||
DrawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, Color.Maroon);
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText("EARTH ORBITING AROUND THE SUN!", 400, 10, 20, Color.Maroon);
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Draw sphere without any matrix transformation
|
||||
// NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f
|
||||
static void DrawSphereBasic(Color color)
|
||||
private static void DrawSphereBasic(Color color)
|
||||
{
|
||||
int rings = 16;
|
||||
int slices = 16;
|
||||
var rings = 16;
|
||||
var slices = 16;
|
||||
|
||||
Rlgl.Begin(DrawMode.Triangles);
|
||||
Rlgl.Color4ub(color.R, color.G, color.B, color.A);
|
||||
|
||||
for (int i = 0; i < (rings + 2); i++)
|
||||
for (var i = 0; i < (rings + 2); i++)
|
||||
{
|
||||
for (int j = 0; j < slices; j++)
|
||||
for (var j = 0; j < slices; j++)
|
||||
{
|
||||
Rlgl.Vertex3f(
|
||||
MathF.Cos(DEG2RAD * (270 + (180 / (rings + 1)) * i)) * MathF.Sin(DEG2RAD * (j * 360 / slices)),
|
||||
|
|
@ -192,5 +188,32 @@ public class SolarSystem
|
|||
}
|
||||
Rlgl.End();
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl solar system");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SolarSystem();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
163
Examples/Models/TesseractView.cs
Normal file
163
Examples/Models/TesseractView.cs
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - tesseract view
|
||||
*
|
||||
* NOTE: This example only works on platforms that support drag & drop (Windows, Linux, OSX, Html5?)
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Timothy van der Valk (@arceryz) 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) 2024-2025 Timothy van der Valk (@arceryz) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Models;
|
||||
|
||||
public partial class TesseractView : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Tesseract View";
|
||||
|
||||
public string Title => "raylib [models] example - tesseract view";
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
private Camera3D camera;
|
||||
|
||||
// Find the coordinates by setting XYZW to +-1
|
||||
private Vector4[] tesseract;
|
||||
|
||||
private float rotation;
|
||||
private Vector3[] transformed;
|
||||
private float[] wValues;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new Camera3D();
|
||||
camera.Position = new Vector3(4.0f, 4.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 0.0f, 1.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 50.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
// Find the coordinates by setting XYZW to +-1
|
||||
tesseract = new Vector4[16]
|
||||
{
|
||||
new( 1, 1, 1, 1 ), new( 1, 1, 1, -1 ),
|
||||
new( 1, 1, -1, 1 ), new( 1, 1, -1, -1 ),
|
||||
new( 1, -1, 1, 1 ), new( 1, -1, 1, -1 ),
|
||||
new( 1, -1, -1, 1 ), new( 1, -1, -1, -1 ),
|
||||
new(-1, 1, 1, 1 ), new(-1, 1, 1, -1 ),
|
||||
new(-1, 1, -1, 1 ), new(-1, 1, -1, -1 ),
|
||||
new(-1, -1, 1, 1 ), new(-1, -1, 1, -1 ),
|
||||
new(-1, -1, -1, 1 ), new(-1, -1, -1, -1 ),
|
||||
};
|
||||
|
||||
rotation = 0.0f;
|
||||
transformed = new Vector3[16];
|
||||
wValues = new float[16];
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
rotation = DEG2RAD * 45.0f * (float)GetTime();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Vector4 p = tesseract[i];
|
||||
|
||||
// Rotate the XW part of the vector
|
||||
Vector2 rotXW = Vector2Rotate(new Vector2(p.X, p.W), rotation);
|
||||
p.X = rotXW.X;
|
||||
p.W = rotXW.Y;
|
||||
|
||||
// Projection from XYZW to XYZ from perspective point (0, 0, 0, 3)
|
||||
// NOTE: Trace a ray from (0, 0, 0, 3) > p and continue until W = 0
|
||||
float c = 3.0f / (3.0f - p.W);
|
||||
p.X = c * p.X;
|
||||
p.Y = c * p.Y;
|
||||
p.Z = c * p.Z;
|
||||
|
||||
// Split XYZ coordinate and W values later for drawing
|
||||
transformed[i] = new Vector3(p.X, p.Y, p.Z);
|
||||
wValues[i] = p.W;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
// Draw spheres to indicate the W value
|
||||
DrawSphere(transformed[i], MathF.Abs(wValues[i] * 0.1f), Color.Red);
|
||||
|
||||
for (int j = 0; j < 16; j++)
|
||||
{
|
||||
// Two lines are connected if they differ by 1 coordinate
|
||||
// This way we dont have to keep an edge list
|
||||
Vector4 v1 = tesseract[i];
|
||||
Vector4 v2 = tesseract[j];
|
||||
int diff = (v1.X == v2.X ? 1 : 0) + (v1.Y == v2.Y ? 1 : 0) + (v1.Z == v2.Z ? 1 : 0) + (v1.W == v2.W ? 1 : 0);
|
||||
|
||||
// Draw only differing by 1 coordinate and the lower index only (duplicate lines)
|
||||
if (diff == 3 && i < j) DrawLine3D(transformed[i], transformed[j], Color.Maroon);
|
||||
}
|
||||
}
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - tesseract view");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new TesseractView();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Waving cubes
|
||||
* raylib [models] example - waving cubes
|
||||
*
|
||||
* 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: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.7
|
||||
*
|
||||
* Example contributed by Codecat (@codecat) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 Codecat (@codecat) 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 Codecat (@codecat) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -17,101 +21,125 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class WavingCubes
|
||||
public partial class WavingCubes : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
// Specify the amount of blocks in each direction
|
||||
private const int numBlocks = 15;
|
||||
|
||||
public string Name => "Models / Waving Cubes";
|
||||
|
||||
public string Title => "raylib [models] example - waving cubes";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialize the camera
|
||||
camera = new();
|
||||
camera.Position = new Vector3(30.0f, 20.0f, 30.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 70.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var time = GetTime();
|
||||
|
||||
// Calculate time scale for cube position and size
|
||||
var scale = (2.0f + (float)Math.Sin(time)) * 0.7f;
|
||||
|
||||
// Move camera around the scene
|
||||
var cameraTime = time * 0.3;
|
||||
camera.Position.X = (float)Math.Cos(cameraTime) * 40.0f;
|
||||
camera.Position.Z = (float)Math.Sin(cameraTime) * 40.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 5.0f);
|
||||
|
||||
for (var x = 0; x < numBlocks; x++)
|
||||
{
|
||||
for (var y = 0; y < numBlocks; y++)
|
||||
{
|
||||
for (var z = 0; z < numBlocks; z++)
|
||||
{
|
||||
// Scale of the blocks depends on x/y/z positions
|
||||
var blockScale = (x + y + z) / 30.0f;
|
||||
|
||||
// Scatter makes the waving effect by adding blockScale over time
|
||||
var scatter = (float)Math.Sin(blockScale * 20.0f + (float)(time * 4.0f));
|
||||
|
||||
// Calculate the cube position
|
||||
Vector3 cubePos = new(
|
||||
(float)(x - numBlocks / 2) * (scale * 3.0f) + scatter,
|
||||
(float)(y - numBlocks / 2) * (scale * 2.0f) + scatter,
|
||||
(float)(z - numBlocks / 2) * (scale * 3.0f) + scatter
|
||||
);
|
||||
|
||||
// Pick a color with a hue depending on cube position for the rainbow color effect
|
||||
// NOTE: This function is quite costly to be done per cube and frame,
|
||||
// pre-catching the results into a separate array could improve performance
|
||||
var cubeColor = ColorFromHSV((float)(((x + y + z) * 18) % 360), 0.75f, 0.9f);
|
||||
|
||||
// Calculate cube size
|
||||
var cubeSize = (2.4f - scale) * blockScale;
|
||||
|
||||
// And finally, draw the cube!
|
||||
DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - waving cubes");
|
||||
|
||||
// Initialize the camera
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(30.0f, 20.0f, 30.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 70.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Specify the amount of blocks in each direction
|
||||
const int numBlocks = 15;
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new WavingCubes();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
double time = GetTime();
|
||||
|
||||
// Calculate time scale for cube position and size
|
||||
float scale = (2.0f + (float)Math.Sin(time)) * 0.7f;
|
||||
|
||||
// Move camera around the scene
|
||||
double cameraTime = time * 0.3;
|
||||
camera.Position.X = (float)Math.Cos(cameraTime) * 40.0f;
|
||||
camera.Position.Z = (float)Math.Sin(cameraTime) * 40.0f;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawGrid(10, 5.0f);
|
||||
|
||||
for (int x = 0; x < numBlocks; x++)
|
||||
{
|
||||
for (int y = 0; y < numBlocks; y++)
|
||||
{
|
||||
for (int z = 0; z < numBlocks; z++)
|
||||
{
|
||||
// Scale of the blocks depends on x/y/z positions
|
||||
float blockScale = (x + y + z) / 30.0f;
|
||||
|
||||
// Scatter makes the waving effect by adding blockScale over time
|
||||
float scatter = (float)Math.Sin(blockScale * 20.0f + (float)(time * 4.0f));
|
||||
|
||||
// Calculate the cube position
|
||||
Vector3 cubePos = new(
|
||||
(float)(x - numBlocks / 2) * (scale * 3.0f) + scatter,
|
||||
(float)(y - numBlocks / 2) * (scale * 2.0f) + scatter,
|
||||
(float)(z - numBlocks / 2) * (scale * 3.0f) + scatter
|
||||
);
|
||||
|
||||
// Pick a color with a hue depending on cube position for the rainbow color effect
|
||||
Color cubeColor = ColorFromHSV((float)(((x + y + z) * 18) % 360), 0.75f, 0.9f);
|
||||
|
||||
// Calculate cube size
|
||||
float cubeSize = (2.4f - scale) * blockScale;
|
||||
|
||||
// And finally, draw the cube!
|
||||
DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [models] example - Plane rotations (yaw, pitch, roll)
|
||||
* raylib [models] example - yaw pitch roll
|
||||
*
|
||||
* This example has been created using raylib 1.8 (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 1.8, last time updated with raylib 4.0
|
||||
*
|
||||
* Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2017-2021 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) 2017-2025 Berni (@Berni8k) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -17,146 +21,178 @@ using static Raylib_cs.Raymath;
|
|||
|
||||
namespace Examples.Models;
|
||||
|
||||
public class YawPitchRoll
|
||||
public partial class YawPitchRoll : IExample
|
||||
{
|
||||
public unsafe static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Models / Yaw Pitch Roll";
|
||||
|
||||
public string Title => "raylib [models] example - yaw pitch roll";
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
private Model model;
|
||||
private Texture2D texture;
|
||||
|
||||
private float pitch;
|
||||
private float roll;
|
||||
private float yaw;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 50.0f, -120.0f);// Camera position perspective
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 30.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera type
|
||||
|
||||
model = LoadModel("resources/models/obj/plane.obj"); // Load model
|
||||
texture = LoadTexture("resources/models/obj/plane_diffuse.png"); // Load model texture
|
||||
|
||||
SetTextureWrap(texture, TextureWrap.Repeat); // Force Repeat to avoid issue on Web version
|
||||
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture; // Set map diffuse texture
|
||||
|
||||
pitch = 0.0f;
|
||||
roll = 0.0f;
|
||||
yaw = 0.0f;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Plane pitch (x-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch += 0.6f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch -= 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch > 0.3f)
|
||||
{
|
||||
pitch -= 0.3f;
|
||||
}
|
||||
else if (pitch < -0.3f)
|
||||
{
|
||||
pitch += 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane yaw (y-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
yaw += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
yaw -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yaw > 0.0f)
|
||||
{
|
||||
yaw -= 0.5f;
|
||||
}
|
||||
else if (yaw < 0.0f)
|
||||
{
|
||||
yaw += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane roll (z-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
roll += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
roll -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (roll > 0.0f)
|
||||
{
|
||||
roll -= 0.5f;
|
||||
}
|
||||
else if (roll < 0.0f)
|
||||
{
|
||||
roll += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Tranformation matrix for rotations
|
||||
model.Transform = MatrixRotateXYZ(new Vector3(DEG2RAD * pitch, DEG2RAD * yaw, DEG2RAD * roll));
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model (recomended to draw 3D always before 2D)
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
DrawModel(model, new Vector3(0.0f, -8.0f, 0.0f), 1.0f, Color.White);
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw controls info
|
||||
DrawRectangle(30, 370, 260, 70, Fade(Color.Green, 0.5f));
|
||||
DrawRectangleLines(30, 370, 260, 70, Fade(Color.DarkGreen, 0.5f));
|
||||
DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, Color.DarkGray);
|
||||
DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, Color.DarkGray);
|
||||
DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, Color.DarkGray);
|
||||
|
||||
DrawText(
|
||||
"(c) WWI Plane Model created by GiaHanLam",
|
||||
screenWidth - 240,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - plane rotations (yaw, pitch, roll)");
|
||||
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.0f, 50.0f, -120.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 30.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Model loading
|
||||
Model model = LoadModel("resources/models/obj/plane.obj");
|
||||
Texture2D texture = LoadTexture("resources/models/obj/plane_diffuse.png");
|
||||
model.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Texture = texture;
|
||||
|
||||
float pitch = 0.0f;
|
||||
float roll = 0.0f;
|
||||
float yaw = 0.0f;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [models] example - yaw pitch roll");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
while (!WindowShouldClose())
|
||||
var game = new YawPitchRoll();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Plane roll (x-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch += 0.6f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch -= 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch > 0.3f)
|
||||
{
|
||||
pitch -= 0.3f;
|
||||
}
|
||||
else if (pitch < -0.3f)
|
||||
{
|
||||
pitch += 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane yaw (y-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
yaw += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
yaw -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yaw > 0.0f)
|
||||
{
|
||||
yaw -= 0.5f;
|
||||
}
|
||||
else if (yaw < 0.0f)
|
||||
{
|
||||
yaw += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Plane pitch (z-axis) controls
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
roll += 1.0f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
roll -= 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (roll > 0.0f)
|
||||
{
|
||||
roll -= 0.5f;
|
||||
}
|
||||
else if (roll < 0.0f)
|
||||
{
|
||||
roll += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
// Tranformation matrix for rotations
|
||||
model.Transform = MatrixRotateXYZ(new Vector3(DEG2RAD * pitch, DEG2RAD * yaw, DEG2RAD * roll));
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// Draw 3D model (recomended to draw 3D always before 2D)
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw 3d model with texture
|
||||
DrawModel(model, new Vector3(0.0f, -8.0f, 0.0f), 1.0f, Color.White);
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw controls info
|
||||
DrawRectangle(30, 370, 260, 70, Fade(Color.Green, 0.5f));
|
||||
DrawRectangleLines(30, 370, 260, 70, Fade(Color.DarkGreen, 0.5f));
|
||||
DrawText("Pitch controlled with: KEY_UP / KEY_DOWN", 40, 380, 10, Color.DarkGray);
|
||||
DrawText("Roll controlled with: KEY_LEFT / KEY_RIGHT", 40, 400, 10, Color.DarkGray);
|
||||
DrawText("Yaw controlled with: KEY_A / KEY_S", 40, 420, 10, Color.DarkGray);
|
||||
|
||||
DrawText(
|
||||
"(c) WWI Plane Model created by GiaHanLam",
|
||||
screenWidth - 240,
|
||||
screenHeight - 20,
|
||||
10,
|
||||
Color.DarkGray
|
||||
);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(model);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,195 +1,88 @@
|
|||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using Examples.Core;
|
||||
using Examples.Shapes;
|
||||
using Examples.Textures;
|
||||
using Examples.Text;
|
||||
using Examples.Models;
|
||||
using Examples.Shaders;
|
||||
using Examples.Audio;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
public class ExampleInfo
|
||||
internal static class Program
|
||||
{
|
||||
public ExampleInfo(string name, Func<int> main)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Main = main;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public Func<int> Main
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
new ExampleInfo("Camera3dFree", Camera3dFree.Main),
|
||||
new ExampleInfo("Camera3dMode", Camera3dMode.Main),
|
||||
new ExampleInfo("Picking3d", Picking3d.Main),
|
||||
new ExampleInfo("BasicScreenManager", BasicScreenManager.Main),
|
||||
new ExampleInfo("BasicWindow", BasicWindow.Main),
|
||||
new ExampleInfo("CustomLogging", CustomLogging.Main),
|
||||
new ExampleInfo("DropFiles", DropFiles.Main),
|
||||
new ExampleInfo("InputGamepad", InputGamepad.Main),
|
||||
new ExampleInfo("InputGestures", InputGestures.Main),
|
||||
new ExampleInfo("InputKeys", InputKeys.Main),
|
||||
new ExampleInfo("InputMouseWheel", InputMouseWheel.Main),
|
||||
new ExampleInfo("InputMouse", InputMouse.Main),
|
||||
new ExampleInfo("InputMultitouch", InputMultitouch.Main),
|
||||
new ExampleInfo("RandomValues", RandomValues.Main),
|
||||
new ExampleInfo("ScissorTest", ScissorTest.Main),
|
||||
new ExampleInfo("SmoothPixelPerfect", SmoothPixelPerfect.Main),
|
||||
new ExampleInfo("SplitScreen", SplitScreen.Main),
|
||||
new ExampleInfo("StorageValues", StorageValues.Main),
|
||||
new ExampleInfo("VrSimulator", VrSimulator.Main),
|
||||
new ExampleInfo("WindowFlags", WindowFlags.Main),
|
||||
new ExampleInfo("WindowLetterbox", WindowLetterbox.Main),
|
||||
new ExampleInfo("WorldScreen", WorldScreen.Main),
|
||||
|
||||
// Shapes
|
||||
new ExampleInfo("BasicShapes", BasicShapes.Main),
|
||||
new ExampleInfo("BouncingBall", BouncingBall.Main),
|
||||
new ExampleInfo("CollisionArea", CollisionArea.Main),
|
||||
new ExampleInfo("ColorsPalette", ColorsPalette.Main),
|
||||
new ExampleInfo("EasingsBallAnim", EasingsBallAnim.Main),
|
||||
new ExampleInfo("EasingsBoxAnim", EasingsBoxAnim.Main),
|
||||
new ExampleInfo("EasingsRectangleArray", EasingsRectangleArray.Main),
|
||||
new ExampleInfo("FollowingEyes", FollowingEyes.Main),
|
||||
new ExampleInfo("LinesBezier", LinesBezier.Main),
|
||||
new ExampleInfo("LogoRaylibAnim", LogoRaylibAnim.Main),
|
||||
new ExampleInfo("LogoRaylibShape", LogoRaylibShape.Main),
|
||||
new ExampleInfo("RectangleScaling", RectangleScaling.Main),
|
||||
|
||||
// Textures
|
||||
new ExampleInfo("BackgroundScrolling", BackgroundScrolling.Main),
|
||||
new ExampleInfo("BlendModes", BlendModes.Main),
|
||||
new ExampleInfo("Bunnymark", Bunnymark.Main),
|
||||
new ExampleInfo("DrawTiled", DrawTiled.Main),
|
||||
new ExampleInfo("ImageDrawing", ImageDrawing.Main),
|
||||
new ExampleInfo("ImageGeneration", ImageGeneration.Main),
|
||||
new ExampleInfo("ImageLoading", ImageLoading.Main),
|
||||
new ExampleInfo("ImageProcessing", ImageProcessing.Main),
|
||||
new ExampleInfo("ImageText", ImageText.Main),
|
||||
new ExampleInfo("LogoRaylibTexture", LogoRaylibTexture.Main),
|
||||
new ExampleInfo("MousePainting", MousePainting.Main),
|
||||
new ExampleInfo("NpatchDrawing", NpatchDrawing.Main),
|
||||
new ExampleInfo("ParticlesBlending", ParticlesBlending.Main),
|
||||
new ExampleInfo("TexturedCurve", TexturedCurve.Main),
|
||||
new ExampleInfo("Polygon", Polygon.Main),
|
||||
new ExampleInfo("RawData", RawData.Main),
|
||||
new ExampleInfo("SpriteAnim", SpriteAnim.Main),
|
||||
new ExampleInfo("SpriteButton", SpriteButton.Main),
|
||||
new ExampleInfo("SpriteExplosion", SpriteExplosion.Main),
|
||||
new ExampleInfo("SrcRecDstRec", SrcRecDstRec.Main),
|
||||
new ExampleInfo("ToImage", ToImage.Main),
|
||||
|
||||
// Text
|
||||
new ExampleInfo("CodepointsLoading", CodepointsLoading.Main),
|
||||
new ExampleInfo("FontFilters", FontFilters.Main),
|
||||
new ExampleInfo("FontLoading", FontLoading.Main),
|
||||
new ExampleInfo("FontSdf", FontSdf.Main),
|
||||
new ExampleInfo("FontSpritefont", FontSpritefont.Main),
|
||||
new ExampleInfo("FormatText", FormatText.Main),
|
||||
new ExampleInfo("InputBox", InputBox.Main),
|
||||
new ExampleInfo("RaylibFonts", RaylibFonts.Main),
|
||||
new ExampleInfo("RectangleBounds", RectangleBounds.Main),
|
||||
new ExampleInfo("WritingAnim", WritingAnim.Main),
|
||||
|
||||
// Models
|
||||
new ExampleInfo("LoadingIqm", LoadingIqm.Main),
|
||||
new ExampleInfo("LoadingGltf", LoadingGltf.Main),
|
||||
new ExampleInfo("BillboardDemo", BillboardDemo.Main),
|
||||
new ExampleInfo("BoxCollisions", BoxCollisions.Main),
|
||||
new ExampleInfo("CubicmapDemo", CubicmapDemo.Main),
|
||||
new ExampleInfo("ModelCubeTexture", ModelCubeTexture.Main),
|
||||
new ExampleInfo("FirstPersonMaze", FirstPersonMaze.Main),
|
||||
new ExampleInfo("GeometricShapes", GeometricShapes.Main),
|
||||
new ExampleInfo("HeightmapDemo", HeightmapDemo.Main),
|
||||
new ExampleInfo("MeshDemo", MeshDemo.Main),
|
||||
new ExampleInfo("ModelLoading", ModelLoading.Main),
|
||||
new ExampleInfo("MeshGeneration", MeshGeneration.Main),
|
||||
new ExampleInfo("MeshPicking", MeshPicking.Main),
|
||||
new ExampleInfo("OrthographicProjection", OrthographicProjection.Main),
|
||||
new ExampleInfo("SolarSystem", SolarSystem.Main),
|
||||
new ExampleInfo("SkyboxDemo", SkyboxDemo.Main),
|
||||
new ExampleInfo("WavingCubes", WavingCubes.Main),
|
||||
new ExampleInfo("YawPitchRoll", YawPitchRoll.Main),
|
||||
new ExampleInfo("DynamicMesh", DynamicMesh.Main),
|
||||
|
||||
// Shaders
|
||||
new ExampleInfo("BasicLighting", BasicLighting.Main),
|
||||
new ExampleInfo("BasicPbr", BasicPbr.Main),
|
||||
new ExampleInfo("CustomUniform", CustomUniform.Main),
|
||||
new ExampleInfo("Eratosthenes", Eratosthenes.Main),
|
||||
new ExampleInfo("Fog", Fog.Main),
|
||||
new ExampleInfo("HotReloading", HotReloading.Main),
|
||||
new ExampleInfo("HybridRender", HybridRender.Main),
|
||||
new ExampleInfo("JuliaSet", JuliaSet.Main),
|
||||
new ExampleInfo("ModelShader", ModelShader.Main),
|
||||
new ExampleInfo("MultiSample2d", MultiSample2d.Main),
|
||||
new ExampleInfo("PaletteSwitch", PaletteSwitch.Main),
|
||||
new ExampleInfo("PostProcessing", PostProcessing.Main),
|
||||
new ExampleInfo("Raymarching", Raymarching.Main),
|
||||
new ExampleInfo("MeshInstancing", MeshInstancing.Main),
|
||||
new ExampleInfo("ShapesTextures", ShapesTextures.Main),
|
||||
new ExampleInfo("SimpleMask", SimpleMask.Main),
|
||||
new ExampleInfo("Spotlight", Spotlight.Main),
|
||||
new ExampleInfo("TextureDrawing", TextureDrawing.Main),
|
||||
new ExampleInfo("TextureOutline", TextureOutline.Main),
|
||||
new ExampleInfo("TextureWaves", TextureWaves.Main),
|
||||
new ExampleInfo("WriteDepth", WriteDepth.Main),
|
||||
|
||||
// Audio
|
||||
new ExampleInfo("ModulePlaying", ModulePlaying.Main),
|
||||
new ExampleInfo("MusicStreamDemo", MusicStreamDemo.Main),
|
||||
new ExampleInfo("SoundLoading", SoundLoading.Main),
|
||||
};
|
||||
|
||||
public static ExampleInfo GetExample(string name)
|
||||
{
|
||||
var example = Array.Find(ExampleList.AllExamples, x =>
|
||||
x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
return example;
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static unsafe void Main(string[] args)
|
||||
private static unsafe void Main(string[] args)
|
||||
{
|
||||
Raylib.SetTraceLogCallback(&Logging.LogConsole);
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
var example = ExampleList.GetExample(args[0]);
|
||||
example?.Main?.Invoke();
|
||||
var example = GetExample(args[0]);
|
||||
if (example == null)
|
||||
{
|
||||
Console.WriteLine($"Unknown example: {args[0]}");
|
||||
return;
|
||||
}
|
||||
|
||||
RunExample(example);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var example in ExampleList.AllExamples)
|
||||
foreach (var example in ExampleRegistry.DesktopExamples)
|
||||
{
|
||||
RunExampleProcess(Environment.ProcessPath, example.Name);
|
||||
RunExampleProcess(Environment.ProcessPath!, example.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
static void RunExampleProcess(
|
||||
private static IExample? GetExample(string name)
|
||||
{
|
||||
return Array.Find(ExampleRegistry.DesktopExamples, x =>
|
||||
x.GetType().Name.Equals(name, StringComparison.OrdinalIgnoreCase) ||
|
||||
x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drives an example the same way its standalone Main() does: window setup from the
|
||||
/// example's properties, then Init/Update/Unload around a blocking frame loop.
|
||||
/// </summary>
|
||||
private static void RunExample(IExample example)
|
||||
{
|
||||
if (example.ConfigFlags != 0)
|
||||
{
|
||||
SetConfigFlags(example.ConfigFlags);
|
||||
}
|
||||
|
||||
InitWindow(example.Width, example.Height, example.Title);
|
||||
|
||||
if (example.CursorDisabled)
|
||||
{
|
||||
DisableCursor();
|
||||
}
|
||||
else if (example.CursorHidden)
|
||||
{
|
||||
HideCursor();
|
||||
}
|
||||
|
||||
SetTargetFPS(example.TargetFps);
|
||||
|
||||
try
|
||||
{
|
||||
example.Init();
|
||||
|
||||
while (!example.ShouldClose)
|
||||
{
|
||||
example.Update();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
example.Unload();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RunExampleProcess(
|
||||
string fileName,
|
||||
string exampleName
|
||||
)
|
||||
|
|
|
|||
166
Examples/Shaders/AsciiRendering.cs
Normal file
166
Examples/Shaders/AsciiRendering.cs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - ascii rendering
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class AsciiRendering : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Ascii Rendering";
|
||||
|
||||
public string Title => "raylib [shaders] example - ascii rendering";
|
||||
|
||||
private Texture2D fudesumi;
|
||||
private Texture2D raysan;
|
||||
private Shader shader;
|
||||
private int resolutionLoc;
|
||||
private int fontSizeLoc;
|
||||
private float fontSize;
|
||||
private Vector2 circlePos;
|
||||
private float circleSpeed;
|
||||
private RenderTexture2D target;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Texture to test static drawing
|
||||
fudesumi = LoadTexture("resources/fudesumi.png");
|
||||
// Texture to test moving drawing
|
||||
raysan = LoadTexture("resources/raysan.png");
|
||||
|
||||
// Load shader to be used on postprocessing
|
||||
shader = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/ascii.fs");
|
||||
|
||||
// These locations are used to send data to the GPU
|
||||
resolutionLoc = GetShaderLocation(shader, "resolution");
|
||||
fontSizeLoc = GetShaderLocation(shader, "fontSize");
|
||||
|
||||
// Set the character size for the ASCII effect
|
||||
// Fontsize should be 9 or more
|
||||
fontSize = 9.0f;
|
||||
|
||||
// Send the updated values to the shader
|
||||
var resolution = new[] { (float)screenWidth, (float)screenHeight };
|
||||
Raylib.SetShaderValue(shader, resolutionLoc, resolution, ShaderUniformDataType.Vec2);
|
||||
|
||||
circlePos = new Vector2(40.0f, screenHeight * 0.5f);
|
||||
circleSpeed = 1.0f;
|
||||
|
||||
// RenderTexture to apply the postprocessing later
|
||||
target = LoadRenderTexture(screenWidth, screenHeight);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
circlePos.X += circleSpeed;
|
||||
if ((circlePos.X > 200.0f) || (circlePos.X < 40.0f))
|
||||
{
|
||||
circleSpeed *= -1; // Revert speed
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Left) && (fontSize > 9.0))
|
||||
{
|
||||
fontSize -= 1; // Reduce fontSize
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Right) && (fontSize < 15.0))
|
||||
{
|
||||
fontSize += 1; // Increase fontSize
|
||||
}
|
||||
|
||||
// Set fontsize for the shader
|
||||
Raylib.SetShaderValue(shader, fontSizeLoc, fontSize, ShaderUniformDataType.Float);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginTextureMode(target);
|
||||
ClearBackground(Color.White);
|
||||
|
||||
// Draw scene in our render texture
|
||||
DrawTexture(fudesumi, 500, -30, Color.White);
|
||||
DrawTextureV(raysan, circlePos, Color.White);
|
||||
EndTextureMode();
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
// Draw the scene texture (that we rendered earlier) to the screen
|
||||
// The shader will process every pixel of this texture
|
||||
DrawTextureRec(
|
||||
target.Texture,
|
||||
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
|
||||
new Vector2(0, 0),
|
||||
Color.White
|
||||
);
|
||||
EndShaderMode();
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 40, Color.Black);
|
||||
DrawText($"Ascii effect - FontSize:{fontSize,2:F0} - [Left] -1 [Right] +1 ", 120, 10, 20, Color.LightGray);
|
||||
DrawFPS(10, 10);
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadRenderTexture(target); // Unload render texture
|
||||
|
||||
UnloadShader(shader); // Unload shader
|
||||
UnloadTexture(fudesumi); // Unload texture
|
||||
UnloadTexture(raysan); // Unload texture
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - ascii rendering");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AsciiRendering();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,21 @@
|
|||
*
|
||||
* raylib [shaders] example - basic lighting
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3).
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* 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 originally created with raylib 3.0, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by Chris Camacho (@codifies) and reviewed by Ramon Santamaria (@raysan5)
|
||||
* Example contributed by Chris Camacho (@chriscamacho) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Chris Camacho (@codifies - http://bedroomcoders.co.uk/) notes:
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* This is based on the PBR lighting example, but greatly simplified to aid learning...
|
||||
* actually there is very little of the PBR example left!
|
||||
* When I first looked at the bewildering complexity of the PBR example I feared
|
||||
* I would never understand how I could do simple lighting with raylib however its
|
||||
* a testement to the authors of raylib (including rlights.h) that the example
|
||||
* came together fairly quickly.
|
||||
*
|
||||
* Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2019-2025 Chris Camacho (@chriscamacho) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -31,52 +26,55 @@ using Examples.Shared;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class BasicLighting
|
||||
public class BasicLighting : IExample
|
||||
{
|
||||
const int GLSL_VERSION = 330;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public unsafe static int Main()
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Basic Lighting";
|
||||
|
||||
public string Title => "raylib [shaders] example - basic lighting";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Light[] lights;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(2.0f, 4.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 4.0f, 6.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
// Load plane model from a generated mesh
|
||||
Model model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3));
|
||||
Model cube = LoadModelFromMesh(GenMeshCube(2.0f, 4.0f, 2.0f));
|
||||
|
||||
Shader shader = LoadShader(
|
||||
"resources/shaders/glsl330/lighting.vs",
|
||||
"resources/shaders/glsl330/lighting.fs"
|
||||
// Load basic lighting shader
|
||||
shader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/lighting.fs"
|
||||
);
|
||||
|
||||
// Get some required shader loactions
|
||||
// Get some required shader locations
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(shader, "viewPos");
|
||||
// NOTE: "matModel" location name is automatically assigned on shader loading,
|
||||
// no need to get the location again if using that uniform name
|
||||
//shader.Locs[(int)ShaderLocationIndex.MatrixModel] = GetShaderLocation(shader, "matModel");
|
||||
|
||||
// ambient light level
|
||||
int ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
float[] ambient = new[] { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
// Ambient light level (some basic lighting)
|
||||
var ambientLoc = GetShaderLocation(shader, "ambient");
|
||||
var ambient = new[] { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||
Raylib.SetShaderValue(shader, ambientLoc, ambient, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Assign out lighting shader to model
|
||||
model.Materials[0].Shader = shader;
|
||||
cube.Materials[0].Shader = shader;
|
||||
|
||||
// Using 4 point lights: Color.gold, Color.red, Color.green and Color.blue
|
||||
Light[] lights = new Light[4];
|
||||
// Create lights
|
||||
lights = new Light[4];
|
||||
lights[0] = Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Point,
|
||||
|
|
@ -109,114 +107,116 @@ public class BasicLighting
|
|||
Color.Blue,
|
||||
shader
|
||||
);
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.Y))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.B))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
BeginShaderMode(shader);
|
||||
|
||||
DrawPlane(Vector3.Zero, new Vector2(10.0f, 10.0f), Color.White);
|
||||
DrawCube(Vector3.Zero, 2.0f, 4.0f, 2.0f, Color.White);
|
||||
|
||||
EndShaderMode();
|
||||
|
||||
// Draw spheres to show where the lights are
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lights[i].Color);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lights[i].Color, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
DrawText("Use keys [Y][R][G][B] to toggle lights", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadShader(shader); // Unload shader
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicLighting();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Y))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.G))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.B))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
// Update light values (actually, only enable/disable them)
|
||||
Rlights.UpdateLightValues(shader, lights[0]);
|
||||
Rlights.UpdateLightValues(shader, lights[1]);
|
||||
Rlights.UpdateLightValues(shader, lights[2]);
|
||||
Rlights.UpdateLightValues(shader, lights[3]);
|
||||
|
||||
// Update the light shader with the camera view position
|
||||
Raylib.SetShaderValue(
|
||||
shader,
|
||||
shader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawModel(model, Vector3.Zero, 1.0f, Color.White);
|
||||
DrawModel(cube, Vector3.Zero, 1.0f, Color.White);
|
||||
|
||||
// Draw markers to show where the lights are
|
||||
if (lights[0].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[0].Position, 0.2f, 8, 8, Color.Yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[0].Position, 0.2f, 8, 8, ColorAlpha(Color.Yellow, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[1].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[1].Position, 0.2f, 8, 8, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[1].Position, 0.2f, 8, 8, ColorAlpha(Color.Red, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[2].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[2].Position, 0.2f, 8, 8, Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[2].Position, 0.2f, 8, 8, ColorAlpha(Color.Green, 0.3f));
|
||||
}
|
||||
|
||||
if (lights[3].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[3].Position, 0.2f, 8, 8, Color.Blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[3].Position, 0.2f, 8, 8, ColorAlpha(Color.Blue, 0.3f));
|
||||
}
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
DrawText("Use keys [Y][R][G][B] to toggle lights", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadModel(model);
|
||||
UnloadModel(cube);
|
||||
UnloadShader(shader);
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - Basic PBR
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.1-dev
|
||||
*
|
||||
* Example contributed by Afan OLOVCIC (@_DevDad) 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-2024 Afan OLOVCIC (@_DevDad)
|
||||
*
|
||||
* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox,
|
||||
* licensed under Creative Commons Attribution-NonCommercial
|
||||
* (http://creativecommons.org/licenses/by-nc/4.0/)
|
||||
*
|
||||
********************************************************************************************/
|
||||
*
|
||||
* raylib [shaders] example - basic pbr
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Afan OLOVCIC (@_DevDad) 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 Afan OLOVCIC (@_DevDad)
|
||||
*
|
||||
* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox,
|
||||
* licensed under Creative Commons Attribution-NonCommercial
|
||||
* (http://creativecommons.org/licenses/by-nc/4.0/)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Numerics;
|
||||
using Examples.Shared;
|
||||
|
|
@ -23,31 +25,50 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public class BasicPbr
|
||||
public class BasicPbr : IExample
|
||||
{
|
||||
private const int GLSL_VERSION = 330;
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public static unsafe int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Shaders / Basic PBR";
|
||||
|
||||
public string Title => "raylib [shaders] example - basic pbr";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Shader shader;
|
||||
private Model car;
|
||||
private Model floor;
|
||||
private PbrLight[] lights;
|
||||
|
||||
private int metallicValueLoc;
|
||||
private int roughnessValueLoc;
|
||||
private int emissiveIntensityLoc;
|
||||
private int emissiveColorLoc;
|
||||
private int textureTilingLoc;
|
||||
|
||||
private Vector2 carTextureTiling;
|
||||
private Vector2 floorTextureTiling;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(2.0f, 4.0f, 6.0f);
|
||||
camera = new();
|
||||
camera.Position = new Vector3(2.0f, 2.0f, 6.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.5f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load PBR shader and setup all required locations
|
||||
var shader = LoadShader("resources/shaders/glsl330/pbr.vs", "resources/shaders/glsl330/pbr.fs");
|
||||
shader = LoadShader($"resources/shaders/glsl{GlslVersion}/pbr.vs", $"resources/shaders/glsl{GlslVersion}/pbr.fs");
|
||||
|
||||
shader.Locs[(int)ShaderLocationIndex.MapAlbedo] = GetShaderLocation(shader, "albedoMap");
|
||||
// WARNING: Metalness, roughness, and ambient occlusion are all packed into a MRA texture
|
||||
|
|
@ -75,23 +96,25 @@ public class BasicPbr
|
|||
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Get location for shader parameters that can be modified in real time
|
||||
var emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||
var emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||
var textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||
metallicValueLoc = GetShaderLocation(shader, "metallicValue");
|
||||
roughnessValueLoc = GetShaderLocation(shader, "roughnessValue");
|
||||
emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||
emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||
textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||
|
||||
// Load old car model using PBR maps and shader
|
||||
// WARNING: We know this model consists of a single model.meshes[0] and
|
||||
// that model.materials[0] is by default assigned to that mesh
|
||||
// There could be more complex models consisting of multiple meshes and
|
||||
// multiple materials defined for those meshes... but always 1 mesh = 1 material
|
||||
var car = LoadModel("resources/models/gltf/old_car_new.glb");
|
||||
car = LoadModel("resources/models/gltf/old_car_new.glb");
|
||||
|
||||
// Assign already setup PBR shader to model.materials[0], used by models.meshes[0]
|
||||
car.Materials[0].Shader = shader;
|
||||
|
||||
// Setup materials[0].maps default parameters
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Albedo].Color = Color.White;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 1.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Occlusion].Value = 1.0f;
|
||||
car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color = new Color(255, 162, 0, 255);
|
||||
|
|
@ -104,7 +127,7 @@ public class BasicPbr
|
|||
|
||||
// Load floor model mesh and assign material parameters
|
||||
// NOTE: A basic plane shape can be generated instead of being loaded from a model file
|
||||
var floor = LoadModel("resources/models/gltf/plane.glb");
|
||||
floor = LoadModel("resources/models/gltf/plane.glb");
|
||||
//Mesh floorMesh = GenMeshPlane(10, 10, 10, 10);
|
||||
//GenMeshTangents(&floorMesh); // TODO: Review tangents generation
|
||||
//Model floor = LoadModelFromMesh(floorMesh);
|
||||
|
|
@ -113,8 +136,8 @@ public class BasicPbr
|
|||
floor.Materials[0].Shader = shader;
|
||||
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Albedo].Color = Color.White;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value = 0.8f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value = 0.1f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Occlusion].Value = 1.0f;
|
||||
floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color = Color.Black;
|
||||
|
||||
|
|
@ -124,11 +147,11 @@ public class BasicPbr
|
|||
|
||||
// Models texture tiling parameter can be stored in the Material struct if required (CURRENTLY NOT USED)
|
||||
// NOTE: Material.params[4] are available for generic parameters storage (float)
|
||||
var carTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
var floorTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
carTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
floorTextureTiling = new Vector2(0.5f, 0.5f);
|
||||
|
||||
// Create some lights
|
||||
var lights = new PbrLight[4];
|
||||
lights = new PbrLight[4];
|
||||
lights[0] = PbrLights.CreateLight(
|
||||
0,
|
||||
PbrLightType.Point,
|
||||
|
|
@ -167,104 +190,113 @@ public class BasicPbr
|
|||
SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), &usage, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), &usage, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), &usage, ShaderUniformDataType.Int);
|
||||
}
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
var cameraPos = camera.Position;
|
||||
SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], cameraPos, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(&camera, CameraMode.Orbital);
|
||||
|
||||
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
|
||||
var cameraPos = camera.Position;
|
||||
SetShaderValue(shader, shader.Locs[(int)ShaderLocationIndex.VectorView], cameraPos, ShaderUniformDataType.Vec3);
|
||||
|
||||
// Check key inputs to enable/disable lights
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
|
||||
// Update light values on shader (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
UpdateLight(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Set floor model texture tiling and emissive color parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, &floorTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var floorEmissiveColor = ColorNormalize(floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
|
||||
DrawModel(floor, Vector3.Zero, 5.0f, Color.White); // Draw floor model
|
||||
|
||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, &carTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var carEmissiveColor = ColorNormalize(car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
var emissiveIntensity = 0.01f;
|
||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(car, Vector3.Zero, 0.25f, Color.White); // Draw car model
|
||||
|
||||
// Draw spheres to show the lights positions
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var color = lights[i].Color;
|
||||
var lightColor = new Color((byte)(color.X * 255), (byte)(color.Y * 255), (byte)(color.Z * 255),
|
||||
(byte)(color.W * 255));
|
||||
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lightColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, Color.LightGray);
|
||||
|
||||
DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, Color.LightGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
lights[2].Enabled = !lights[2].Enabled;
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
lights[1].Enabled = !lights[1].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
lights[3].Enabled = !lights[3].Enabled;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
lights[0].Enabled = !lights[0].Enabled;
|
||||
}
|
||||
|
||||
// Update light values on shader (actually, only enable/disable them)
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
UpdateLight(shader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.Black);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Set floor model texture tiling and emissive color parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, floorTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var floorEmissiveColor = ColorNormalize(floor.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
|
||||
// Set floor metallic and roughness values
|
||||
var floorMetallicValue = floor.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value;
|
||||
SetShaderValue(shader, metallicValueLoc, &floorMetallicValue, ShaderUniformDataType.Float);
|
||||
var floorRoughnessValue = floor.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value;
|
||||
SetShaderValue(shader, roughnessValueLoc, &floorRoughnessValue, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(floor, Vector3.Zero, 5.0f, Color.White); // Draw floor model
|
||||
|
||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||
SetShaderValue(shader, textureTilingLoc, carTextureTiling, ShaderUniformDataType.Vec2);
|
||||
var carEmissiveColor = ColorNormalize(car.Materials[0].Maps[(int)MaterialMapIndex.Emission].Color);
|
||||
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, ShaderUniformDataType.Vec4);
|
||||
var emissiveIntensity = 0.01f;
|
||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, ShaderUniformDataType.Float);
|
||||
|
||||
// Set old car metallic and roughness values
|
||||
var carMetallicValue = car.Materials[0].Maps[(int)MaterialMapIndex.Metalness].Value;
|
||||
SetShaderValue(shader, metallicValueLoc, &carMetallicValue, ShaderUniformDataType.Float);
|
||||
var carRoughnessValue = car.Materials[0].Maps[(int)MaterialMapIndex.Roughness].Value;
|
||||
SetShaderValue(shader, roughnessValueLoc, &carRoughnessValue, ShaderUniformDataType.Float);
|
||||
|
||||
DrawModel(car, Vector3.Zero, 0.25f, Color.White); // Draw car model
|
||||
|
||||
// Draw spheres to show the lights positions
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var color = lights[i].Color;
|
||||
var lightColor = new Color((byte)(color.X * 255), (byte)(color.Y * 255), (byte)(color.Z * 255),
|
||||
(byte)(color.W * 255));
|
||||
|
||||
if (lights[i].Enabled)
|
||||
{
|
||||
DrawSphereEx(lights[i].Position, 0.2f, 8, 8, lightColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSphereWires(lights[i].Position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Toggle lights: [1][2][3][4]", 10, 40, 20, Color.LightGray);
|
||||
|
||||
DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, Color.LightGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public unsafe void Unload()
|
||||
{
|
||||
// Unbind (disconnect) shader from car.material[0]
|
||||
// to avoid UnloadMaterial() trying to unload it automatically
|
||||
car.Materials[0].Shader = new();
|
||||
|
|
@ -278,7 +310,32 @@ public class BasicPbr
|
|||
UnloadModel(floor);
|
||||
|
||||
UnloadShader(shader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Enable Multi Sampling Anti Aliasing 4x (if available)
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicPbr();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -287,8 +344,8 @@ public class BasicPbr
|
|||
|
||||
private static void UpdateLight(Shader shader, PbrLight light)
|
||||
{
|
||||
SetShaderValue(shader, light.EnabledLoc, light.Enabled, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.TypeLoc, light.Type, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.EnabledLoc, light.Enabled ? 1 : 0, ShaderUniformDataType.Int);
|
||||
SetShaderValue(shader, light.TypeLoc, (int)light.Type, ShaderUniformDataType.Int);
|
||||
|
||||
// Send to shader light position values
|
||||
SetShaderValue(shader, light.PositionLoc, light.Position, ShaderUniformDataType.Vec3);
|
||||
|
|
|
|||
252
Examples/Shaders/CelShading.cs
Normal file
252
Examples/Shaders/CelShading.cs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [shaders] example - cel shading
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
||||
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
|
||||
*
|
||||
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
|
||||
*
|
||||
* Example contributed by Gleb A (@ggrizzly) 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) 2026 Gleb A (@ggrizzly)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
using static Raylib_cs.Rlgl;
|
||||
using Examples.Shared;
|
||||
|
||||
namespace Examples.Shaders;
|
||||
|
||||
public partial class CelShading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MaxLights = 4;
|
||||
|
||||
// rlgl cull face modes (rlgl.h: RL_CULL_FACE_FRONT = 0, RL_CULL_FACE_BACK = 1)
|
||||
private const int CullFaceFront = 0;
|
||||
private const int CullFaceBack = 1;
|
||||
|
||||
#if BROWSER
|
||||
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
|
||||
#else
|
||||
private const int GlslVersion = 330;
|
||||
#endif
|
||||
|
||||
public string Name => "Shaders / Cel Shading";
|
||||
|
||||
public string Title => "raylib [shaders] example - cel shading";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private Camera3D camera;
|
||||
private Model model;
|
||||
private Shader celShader;
|
||||
private Shader defaultShader;
|
||||
private Shader outlineShader;
|
||||
private float numBands;
|
||||
private int numBandsLoc;
|
||||
private int outlineThicknessLoc;
|
||||
private Light[] lights;
|
||||
private bool celEnabled;
|
||||
private bool outlineEnabled;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
camera = new();
|
||||
camera.Position = new Vector3(9.0f, 6.0f, 9.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
// Load model
|
||||
model = LoadModel("resources/models/old_car_new.glb");
|
||||
|
||||
// Load cel shader
|
||||
celShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/cel.fs"
|
||||
);
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView] = GetShaderLocation(celShader, "viewPos");
|
||||
|
||||
// Apply cel shader to model, keep copy of default shader
|
||||
defaultShader = model.Materials[0].Shader;
|
||||
model.Materials[0].Shader = celShader;
|
||||
|
||||
// numBands: controls toon quantization steps (2 = hard binary, 20 = near-smooth)
|
||||
numBands = 10.0f;
|
||||
numBandsLoc = GetShaderLocation(celShader, "numBands");
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Inverted-hull outline shader: draws back faces extruded along normals
|
||||
outlineShader = LoadShader(
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.vs",
|
||||
$"resources/shaders/glsl{GlslVersion}/outline_hull.fs"
|
||||
);
|
||||
outlineThicknessLoc = GetShaderLocation(outlineShader, "outlineThickness");
|
||||
|
||||
// Single directional white light, angled so toon bands are visible on the model sides.
|
||||
// Spins opposite to CAMERA_ORBITAL (0.5 rad/s) so lighting changes as you watch.
|
||||
lights = new Light[MaxLights];
|
||||
lights[0] = Rlights.CreateLight(
|
||||
0,
|
||||
LightType.Directorional,
|
||||
new Vector3(50.0f, 50.0f, 50.0f),
|
||||
Vector3.Zero,
|
||||
Color.White,
|
||||
celShader
|
||||
);
|
||||
|
||||
celEnabled = true;
|
||||
outlineEnabled = true;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Orbital);
|
||||
|
||||
Raylib.SetShaderValue(
|
||||
celShader,
|
||||
celShader.Locs[(int)ShaderLocationIndex.VectorView],
|
||||
camera.Position,
|
||||
ShaderUniformDataType.Vec3
|
||||
);
|
||||
|
||||
// [Z] Toggle cel shading on/off
|
||||
if (IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
celEnabled = !celEnabled;
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
}
|
||||
|
||||
// [C] Toggle outline on/off
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
outlineEnabled = !outlineEnabled;
|
||||
}
|
||||
|
||||
// [Q/E] Decrease/increase toon band count (press or hold to repeat)
|
||||
if (IsKeyPressed(KeyboardKey.E) || IsKeyPressedRepeat(KeyboardKey.E))
|
||||
{
|
||||
numBands = Clamp(numBands + 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
if (IsKeyPressed(KeyboardKey.Q) || IsKeyPressedRepeat(KeyboardKey.Q))
|
||||
{
|
||||
numBands = Clamp(numBands - 1.0f, 2.0f, 20.0f);
|
||||
}
|
||||
Raylib.SetShaderValue(celShader, numBandsLoc, numBands, ShaderUniformDataType.Float);
|
||||
|
||||
// Spin light opposite to CAMERA_ORBITAL (0.5 rad/s), angled 45 degrees off vertical
|
||||
float t = (float)GetTime();
|
||||
lights[0].Position = new Vector3(MathF.Sin(-t * 0.3f) * 5.0f, 5.0f, MathF.Cos(-t * 0.3f) * 5.0f);
|
||||
|
||||
for (var i = 0; i < MaxLights; i++)
|
||||
{
|
||||
Rlights.UpdateLightValues(celShader, lights[i]);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
if (outlineEnabled)
|
||||
{
|
||||
// Outline pass: cull front faces, draw extruded back faces as silhouette
|
||||
float thickness = 0.005f;
|
||||
Raylib.SetShaderValue(outlineShader, outlineThicknessLoc, thickness, ShaderUniformDataType.Float);
|
||||
|
||||
SetCullFace(CullFaceFront);
|
||||
|
||||
model.Materials[0].Shader = outlineShader;
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
|
||||
if (celEnabled)
|
||||
{
|
||||
model.Materials[0].Shader = celShader; // Apply cel shader to model
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Materials[0].Shader = defaultShader; // Apply default shader to model
|
||||
}
|
||||
|
||||
SetCullFace(CullFaceBack);
|
||||
}
|
||||
|
||||
DrawModel(model, Vector3.Zero, 0.75f, Color.White);
|
||||
DrawSphereEx(lights[0].Position, 0.2f, 50, 50, Color.Yellow); // Light position indicator
|
||||
DrawGrid(10, 10.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawFPS(10, 10);
|
||||
DrawText($"Cel: {(celEnabled ? "ON" : "OFF")} [Z]", 10, 65, 20, celEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Outline: {(outlineEnabled ? "ON" : "OFF")} [C]", 10, 90, 20, outlineEnabled ? Color.DarkGreen : Color.DarkGray);
|
||||
DrawText($"Bands: {numBands:0} [Q/E]", 10, 115, 20, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadModel(model);
|
||||
UnloadShader(celShader);
|
||||
UnloadShader(outlineShader);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint);
|
||||
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - cel shading");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new CelShading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue