2016-11-28 5 views
0

Wir möchten eine SDL-Oberfläche erstellen, indem wir ein Bild mit SDL_Image laden. Wenn die Abmessungen einen Grenzwert überschreiten, ändern Sie die Größe der Oberfläche.SDL2 Größe einer Oberfläche ändern

Der Grund, warum wir dies tun müssen, ist auf Raspbian SDL wirft einen Fehler beim Erstellen einer Textur von der Oberfläche ('Textur Abmessungen sind auf 2048x2048 begrenzt'). Während das ein sehr großes Bild ist, wollen wir nicht, dass Benutzer sich Gedanken über die Bildgröße machen, wir wollen die Größe für sie ändern. Obwohl wir dieses Limit für Windows nicht erreicht haben, versuchen wir, die Lösung für Windows zu entwickeln und Probleme bei der Größenänderung der Textur zu haben.

für eine Lösung dort gesucht haben ähnliche Fragen ...:

ist ein Brauch blitter oder SDL_gfx notwendig mit Strom SDL2 (diejenigen, antwortet vor dem SDL2-Release von 2013)? SDLRenderCopyEx hilft nicht, da Sie die Textur generieren müssen, wo unser Problem auftritt.

So haben wir versucht, einige der verfügbaren Blitten Funktionen wie SDL_BlitScaled, unten ist ein einfaches Programm eine 2500x2500 PNG ohne Skalierung zu machen:

#include <SDL.h> 
#include <SDL_image.h> 
#include <sstream> 
#include <string> 

SDL_Texture * get_texture(
    SDL_Renderer * pRenderer, 
    std::string image_filename) { 
    SDL_Texture * result = NULL; 

    SDL_Surface * pSurface = IMG_Load(image_filename.c_str()); 

    if (pSurface == NULL) { 
     printf("Error image load: %s\n", IMG_GetError()); 
    } 
    else { 
     SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface); 

     if (pTexture == NULL) { 
      printf("Error image load: %s\n", SDL_GetError()); 
     } 
     else { 
      SDL_SetTextureBlendMode(
       pTexture, 
       SDL_BLENDMODE_BLEND); 

      result = pTexture; 
     } 

     SDL_FreeSurface(pSurface); 
     pSurface = NULL; 
    } 

    return result; 
} 

int main(int argc, char* args[]) { 
    SDL_Window * pWindow = NULL; 
    SDL_Renderer * pRenderer = NULL; 

    // set up 
    SDL_Init(SDL_INIT_VIDEO); 

    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); 

    SDL_Rect screenDimensions; 

    screenDimensions.x = 0; 
    screenDimensions.y = 0; 

    screenDimensions.w = 640; 
    screenDimensions.h = 480; 

    pWindow = SDL_CreateWindow("Resize Test", 
     SDL_WINDOWPOS_UNDEFINED, 
     SDL_WINDOWPOS_UNDEFINED, 
     screenDimensions.w, 
     screenDimensions.h, 
     SDL_WINDOW_SHOWN); 

    pRenderer = SDL_CreateRenderer(pWindow, 
     -1, 
     SDL_RENDERER_ACCELERATED); 

    IMG_Init(IMG_INIT_PNG); 

    // render 
    SDL_SetRenderDrawColor(
     pRenderer, 
     0, 
     0, 
     0, 
     0); 

    SDL_RenderClear(pRenderer); 

    SDL_Texture * pTexture = get_texture(
     pRenderer, 
     "2500x2500.png"); 

    if (pTexture != NULL) { 
     SDL_RenderCopy(
      pRenderer, 
      pTexture, 
      NULL, 
      &screenDimensions); 

     SDL_DestroyTexture(pTexture); 
     pTexture = NULL; 
    } 

    SDL_RenderPresent(pRenderer); 

    // wait for quit 
    bool quit = false; 

    while (!quit) 
    { 
     // poll input for quit 
     SDL_Event inputEvent; 

     while (SDL_PollEvent(&inputEvent) != 0) { 
      if ((inputEvent.type == SDL_KEYDOWN) && 
       (inputEvent.key.keysym.sym == 113)) { 
       quit = true; 
      } 
     } 
    } 

    IMG_Quit(); 

    SDL_DestroyRenderer(pRenderer); 

    pRenderer = NULL; 

    SDL_DestroyWindow(pWindow); 

    pWindow = NULL; 

    return 0; 
} 

Ändern der get_texture Funktion, so dass es eine Grenze identifiziert und versucht, zu erstellen eine neue Oberfläche:

