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
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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue