libsdl-org / SDL

Simple Directmedia Layer
https://libsdl.org
zlib License
10k stars 1.85k forks source link

SDL2 - Emscripten / HTML5 - manageAspectRatioFitting AND HighDPI #9151

Open corentin35000 opened 8 months ago

corentin35000 commented 8 months ago

Hello, I use my own engine based on the SDL2! It already works on Android, iOS, Windows, macOS and Linux, I'm almost finished with Emscripten (HTML5), but I just have a problem with scaling! It works well on all platforms except HTML5, I implemented a LETTERBOX or OVERSCAN mode (which works except on HTML5) here is my gameloop:

`void rc2d_gameloop(void) {

ifdef EMSCRIPTEN

if (!gameIsRunning) 
{
    emscripten_cancel_main_loop();
}

endif

rc2d_deltatimeframerates_start();
rc2d_processevent();
if (callbacksEngine.rc2d_update != NULL) callbacksEngine.rc2d_update(rc2d_deltaTime);
rc2d_graphics_clear();
if (rc2d_renderLogicalSizeMode != RC2D_RENDER_LOGICAL_SIZE_MODE_NONE) rc2d_prepareScaledRendering();
if (callbacksEngine.rc2d_draw != NULL) callbacksEngine.rc2d_draw();
if (rc2d_renderLogicalSizeMode != RC2D_RENDER_LOGICAL_SIZE_MODE_NONE) rc2d_finalizeScaledRendering();
rc2d_graphics_present();
rc2d_deltatimeframerates_end();

}

void rc2d_prepareScaledRendering(void) { // Definir la texture comme cible de rendu SDL_SetRenderTarget(rc2d_sdl_renderer, rc2d_renderTarget); }

void rc2d_finalizeScaledRendering(void) { // Retablir le rendu à l'ecran SDL_SetRenderTarget(rc2d_sdl_renderer, NULL);

// Mise a l echelle + letter box or overscan
SDL_Rect destRect;
rc2d_manageAspectRatioFitting(&destRect);

// Dessiner la texture de rendu agrandie à l'ecran
SDL_RenderCopy(rc2d_sdl_renderer, rc2d_renderTarget, NULL, &destRect);

}

void rc2d_manageAspectRatioFitting(SDL_Rect* destRect) { // Obtenez les dimensions de sortie du rendu (resolution reelle), au lieu de la taille de la fenetre (qui comprends aussi le HIGH DPI) int outputWidth, outputHeight; rc2d_graphics_getRendererOutputSize(&outputWidth, &outputHeight);

// Dimensions de la texture de rendu (resolution virtuelle du jeu)
int textureWidth = rc2d_sdl_renderer_width;
int textureHeight = rc2d_sdl_renderer_height;

// Calculer le facteur de mise à l'echelle pour remplir l'ecran
rc2d_aspectRatioScaleX = (double)outputWidth / (double)textureWidth;
rc2d_aspectRatioScaleY = (double)outputHeight / (double)textureHeight;
double scale = 1.0;

// Utiliser fmin pour le letter boxing et fmax pour l'overscan (selon le besoin)
if (rc2d_renderLogicalSizeMode == RC2D_RENDER_LOGICAL_SIZE_MODE_LETTERBOX)
{
    scale = fmin(rc2d_aspectRatioScaleX, rc2d_aspectRatioScaleY);
}
else if (rc2d_renderLogicalSizeMode == RC2D_RENDER_LOGICAL_SIZE_MODE_OVERSCAN)
{
    scale = fmax(rc2d_aspectRatioScaleX, rc2d_aspectRatioScaleY);

    // Calculer le decalage necessaire pour centrer le contenu (notamment la GUI et les HUD) dans la fenetre window
    // Ceci n'ai pas utiliser la, c'est pour les jeux qui veulent utiliser l'overscan pour recentrer les elements comme HUD..etc
    rc2d_offsetXOverscan = (outputWidth - (textureWidth * scale)) / 2.0;
    rc2d_offsetYOverscan = (outputHeight - (textureHeight * scale)) / 2.0;
}

if (destRect == NULL) return;

// Calculer les nouvelles dimensions de destination
destRect->w = textureWidth * scale; // Largeur agrandie
destRect->h = textureHeight * scale; // Hauteur agrandie
destRect->x = (outputWidth - destRect->w) / 2; // Centrer horizontalement
destRect->y = (outputHeight - destRect->h) / 2; // Centrer verticalement

} ``

JS side (emscripten attached to .html):

`<!DOCTYPE html>

RC2D HTML5 {{{ SCRIPT }}} ` AND : `/**************************************/ /* RENDERER */ /**************************************/ #ifdef __EMSCRIPTEN__ void rc2d_graphics_resizeWindowForCanvas(int width, int height, double devicePixelRatio) { SDL_SetWindowSize(rc2d_sdl_window, width, height); rc2d_sdl_window_width = width; rc2d_sdl_window_height = height; rc2d_devicePixelRatioCanvas = devicePixelRatio; } // Recupere les Pixels Physique (pixels reel) du renderer pour le canvas void rc2d_graphics_getRendererOutputSizeForCanvas(int* width, int* height) { *width = rc2d_sdl_renderer_width * rc2d_devicePixelRatioCanvas; *height = rc2d_sdl_renderer_height * rc2d_devicePixelRatioCanvas; } #endif void rc2d_graphics_getRendererOutputSize(int* width, int* height) { #ifdef __EMSCRIPTEN__ rc2d_graphics_getRendererOutputSizeForCanvas(width, height); #else int result = SDL_GetRendererOutputSize(rc2d_sdl_renderer, width, height); if (result != 0) { SDL_Log("Could not get renderer output size: %s", SDL_GetError()); } #endif`
corentin35000 commented 8 months ago

What am I doing wrong? Thanks in advance !