SDL_Texture * get_texture(
    SDL_Renderer * pRenderer, 
    std::string image_filename) { 
    SDL_Texture * result = NULL; 

    SDL_Surface * pSurface = IMG_Load(image_filename.c_str()); 

    if (pSurface == NULL) { 
     printf("Error image load: %s\n", IMG_GetError()); 
    } 
    else { 
     const int limit = 1024; 
     int width = pSurface->w; 
     int height = pSurface->h; 

     if ((width > limit) || 
      (height > limit)) { 
      SDL_Rect sourceDimensions; 
      sourceDimensions.x = 0; 
      sourceDimensions.y = 0; 
      sourceDimensions.w = width; 
      sourceDimensions.h = height; 

      float scale = (float)limit/(float)width; 
      float scaleH = (float)limit/(float)height; 

      if (scaleH < scale) { 
       scale = scaleH; 
      } 

      SDL_Rect targetDimensions; 
      targetDimensions.x = 0; 
      targetDimensions.y = 0; 
      targetDimensions.w = (int)(width * scale); 
      targetDimensions.h = (int)(height * scale); 

      SDL_Surface *pScaleSurface = SDL_CreateRGBSurface(
       pSurface->flags, 
       targetDimensions.w, 
       targetDimensions.h, 
       pSurface->format->BitsPerPixel, 
       pSurface->format->Rmask, 
       pSurface->format->Gmask, 
       pSurface->format->Bmask, 
       pSurface->format->Amask); 

      if (SDL_BlitScaled(pSurface, NULL, pScaleSurface, &targetDimensions) < 0) { 
       printf("Error did not scale surface: %s\n", SDL_GetError()); 

       SDL_FreeSurface(pScaleSurface); 
       pScaleSurface = NULL; 
      } 
      else { 
       SDL_FreeSurface(pSurface); 

       pSurface = pScaleSurface; 
       width = pSurface->w; 
       height = pSurface->h; 
      } 
     } 

     SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface); 

     if (pTexture == NULL) { 
      printf("Error image load: %s\n", SDL_GetError()); 
     } 
     else { 
      SDL_SetTextureBlendMode(
       pTexture, 
       SDL_BLENDMODE_BLEND); 

      result = pTexture; 
     } 

     SDL_FreeSurface(pSurface); 
     pSurface = NULL; 
    } 

    return result; 
} 

SDL_BlitScaled schlägt mit einem Fehler andere Variationen haben einen ähnlichen Fehler ‚Blit Kombination nicht unterstützt‘:

Dann haben wir ein nicht skaliertes Blit ausprobiert ... welches keinen Fehler ausgelöst hat, sondern nur weiß (nicht die klare Farbe oder eine Farbe im Bild).

SDL_BlitSurface(pSurface, &targetDimensions, pScaleSurface, &targetDimensions) 

Damit blitting Funktion arbeiten wir nicht dann versucht, es mit dem gleichen Bild als Bitmap (nur die .png als .bmp Export), noch die Datei mit SDL_image Laden und beide dieser Funktionen arbeiten mit SDL_BlitScaled Skalierung als erwartet

Nicht sicher, was hier falsch läuft (wir erwarten und brauchen Unterstützung für wichtige Bilddateiformate wie. Png) oder wenn dies der empfohlene Ansatz ist, jede Hilfe geschätzt!

+1

Um Blit-Funktionen verwenden zu können, muss Ihre Hardware GL_EXT_framebuffer_blit unterstützen - integrierte Grafik und einige Workstation-GPUs werden normalerweise nicht unterstützt. –

+1

Was ist das Pixelformat Ihres Quellbildes (Bits pro Pixel und Masken)? Dieser Fehler wird erzeugt, wenn keine Blitting-Implementierung für die Kombination von Quell- und Zieloberflächenformat vorliegt; Ich schlage vor, 'normale' 8 Bits pro Kanal Zieloberfläche zu erstellen (24 Bit für RGB, 32 für RGBA) und Blitting hinein. – keltar

+0

@ bruno-ferreira danke, du hattest Recht, dass Erweiterung wurde nicht unterstützt, also habe ich Treiber für die Grafikkarte installiert und habe es aber leider, wenn nicht auf dieses Problem gerichtet – Paddy

Antwort

1

TL; DR Der Kommentar von @kelter wies mich in der richtigen Richtung und another stack overflow question gab mir eine Lösung: es funktioniert, wenn Sie zum ersten Mal Blit auf eine 32bpp Oberfläche und dann an einem anderen 32bpp Oberfläche BlitScaled. Das funktionierte für 8 und 24 Bit Tiefe PNGs, 32 Bit waren unsichtbar again another stack overflow question vorgeschlagen, zuerst die Oberfläche vor dem Blitting zu füllen.

Eine aktualisierte get_texture Funktion:

