diff --git a/examples/core/core_viewport_scaling.c b/examples/core/core_viewport_scaling.c index cf07838c6..e70b89829 100644 --- a/examples/core/core_viewport_scaling.c +++ b/examples/core/core_viewport_scaling.c @@ -17,26 +17,8 @@ #include "raylib.h" -int screenWidth = 800; -int screenHeight = 450; -int gameWidth = 320; -int gameHeight = 180; - -RenderTexture2D target; -Rectangle sourceRect; -Rectangle destRect; - // For itteration purposes and teaching example #define RESOLUTION_COUNT 4 -// Preset resolutions that could be created by subdividing screen resolution -Vector2 resolutionList[RESOLUTION_COUNT] = { - (Vector2){64, 64}, - (Vector2){256, 240}, - (Vector2){320, 180}, - // 4K doesn't work with integer scaling but included for example purposes with non-integer scaling - (Vector2){3840, 2160}, -}; -int resolutionIndex = 2; enum ViewportType { @@ -48,78 +30,29 @@ enum ViewportType KEEP_ASPECT, KEEP_HEIGHT, KEEP_WIDTH, - // For itteration purposes and teaching example + // For itteration purposes and as a teaching example VIEWPORT_TYPE_COUNT, }; -// For displaying on GUI -const char *ViewportTypeNames[VIEWPORT_TYPE_COUNT] = { - "KEEP_ASPECT_INTEGER", - "KEEP_HEIGHT_INTEGER", - "KEEP_WIDTH_INTEGER", - "KEEP_ASPECT", - "KEEP_HEIGHT", - "KEEP_WIDTH", -}; -enum ViewportType viewportType = KEEP_ASPECT_INTEGER; -// Function declarations (header part), implementation at bottom -void KeepAspectCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); -void KeepHeightCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); -void KeepWidthCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); -void KeepAspectCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); -void KeepHeightCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); -void KeepWidthCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect); +//-------------------------------------------------------------------------------------- +// Module Functions Declaration +//-------------------------------------------------------------------------------------- +static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); -void ResizeRenderSize() -{ - screenWidth = GetScreenWidth(); - screenHeight = GetScreenHeight(); +static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); - switch(viewportType) - { - case KEEP_ASPECT_INTEGER: - { - KeepAspectCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - case KEEP_HEIGHT_INTEGER: - { - KeepHeightCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - case KEEP_WIDTH_INTEGER: - { - KeepWidthCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - case KEEP_ASPECT: - { - KeepAspectCentered(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - case KEEP_HEIGHT: - { - KeepHeightCentered(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - case KEEP_WIDTH: - { - KeepWidthCentered(screenWidth, screenHeight, gameWidth, gameHeight, &sourceRect, &destRect); - break; - } - default: {} - } - UnloadRenderTexture(target); - target = LoadRenderTexture(sourceRect.width, -sourceRect.height); -} +static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); + +static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); + +static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); + +static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect); + +static void ResizeRenderSize(enum ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target); // Example how to calculate position on RenderTexture -Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle* textureRect, Rectangle* scaledRect){ - Vector2 relativePosition = {point.x - scaledRect->x, point.y - scaledRect->y}; - Vector2 ratio = {textureRect->width / scaledRect->width, -textureRect->height / scaledRect->height}; - - return (Vector2){relativePosition.x * ratio.x, relativePosition.y * ratio.x}; -} +static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect); //------------------------------------------------------------------------------------ // Program main entry point @@ -128,10 +61,39 @@ int main(void) { // Initialization //--------------------------------------------------------- + // Preset resolutions that could be created by subdividing screen resolution + Vector2 resolutionList[RESOLUTION_COUNT] = { + (Vector2){64, 64}, + (Vector2){256, 240}, + (Vector2){320, 180}, + // 4K doesn't work with integer scaling but included for example purposes with non-integer scaling + (Vector2){3840, 2160}, + }; + int resolutionIndex = 0; + + int screenWidth = 800; + int screenHeight = 450; + int gameWidth = 64; + int gameHeight = 64; + + RenderTexture2D target = (RenderTexture2D){0}; + Rectangle sourceRect = (Rectangle){0}; + Rectangle destRect = (Rectangle){0}; + + // For displaying on GUI + const char *ViewportTypeNames[VIEWPORT_TYPE_COUNT] = { + "KEEP_ASPECT_INTEGER", + "KEEP_HEIGHT_INTEGER", + "KEEP_WIDTH_INTEGER", + "KEEP_ASPECT", + "KEEP_HEIGHT", + "KEEP_WIDTH", + }; + enum ViewportType viewportType = KEEP_ASPECT_INTEGER; SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(screenWidth, screenHeight, "raylib [core] example - Viewport Scaling"); - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); SetTargetFPS(60); // Set our game to run at 60 frames-per-second //---------------------------------------------------------- @@ -147,7 +109,7 @@ int main(void) // Update //----------------------------------------------------- if (IsWindowResized()){ - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); } Vector2 mousePosition = GetMousePosition(); bool mousePressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT); @@ -157,21 +119,21 @@ int main(void) resolutionIndex = (resolutionIndex + RESOLUTION_COUNT - 1) % RESOLUTION_COUNT; gameWidth = resolutionList[resolutionIndex].x; gameHeight = resolutionList[resolutionIndex].y; - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); } if (CheckCollisionPointRec(mousePosition, increaseResolutionButton) && mousePressed){ resolutionIndex = (resolutionIndex + 1) % RESOLUTION_COUNT; gameWidth = resolutionList[resolutionIndex].x; gameHeight = resolutionList[resolutionIndex].y; - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); } if (CheckCollisionPointRec(mousePosition, decreaseTypeButton) && mousePressed){ viewportType = (viewportType + VIEWPORT_TYPE_COUNT - 1) % VIEWPORT_TYPE_COUNT; - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); } if (CheckCollisionPointRec(mousePosition, increaseTypeButton) && mousePressed){ viewportType = (viewportType + 1) % VIEWPORT_TYPE_COUNT; - ResizeRenderSize(); + ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target); } Vector2 textureMousePosition = Screen2RenderTexturePosition(mousePosition, &sourceRect, &destRect); @@ -204,9 +166,16 @@ int main(void) DrawText(TextFormat("Window Resolution: %d x %d", screenWidth, screenHeight), 15, 15, 10, BLACK); DrawText(TextFormat("Game Resolution: %d x %d", gameWidth, gameHeight), 15, 30, 10, BLACK); - Vector2 scaleRatio = (Vector2){destRect.width / sourceRect.width, destRect.height / -sourceRect.height}; DrawText(TextFormat("Type: %s", ViewportTypeNames[viewportType]), 15, 45, 10, BLACK); - DrawText(TextFormat("Scale ratio: %.2f x %.2f", scaleRatio.x, scaleRatio.y), 15, 60, 10, BLACK); + Vector2 scaleRatio = (Vector2){destRect.width / sourceRect.width, destRect.height / -sourceRect.height}; + if (scaleRatio.x < 0.001f || scaleRatio.y < 0.001f) + { + DrawText(TextFormat("Scale ratio: INVALID"), 15, 60, 10, BLACK); + } + else + { + DrawText(TextFormat("Scale ratio: %.2f x %.2f", scaleRatio.x, scaleRatio.y), 15, 60, 10, BLACK); + } DrawText(TextFormat("Source size: %.2f x %.2f", sourceRect.width, -sourceRect.height), 15, 75, 10, BLACK); DrawText(TextFormat("Destination size: %.2f x %.2f", destRect.width, destRect.height), 15, 90, 10, BLACK); @@ -232,90 +201,151 @@ int main(void) return 0; } -void KeepAspectCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - source_rect->x = 0.f; - source_rect->y = (float)view_h; - source_rect->width = (float)view_w; - source_rect->height = (float)-view_h; +//-------------------------------------------------------------------------------------- +// Module Functions Definition +//-------------------------------------------------------------------------------------- +static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + sourceRect->x = 0.f; + sourceRect->y = (float)gameHeight; + sourceRect->width = (float)gameWidth; + sourceRect->height = (float)-gameHeight; - const int ratio_x = (scr_w/view_w); - const int ratio_y = (scr_h/view_h); - const float resize_ratio = (float)(ratio_x < ratio_y ? ratio_x : ratio_y); + const int ratio_x = (screenWidth/gameWidth); + const int ratio_y = (screenHeight/gameHeight); + const float resizeRatio = (float)(ratio_x < ratio_y ? ratio_x : ratio_y); - dest_rect->x = (float)(int)((scr_w - (view_w * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (view_h * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(view_w * resize_ratio); - dest_rect->height = (float)(int)(view_h * resize_ratio); + destRect->x = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5); + destRect->width = (float)(int)(gameWidth * resizeRatio); + destRect->height = (float)(int)(gameHeight * resizeRatio); } -void KeepHeightCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - const float resize_ratio = ((float)scr_h/(float)view_h); - source_rect->x = 0.f; - source_rect->y = 0.f; - source_rect->width = (float)(int)(scr_w / resize_ratio); - source_rect->height = (float)-view_h; +static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + const float resizeRatio = (float)(screenHeight/gameHeight); + sourceRect->x = 0.f; + sourceRect->y = 0.f; + sourceRect->width = (float)(int)(screenWidth / resizeRatio); + sourceRect->height = (float)-gameHeight; - dest_rect->x = (float)(int)((scr_w - (source_rect->width * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (view_h * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(source_rect->width * resize_ratio); - dest_rect->height = (float)(int)(view_h * resize_ratio); + destRect->x = (float)(int)((screenWidth - (sourceRect->width * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5); + destRect->width = (float)(int)(sourceRect->width * resizeRatio); + destRect->height = (float)(int)(gameHeight * resizeRatio); } -void KeepWidthCenteredInteger(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - const float resize_ratio = ((float)scr_w/(float)view_w); - source_rect->x = 0.f; - source_rect->y = 0.f; - source_rect->width = (float)view_w; - source_rect->height = (float)(int)(scr_h / resize_ratio); +static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + const float resizeRatio = (float)(screenWidth/gameWidth); + sourceRect->x = 0.f; + sourceRect->y = 0.f; + sourceRect->width = (float)gameWidth; + sourceRect->height = (float)(int)(screenHeight / resizeRatio); - dest_rect->x = (float)(int)((scr_w - (view_w * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (source_rect->height * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(view_w * resize_ratio); - dest_rect->height = (float)(int)(source_rect->height * resize_ratio); + destRect->x = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (sourceRect->height * resizeRatio)) * 0.5); + destRect->width = (float)(int)(gameWidth * resizeRatio); + destRect->height = (float)(int)(sourceRect->height * resizeRatio); - source_rect->height *= -1.f; + sourceRect->height *= -1.f; } -void KeepAspectCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - source_rect->x = 0.f; - source_rect->y = (float)view_h; - source_rect->width = (float)view_w; - source_rect->height = (float)-view_h; +static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + sourceRect->x = 0.f; + sourceRect->y = (float)gameHeight; + sourceRect->width = (float)gameWidth; + sourceRect->height = (float)-gameHeight; - const float ratio_x = ((float)scr_w/(float)view_w); - const float ratio_y = ((float)scr_h/(float)view_h); - const float resize_ratio = (ratio_x < ratio_y ? ratio_x : ratio_y); + const float ratio_x = ((float)screenWidth/(float)gameWidth); + const float ratio_y = ((float)screenHeight/(float)gameHeight); + const float resizeRatio = (ratio_x < ratio_y ? ratio_x : ratio_y); - dest_rect->x = (float)(int)((scr_w - (view_w * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (view_h * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(view_w * resize_ratio); - dest_rect->height = (float)(int)(view_h * resize_ratio); + destRect->x = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5); + destRect->width = (float)(int)(gameWidth * resizeRatio); + destRect->height = (float)(int)(gameHeight * resizeRatio); } -void KeepHeightCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - const float resize_ratio = ((float)scr_h/(float)view_h); - source_rect->x = 0.f; - source_rect->y = 0.f; - source_rect->width = (float)(int)((float)scr_w / resize_ratio); - source_rect->height = (float)-view_h; +static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + const float resizeRatio = ((float)screenHeight/(float)gameHeight); + sourceRect->x = 0.f; + sourceRect->y = 0.f; + sourceRect->width = (float)(int)((float)screenWidth / resizeRatio); + sourceRect->height = (float)-gameHeight; - dest_rect->x = (float)(int)((scr_w - (source_rect->width * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (view_h * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(source_rect->width * resize_ratio); - dest_rect->height = (float)(int)(view_h * resize_ratio); + destRect->x = (float)(int)((screenWidth - (sourceRect->width * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5); + destRect->width = (float)(int)(sourceRect->width * resizeRatio); + destRect->height = (float)(int)(gameHeight * resizeRatio); } -void KeepWidthCentered(int scr_w, int scr_h, int view_w, int view_h, Rectangle* source_rect, Rectangle* dest_rect){ - const float resize_ratio = ((float)scr_w/(float)view_w); - source_rect->x = 0.f; - source_rect->y = 0.f; - source_rect->width = (float)view_w; - source_rect->height = (float)(int)((float)scr_h / resize_ratio); +static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect) +{ + const float resizeRatio = ((float)screenWidth/(float)gameWidth); + sourceRect->x = 0.f; + sourceRect->y = 0.f; + sourceRect->width = (float)gameWidth; + sourceRect->height = (float)(int)((float)screenHeight / resizeRatio); - dest_rect->x = (float)(int)((scr_w - (view_w * resize_ratio)) * 0.5); - dest_rect->y = (float)(int)((scr_h - (source_rect->height * resize_ratio)) * 0.5); - dest_rect->width = (float)(int)(view_w * resize_ratio); - dest_rect->height = (float)(int)(source_rect->height * resize_ratio); + destRect->x = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5); + destRect->y = (float)(int)((screenHeight - (sourceRect->height * resizeRatio)) * 0.5); + destRect->width = (float)(int)(gameWidth * resizeRatio); + destRect->height = (float)(int)(sourceRect->height * resizeRatio); - source_rect->height *= -1.f; + sourceRect->height *= -1.f; +} + +static void ResizeRenderSize(enum ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target) +{ + *screenWidth = GetScreenWidth(); + *screenHeight = GetScreenHeight(); + + switch(viewportType) + { + case KEEP_ASPECT_INTEGER: + { + KeepAspectCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + case KEEP_HEIGHT_INTEGER: + { + KeepHeightCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + case KEEP_WIDTH_INTEGER: + { + KeepWidthCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + case KEEP_ASPECT: + { + KeepAspectCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + case KEEP_HEIGHT: + { + KeepHeightCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + case KEEP_WIDTH: + { + KeepWidthCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); + break; + } + default: {} + } + UnloadRenderTexture(*target); + *target = LoadRenderTexture(sourceRect->width, -sourceRect->height); +} + +// Example how to calculate position on RenderTexture +static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect) +{ + Vector2 relativePosition = {point.x - scaledRect->x, point.y - scaledRect->y}; + Vector2 ratio = {textureRect->width / scaledRect->width, -textureRect->height / scaledRect->height}; + + return (Vector2){relativePosition.x * ratio.x, relativePosition.y * ratio.x}; } \ No newline at end of file