SDL_Image / PNG Datei wird nicht angezeigt
-
Hey,
Ich möchte gerne ein PNG Bild anzeigen lassen. Und es funktioniert nicht Ich verwende Visual Studio 2013, SDL 2.0.1 und SDL2_image-2.0.0. Im Code unten wird deutlich, dass ich für die Konsole, die immer mit geöffnet wird, Fehlerausgaben generieren lasse. Daher weiß ich, dass alle Funktionen die richtigen Werte zurückzugeben scheinen. Es sollte also alles funktionieren. Wenn ich das Bild beispielsweise aus dem Verzeichnis entferne kriege ich eben auch jede Menge Fehler. Das Bild wird nur einfach nicht angezeigt.
Das Programm ist objektorientier gestaltet. Ich hoffe das wird jetzt nicht zu viel Code.
Klassendeklaration:
#ifndef H_CBUILD #define H_CBUILD #include "globals.h" #include <SDL.h> #include <SDL_image.h> #include "crandompixels.h" #include "cimage.h" // gamestate enum gameState { init_menu = 0, menu = 1 }; // application class class CBuild { private: // var SDL_Window * pWindow; SDL_Surface * pSurfWnd; SDL_Event event; SDL_Renderer * pRenderer; SDL_DisplayMode displaymode; bool execute; // gibt an, ob Programm laufen, oder beendet werden soll bool render; // gibt an, ob neu gezeichnet werden soll, oder nicht gameState state; CRandomPixels * pEffectRandomPixels; // images CImage * pIMG_logo; public: CBuild(); ~CBuild(); // main void init(); void interact(); void draw(); // GET bool getExFlag(); // sub functions void keydown(); }; #endif
Imageklasse:
#ifndef H_CIMAGE #define H_CIMAGE #include "globals.h" #include <SDL.h> #include <SDL_image.h> class CImage { private: SDL_Surface * pSurfImage; SDL_Surface * pSurfUpd; SDL_Rect * pPosition; char * pFile; public: CImage(); ~CImage(); void createIMG(char*, int, int); void drawIMG(SDL_Renderer*, SDL_Surface*); }; #endif
Imageklasse Definitionen:
#include "cimage.h" /////////////////////////// // constr. / destr. /////////////////////////// CImage::CImage() { pPosition = new SDL_Rect; pFile = NULL; pSurfImage = NULL; pSurfUpd = NULL; } CImage::~CImage() { SDL_FreeSurface(pSurfImage); delete pPosition; delete pFile; delete pSurfImage; delete pSurfUpd; } /////////////////////////// // functions /////////////////////////// void CImage::createIMG(char * pName, int x, int y) { #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << "createIMG()\n" << endl; #endif #endif int iflag = 0; SDL_bool bflag = SDL_FALSE; iflag = IMG_Init(IMG_INIT_PNG); #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << "IMG_Init() ->\t" << iflag << endl; #endif #endif pSurfImage = IMG_Load(pName); #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE if(pSurfImage == NULL) {cout << "IMG_Load()\t\tFAILED!" << endl;} else {cout << "IMG_Load()\t\tSUCCESS!" << endl;} #endif #endif pPosition->x = x; pPosition->y = y; pPosition->w = pSurfImage->w; pPosition->h = pSurfImage->h; bflag = SDL_SetClipRect(pSurfImage, pPosition); #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE if(bflag == SDL_FALSE) {cout << "SDL_SetClipRect()\tFAILED!" << endl;} else {cout << "SDL_SetClipRect()\tSUCCESS!" << endl;} #endif #endif #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << "Error:" << IMG_GetError() << endl; #endif #endif #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << endl; #endif #endif } void CImage::drawIMG(SDL_Renderer * pRenderer, SDL_Surface * pSurfWnd) { int iflag = 0; #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << "drawIMG()\n" << endl; #endif #endif pSurfUpd = SDL_ConvertSurface(pSurfImage, pSurfWnd->format, 0); #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE if(pSurfUpd == NULL) {cout << "SDL_ConvertSurface()\tFAILED!" << endl;} else {cout << "SDL_ConvertSurface()\tSUCCESS!" << endl;} #endif #endif iflag = SDL_BlitSurface(pSurfUpd, NULL, pSurfWnd, pPosition); #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE if(iflag == 0) {cout << "SDL_BlitSurface()\tSUCCESS!" << endl;} else {cout << "SDL_BlitSurface()\tFAILED!" << endl;} #endif #endif #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE cout << endl; #endif #endif }
Es gibt eine Nachrichtenschleife, wo interact und draw die ganze Zeit im Wechsel aufgerufen werden. Die draw Funktion sieht so aus:
#include "cbuild.h" /////////////////////////// // main draw function /////////////////////////// void CBuild::draw() { int iflag = 0; if(render) { #ifdef DEBUGMODE #ifdef DEBUGDRAW cout << "draw()\n" << endl; #endif #endif if(state == init_menu) { pEffectRandomPixels->drawRandomPixels(pRenderer, 0xdc, 0xdc, 0xdc, 0xff); pIMG_logo->drawIMG(pRenderer, pSurfWnd); state = menu; } iflag = SDL_UpdateWindowSurface(pWindow); #ifdef DEBUGMODE #ifdef DEBUGDRAW if(iflag == 0) {cout << "SDL_UpdateWindowSurface()\tSUCCESS!" << endl;} else {cout << "SDL_UpdateWindowSurface()\tFAILED!" << endl;} #endif #endif render = 0; #ifdef DEBUGMODE #ifdef DEBUGDRAW cout << endl; #endif #endif } }
SDL ist ziemliches Neuland für mich. Es kann also sein, dass ich einfach was vergesse oder falsch mache. Über jede Hilfe würde ich mich sehr freuen!
Gruß,
PadMad
-
Ich bin den code nicht vollständig durchgegangen, aber SDL_UpdateWindowSurface ist die SDL 2.0 version von SDL_Flip, das passt also schonmal. Einzige Idee die ich momentan habe, ist das deine cliprects, bzw die positionen wo du hinblittest falsch gesetzt sind. Z.B. wenn du ein fenster mit w=640 hast und an die position 640 blittest kommt natürlich auch nichts mehr an. Oder dein Blitrect ist nur ein pixel groß oder sowas. Ist mir auch schonmal passiert. Weitere Vorschläge für einen Test, den ich bei SDL immer recht hilfreich bei solchen Fällen: Du kannst mit SDL surfaces als datei speichern - schreib dir mal die einzelnen surfaces raus, und schau sie dir genauer an.
[edit]
Das "p" vor deinen Variablennamen hält mich wirklich davon ab, da etwas genauer reinzuschaun. Finde das sehr mühsam zu lesen.
-
Hey,
Vielen Dank für die Antwort. Das "p" steht einfach nur für Pointer. Falls du das Prefix meinst und nicht die Variable.
Das mit den Clipping areas ist nen guter Ansatz, allerdings vertraue ich darauf, dass SDL_SetClipRect() dann SDL_FALSE zurückgeben müsste, sollten die Koordinaten irgendwie aus der Reihe tanzen. Es wird aber SDL_TRUE zurückgeben.
Momentan setze ich die Clipping area des Image Surfaces. Oder kann es sein, dass ich die clipping area des Window Surfaces setzen muss? Hat aber auch nicht funktioniert. Wie gesagt die Funktionen geben ja alle korrekte Werte zurück.
Das Surface in eine Datei zu schreiben. Wie meinst du das genau? Ich weiß, dass man beispielsweise Bitmaps direkt aus einem Surface heraus erstellen kann, glaube ich.
Gruß,
PadMad
-
Mir ist schon klar dass das "p" für pointer steht, find es aber trotzdem unangenehm zu lesen (ich weiß das Leute die das verwenden das irgendwie einfach überlesen können, für mich macht es das lesen halt irgendwie mühsam).
Ich glaube nicht, das du bei SDL_SetClipRect() ein SDL_FALSE zurückbekommst, weil das eher dafür ist, wenn das ClipRect gar nicht gesetzt werden konnte - aber das clip rect wird ja gesetzt, nur auf einen nutzlosen Wert. Zumindest war das bei meinem Fehler mal bei mir so, habe aber SDL 2.0 nicht direkt verwendet sondern habe nur Erfahrung mit 1.x.
Wenn du z.B. bei einer 100x100 surface SetClipRect mit 99,99,100,100 aufrufst wird das intern in 99,99,1,1 umgewandelt, also auf die tatsächliche Größe zurechtgestutzt. Du hast dann zwar ein ClipRect gesetzt, aber nicht mehr unbedingt das, was du wolltest. Deswegen würd ich da ein SDL_TRUE erwarten, aber du müsst ich mir selbst nochmal die doku anschaun. (Nachgeschaut: Die Doku sagt dass es nur dann FALSE zurückgibt wenn dein x/y wert außerhalb der surface ist, dann wird clipping disabled)
Die clipping area der quelle zu setzen ist iirc richtig.
Mit SDL_SaveBMP(SDL_Surface* surface, const char* filename) solltest du einfach eine surface als BMP in einen dateinamen schreiben können, das geht soweit ich sehe in SDL 2.0 auch.
Probier mal folgendes:
//Funktion DrawIMG SDL_SetClipRect(pSurfWnd, 0); //disable clipping, alternativ auch ein Rect erstellen das garantiert die gesamte größe der surface darstellt SDL_Rect dst; //Ziel rect dst.x = dst.y = 1; //ganz am Anfang hinblitten. SDL_SetAlpha(pSurfUpd,0,128); //disable alpha blending (vielleicht ist das ein Problem?) iflag = SDL_BlitSurface(pSurfUpd, NULL, pSurfWnd, &dst); SDL_SaveBMP(pSurfUpd, "test1.bmp"); //surface als datei speichern, um zu schaun was drinnen steht SDL_SaveBMP(pSurfWnd, "test2.bmp"); //surface als datei speichern, um zu schaun was drinnen steht #ifdef DEBUGMODE #ifdef DEBUG_CIMAGE if(iflag == 0)
Ändere vielleicht noch etwas code damit es nur einmal aufgerufen wird, und schau dir die Dateien an, bzw ob du jetzt etwas auf deinems screen siehst. Ist schon etwas länger her das ich mit SDL gearbeitet habe, vllt habe ich einen kleinen Fehler gemacht, aber die idee sollte klar sein.
Mir ist übrigens auch aufgefallen, das alpha blending ein Problem machen könnte, also mit SetAlpha das mal ausmachen.
-
Hey,
Ich habe meinen DEBUG Code mal erweitert. Die folgende Ausgabe zeigt alle Funktionen und die daneben stehenden Rückgabewerte, die ich zum Zeichnen des PNG benutze und zeigt auch die jeweiligen Surfaces (den jeweils interessanten Teil):
http://s14.directupload.net/images/131225/bgcftciw.png
Das Bild hat eine Größe von 420 * 77 px
Daher glaube ich an sich, dass alles korrekt ist.
Interessant ist aber:Ich entwickle unter Windows 7. Wenn ich unten in der Taskbar über meine Anwendung rüberzoome ist das Bild in der Vorschau tatsächlich auch zu sehen. Ich komme nur nicht mehr in die Anwendung direkt (durch raufklicken) rein, sowie ich einmal ALT-TAB verwendet habe (Ist ja im Vollbildmodus). Da zeichnet sich nichts neu.
Beim aller ersten Mal Zeichnen zeichnet er aber alles andere nur nicht das Bild. Ich mache also definitiv beim Zeichnen irgendwas falsch. Ich zeichne folgende Sachen in genau der Reihenfolge:
Hintergrund (schwarz)
zufällig generierte Pixel
das BildHintergrund und zufällig generierte Pixel klappt. Nur das Bild nicht.
Draw Funktion sieht wie folgt aus.void CBuild::draw() { int iflag = 0; if(render) { if(state == menu) { pEffectRandomPixels->drawRandomPixels(pRenderer, 0xdc, 0xdc, 0xdc, 0xff); pIMG_logo->drawIMG(pRenderer, pSurfWnd); state = menu; } render = 0; } SDL_UpdateWindowSurface(pWindow); }
"render" ist ein flag, was ich benutzen will, um zu verhindern, dass später ständig gezeichnet wird, auch wenn nichts passiert. Ob das Sinn macht weiß ich noch nicht. Aber ob render true oder false ist, ändert nichts am Problem.
Gruß,
PadMad
-
Kannst du mir evtl dein Projekt zur Verfügung stellen, damit ichs mir selbst anschaun kann? Bin schon neugierig was da los ist. Sonst fällt mir halt noch alpha an, die surfaces als BMP speichern zum feststellen WO das Problem ist, und evtl hast du vllt ein Problem mit einer endlosschleife bei pollevent...? Muss man evtl alles mal anschaun :>
-
Hey,
Das wäre super, wenn da mal Jemand rüberschauen würde. Wäre dir sehr dankbar.
http://www.wp1105995.server-he.de/kartoffel.zip
Einfach entpacken. Sind die ganzen Files und die Projektdatei für vc++
Schreib mir am besten über mein Profil ne Email. Ich glaube das geht iwie.EDIT: Das random'en von Pixeln ist leider auch noch verbuggt. Das liegt iwie an den Zufallszahlen. Kann also sein, dass du nen paar Mal starten musst, bis man was sieht
Gruß,
PadMad
-
Mal abgesehen vom bug beim random pixel (hab ihn dann selbst auch gefunden ) funktioniert, es letztlich alles so, wie es soll - zumindest wird das Bild "test" bei mir angezeigt. Ich geh jetzt gleich schlafen, aber das sieht eher nach etwas aus, das eher nichts mit dem code zu tun hat. clean+rebuild versucht?
-
Hey,
Danke für deine Mühe. Also clean und rebuild hat nichts gebracht. Aber wenns bei dir funktioniert und bei mir nicht... Dann weiß ich gerade echt nicht weiter...
Die Frage ist, was hast du gemacht, was ich nicht gemacht habe
EDIT:
habe gerade nochmal alle Bibliotheken und Abhängigkeiten geprüft.
Konfigurationseigentschaften -> VC++ - Verzeichnisse
C:\SDL2_image-2.0.0\include
C:\SDL2-2.0.1\includeLinker -> Eingabe:
SDL2.lib
SDL2main.lib
SDL2_image.libDLL - Dateien
C:\SDL2-2.0.1\lib\x86\ -> SysWOW64
C:\SDL2-2.0.1\lib\x64\ -> System32das gleiche auch mit den aus SDL2 Image.
-
Interessant:
F:\dev\SDL2-2.0.1\include
F:\dev\SDL2_image-2.0.0\includeF:\dev\SDL2-2.0.1\lib\x86
F:\dev\SDL2_image-2.0.0\lib\x86
(hab nur die x86 libs verwendet, ich muss zugeben bin mir nicht sicher, aber x86 und x64 zu mischen kommt mir seltsam vor - kann sein dass du da falsche Funktionen gelinkt bekommst)Additional dependencies:
SDL2.lib
SDL2main.lib
SDL2_image.libDie .dlls hab ich direkt in den Programmordner kopiert - hab nur ne debug build getestet weil ich zu faul war das nochmal für release einzustellen :>
Weiterer Unterschied: Ich hab vs2012 statt vs2013 verwendet
-
Hey,
Ich mische sie nicht. Die 64 bit Dateien befinden sich nur vorsichtigshalber im System32 Ordner. Aber da es eine 32 Bit Anwendung ist, geht der nur an die DLLs im SysWOW64 Ordner. Und linken tue ich ja nur die x86 files. Du hast eigentlich dann auch nichts andereres gemacht, außer Visual Studio 2012 zu verwenden. Ich hoffe es liegt nicht daran, aber das werde ich später nochmal ausprobieren.
-
Ich habe jetzt unter VS 2013 nochmal die DLLs in den work ordner gepackt, aus den System32 und SysWOW64 auch komplett raus gehauen, gecleant, neu rebuildet und getestet. Hat immernoch nicht geklappt.
Jetzt gerade möchte ich Visual Studio 2012 damit zum laufen kriegen, aber, er kennt die standardbibliotheken nicht? Weder time.h, noch iostream noch sonst was. Wie kommt das bitte?
Das war ein leeres Projekt und es ist frisch neu installiert alles.
-
So...Nochmal komplett auf einem anderen Rechner alles wiederholt mit Visual Studio 2012 Express und es kommt genau die gleiche Macke.
Es liegt entweder doch am Code oder du hast was grundsätzlich anders gemacht als ich.
DLL Dateien (nur x86):
Alle im Projektordner
VC++-Verzeichnisse:
Includeverzeichnisse: C:\SDL2-2.0.1\include C:\SDL2_image-2.0.0\include Bibliotheksverzeichnisse: C:\SDL2-2.0.1\lib\x86 C:\SDL2_image-2.0.0\lib\x86
Linker->Eingabe->Zusätzliche Abhängigkeiten
SDL2.lib SDL2main.lib SDL2_image.lib
Bis auf Visual Studio 2012 Express habe ich auch alles neu runtergeladen und alles neu eingebunden. Es muss doch am Code liegen irgendwie, oder am falsch einbinden. Das ist echt deprimierend an so was einfachem schon zu scheitern, weil ich auch einfach nicht weiß warum.