SDL_Texture * get_texture(
    SDL_Renderer * pRenderer, 
    std::string image_filename) { 
    SDL_Texture * result = NULL; 

    SDL_Surface * pSurface = IMG_Load(image_filename.c_str()); 

    if (pSurface == NULL) { 
     printf("Error image load: %s\n", IMG_GetError()); 
    } 
    else { 
     const int limit = 1024; 
     int width = pSurface->w; 
     int height = pSurface->h; 

     if ((width > limit) || 
      (height > limit)) { 
      SDL_Rect sourceDimensions; 
      sourceDimensions.x = 0; 
      sourceDimensions.y = 0; 
      sourceDimensions.w = width; 
      sourceDimensions.h = height; 

      float scale = (float)limit/(float)width; 
      float scaleH = (float)limit/(float)height; 

      if (scaleH < scale) { 
       scale = scaleH; 
      } 

      SDL_Rect targetDimensions; 
      targetDimensions.x = 0; 
      targetDimensions.y = 0; 
      targetDimensions.w = (int)(width * scale); 
      targetDimensions.h = (int)(height * scale); 

      // create a 32 bits per pixel surface to Blit the image to first, before BlitScaled 
      // https://stackoverflow.com/questions/33850453/sdl2-blit-scaled-from-a-palettized-8bpp-surface-gives-error-blit-combination/33944312 
      SDL_Surface *p32BPPSurface = SDL_CreateRGBSurface(
       pSurface->flags, 
       sourceDimensions.w, 
       sourceDimensions.h, 
       32, 
       pSurface->format->Rmask, 
       pSurface->format->Gmask, 
       pSurface->format->Bmask, 
       pSurface->format->Amask); 

      if (SDL_BlitSurface(pSurface, NULL, p32BPPSurface, NULL) < 0) { 
       printf("Error did not blit surface: %s\n", SDL_GetError()); 
      } 
      else { 
       // create another 32 bits per pixel surface are the desired scale 
       SDL_Surface *pScaleSurface = SDL_CreateRGBSurface(
        p32BPPSurface->flags, 
        targetDimensions.w, 
        targetDimensions.h, 
        p32BPPSurface->format->BitsPerPixel, 
        p32BPPSurface->format->Rmask, 
        p32BPPSurface->format->Gmask, 
        p32BPPSurface->format->Bmask, 
        p32BPPSurface->format->Amask); 

       // 32 bit per pixel surfaces (loaded from the original file) won't scale down with BlitScaled, suggestion to first fill the surface 
       // 8 and 24 bit depth pngs did not require this 
       // https://stackoverflow.com/questions/20587999/sdl-blitscaled-doesnt-work 
       SDL_FillRect(pScaleSurface, &targetDimensions, SDL_MapRGBA(pScaleSurface->format, 255, 0, 0, 255)); 

       if (SDL_BlitScaled(p32BPPSurface, NULL, pScaleSurface, NULL) < 0) { 
        printf("Error did not scale surface: %s\n", SDL_GetError()); 

        SDL_FreeSurface(pScaleSurface); 
        pScaleSurface = NULL; 
       } 
       else { 
        SDL_FreeSurface(pSurface); 

        pSurface = pScaleSurface; 
        width = pSurface->w; 
        height = pSurface->h; 
       } 
      } 

      SDL_FreeSurface(p32BPPSurface); 
      p32BPPSurface = NULL; 
     } 

     SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface); 

     if (pTexture == NULL) { 
      printf("Error image load: %s\n", SDL_GetError()); 
     } 
     else { 
      SDL_SetTextureBlendMode(
       pTexture, 
       SDL_BLENDMODE_BLEND); 

      result = pTexture; 
     } 

     SDL_FreeSurface(pSurface); 
     pSurface = NULL; 
    } 

    return result; 
} 

Der Kommentar von @kelter hatte mich näher an der Oberfläche Pixelformate aussehen, Bitmaps bei 24 bpp arbeiteten, arbeiten pngs wurden bei 8bpp geladen und nicht.Versucht, die Zieloberfläche auf 24 oder 32 bpp zu ändern, aber das hat nicht geholfen. Wir hatten den png mit automatisch erkannter Bittiefe erzeugt, indem wir ihn auf 8 oder 24 gesetzt hatten und das BlitScaled auf einer Oberfläche mit den gleichen Bits pro Pixel ausgeführt hatten, obwohl es für 32 nicht funktionierte. Das Googlen des Blitkonversionsfehlers führte zu die Frage und Antwort von @Petruza.

Update War ein bisschen schnell schriftlich diese Antwort, die ursprüngliche Lösung behandelt BMP und 8 und 24 Bit PNGs aber 32-Bit-PNGs wurden nicht gerendert. @Retired Ninja Antwort auf eine andere Frage über Blit_Scaled vorgeschlagen, die Oberfläche vor dem Aufruf der Funktion und das sortiert es, gibt es another question im Zusammenhang mit der Einstellung Alpha auf neue Oberflächen, die relevant sein können (insbesondere wenn Sie Transparenz benötigten), aber mit einer Volltonfarbe füllen ist genug für mich ... für jetzt.

Verwandte Themen