diff --git a/src/config.h b/src/config.h index 2ea4b438f..77e936bd6 100644 --- a/src/config.h +++ b/src/config.h @@ -50,6 +50,8 @@ #define SUPPORT_SCREEN_CAPTURE 1 // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() #define SUPPORT_GIF_RECORDING 1 +// Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP) +//#define SUPPORT_HIGH_DPI 1 //------------------------------------------------------------------------------------ diff --git a/src/core.c b/src/core.c index f2978d77e..6dd423fae 100644 --- a/src/core.c +++ b/src/core.c @@ -59,6 +59,9 @@ * #define SUPPORT_GIF_RECORDING * Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() * +* #define SUPPORT_HIGH_DPI +* Allow scale all the drawn content to match the high-DPI equivalent size (only PLATFORM_DESKTOP) +* * DEPENDENCIES: * rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly) * raymath - 3D math functionality (Vector2, Vector3, Matrix, Quaternion) @@ -437,7 +440,7 @@ extern void UnloadDefaultFont(void); // [Module: text] Unloads default fo //---------------------------------------------------------------------------------- static bool InitGraphicsDevice(int width, int height); // Initialize graphics device static void SetupFramebuffer(int width, int height); // Setup main framebuffer -static void SetupViewport(void); // Set viewport parameters +static void SetupViewport(int width, int height); // Set viewport for a provided width and height static void SwapBuffers(void); // Copy back buffer to front buffers static void InitTimer(void); // Initialize timer @@ -1175,6 +1178,7 @@ void BeginMode2D(Camera2D camera) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlLoadIdentity(); // Reset current matrix (MODELVIEW) + rlMultMatrixf(MatrixToFloat(screenScaling)); // Apply screen scaling if required // Camera rotation and scaling is always relative to target Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); @@ -1193,6 +1197,7 @@ void EndMode2D(void) rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) rlLoadIdentity(); // Reset current matrix (MODELVIEW) + rlMultMatrixf(MatrixToFloat(screenScaling)); // Apply screen scaling if required } // Initializes 3D mode with custom camera (3D) @@ -1246,6 +1251,8 @@ void EndMode3D(void) rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) + rlMultMatrixf(MatrixToFloat(screenScaling)); // Apply screen scaling if required + rlDisableDepthTest(); // Disable DEPTH_TEST for 2D } @@ -1284,22 +1291,8 @@ void EndTextureMode(void) rlDisableRenderTexture(); // Disable render target - // Set viewport to default framebuffer size (screen size) - SetupViewport(); - - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - - // Set orthographic projection to current framebuffer size - // NOTE: Configured top-left corner as (0, 0) - rlOrtho(0, GetScreenWidth(), GetScreenHeight(), 0, 0.0f, 1.0f); - - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - - // Reset current screen size - currentWidth = GetScreenWidth(); - currentHeight = GetScreenHeight(); + // Set viewport to default framebuffer size + SetupViewport(renderWidth, renderHeight); } // Returns a ray trace from mouse position @@ -2336,12 +2329,11 @@ static bool InitGraphicsDevice(int width, int height) currentWidth = width; currentHeight = height; + screenScaling = MatrixIdentity(); // No draw scaling required by default + // NOTE: Framebuffer (render area - renderWidth, renderHeight) could include black bars... // ...in top-down or left-right to match display aspect ratio (no weird scalings) - // Screen scaling matrix is required in case desired screen area is different than display area - screenScaling = MatrixIdentity(); - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSetErrorCallback(ErrorCallback); @@ -2388,7 +2380,7 @@ static bool InitGraphicsDevice(int width, int height) //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers -#if defined(PLATFORM_DESKTOP) +#if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI) // NOTE: If using external GLFW, it requires latest GLFW 3.3 for this functionality glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on #endif @@ -2468,9 +2460,11 @@ static bool InitGraphicsDevice(int width, int height) // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched // by the sides to fit all monitor space... - // At this point we need to manage render size vs screen size - // NOTE: This function uses and modifies global module variables: - // screenWidth/screenHeight - renderWidth/renderHeight - screenScaling + // Try to setup the most appropiate fullscreen framebuffer for the requested screenWidth/screenHeight + // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) + // Modified global variables: screenWidth/screenHeight - renderWidth/renderHeight - renderOffsetX/renderOffsetY - screenScaling + // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... + // HighDPI monitors are properly considered in a following similar function: SetupViewport() SetupFramebuffer(displayWidth, displayHeight); window = glfwCreateWindow(displayWidth, displayHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); @@ -2494,12 +2488,6 @@ static bool InitGraphicsDevice(int width, int height) if (windowPosY < 0) windowPosY = 0; glfwSetWindowPos(window, windowPosX, windowPosY); - - // Get window HiDPI scaling factor - float scaleRatio = 0.0f; - glfwGetWindowContentScale(window, &scaleRatio, NULL); - scaleRatio = roundf(scaleRatio); - //screenScaling = MatrixScale(scaleRatio, scaleRatio, scaleRatio); #endif renderWidth = screenWidth; renderHeight = screenHeight; @@ -2886,23 +2874,23 @@ static bool InitGraphicsDevice(int width, int height) } #endif // PLATFORM_ANDROID || PLATFORM_RPI - renderWidth = screenWidth; - renderHeight = screenHeight; - // Initialize OpenGL context (states and resources) - // NOTE: screenWidth and screenHeight not used, just stored as globals + // NOTE: screenWidth and screenHeight not used, just stored as globals in rlgl rlglInit(screenWidth, screenHeight); - // Setup default viewport - SetupViewport(); + int fbWidth = renderWidth; + int fbHeight = renderHeight; - // Initialize internal projection and modelview matrices - // NOTE: Default to orthographic projection mode with top-left corner at (0,0) - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - rlOrtho(0, renderWidth - renderOffsetX, renderHeight - renderOffsetY, 0, 0.0f, 1.0f); - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) +#if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI) + glfwGetFramebufferSize(window, &fbWidth, &fbHeight); + + // Screen scaling matrix is required in case desired screen area is different than display area + screenScaling = MatrixScale((float)fbWidth/screenWidth, (float)fbHeight/screenHeight, 1.0f); + SetMouseScale((float)screenWidth/fbWidth, (float)screenHeight/fbHeight); +#endif // PLATFORM_DESKTOP && SUPPORT_HIGH_DPI + + // Setup default viewport + SetupViewport(fbWidth, fbHeight); ClearBackground(RAYWHITE); // Default background color for raylib games :P @@ -2912,21 +2900,32 @@ static bool InitGraphicsDevice(int width, int height) return true; } -// Set viewport parameters -static void SetupViewport(void) +// Set viewport for a provided width and height +static void SetupViewport(int width, int height) { -#if defined(__APPLE__) - // Get framebuffer size of current window - // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer is automatically reasized to adapt to new DPI. - // When OS does that, it can be detected using GLFW3 callback: glfwSetFramebufferSizeCallback() - int fbWidth, fbHeight; - glfwGetFramebufferSize(window, &fbWidth, &fbHeight); - rlViewport(renderOffsetX/2, renderOffsetY/2, fbWidth - renderOffsetX, fbHeight - renderOffsetY); -#else - // Initialize screen viewport (area of the screen that you will actually draw to) - // NOTE: Viewport must be recalculated if screen is resized + renderWidth = width; + renderHeight = height; + + // Set viewport width and height + // NOTE: We consider render size and offset in case black bars are required and + // render area does not match full display area (this situation is only applicable on fullscreen mode) rlViewport(renderOffsetX/2, renderOffsetY/2, renderWidth - renderOffsetX, renderHeight - renderOffsetY); -#endif + + rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix + rlLoadIdentity(); // Reset current matrix (PROJECTION) + + // Set orthographic projection to current framebuffer size + // NOTE: Configured top-left corner as (0, 0) + rlOrtho(0, renderWidth, renderHeight, 0, 0.0f, 1.0f); + + rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix + rlLoadIdentity(); // Reset current matrix (MODELVIEW) + + // Window size must be updated to be used on 3D mode to get new aspect ratio (BeginMode3D()) + // NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor, + // for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported) + currentWidth = screenWidth; + currentHeight = screenHeight; } // Compute framebuffer size relative to screen size and display size @@ -2959,7 +2958,7 @@ static void SetupFramebuffer(int width, int height) // Screen scaling required float scaleRatio = (float)renderWidth/(float)screenWidth; - screenScaling = MatrixScale(scaleRatio, scaleRatio, scaleRatio); + screenScaling = MatrixScale(scaleRatio, scaleRatio, 1.0f); // NOTE: We render to full display resolution! // We just need to calculate above parameters for downscale matrix and offsets @@ -3705,24 +3704,7 @@ static void CursorEnterCallback(GLFWwindow *window, int enter) // NOTE: Window resizing not allowed by default static void WindowSizeCallback(GLFWwindow *window, int width, int height) { - // If window is resized, viewport and projection matrix needs to be re-calculated - rlViewport(0, 0, width, height); // Set viewport width and height - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - rlOrtho(0, width, height, 0, 0.0f, 1.0f); // Orthographic projection mode with top-left corner at (0,0) - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - rlClearScreenBuffers(); // Clear screen buffers (color and depth) - - // Window size must be updated to be used on 3D mode to get new aspect ratio (BeginMode3D()) - // NOTE: Be careful! GLFW3 will choose the closest fullscreen resolution supported by current monitor, - // for example, if reescaling back to 800x450 (desired), it could set 720x480 (closest fullscreen supported) - screenWidth = width; - screenHeight = height; - renderWidth = width; - renderHeight = height; - currentWidth = width; - currentHeight = height; + SetupViewport(width, height); // Reset viewport and projection matrix for new size // NOTE: Postprocessing texture is not scaled to new size