SDL2 Texture Access
-
Hey,
Ich würde gerne ein Bild mittels SDL2 laden und würde gerne die Pixel auslesen und auf RGBA prüfen wollen.
Ich nutze zunächst ein SDL_Surface und darüber die Funktion IMG_Load(). Das Surface wandel ich dann in eine SDL_Texture um mittels der SDL_CreateTextureFromSurface Funktion. Nun würde ich gerne die SDL_RenderReadPixels Funktion nutzen.
int result = 0; SDL_Rect * pPixelPos = new SDL_Rect; pPixelPos->x = 0; pPixelPos->y = 0; pPixelPos->w = 1; pPixelPos->h = 1; void * pPixels = NULL; for (int r = 0; r < height; r++) { for(int c = 0 ; c < width ; c++) { pPixelPos->x = c; pPixelPos->y = r; result = SDL_RenderReadPixels(pRenderer, pPixelPos, 0, pPixels, 4); } }
pPixels hat aber immer den Wert 0x00000000. Muss die Textur dafür die Zugriffsberechtigung SDL_TEXTUREACCESS_STREAMING haben? Weil dann hab ich ein Problem. Die kriegt es durch die Funktion SDL_CreateTextureFromSurface auch nicht. Da ist sie nämlich standardmäßig auf SDL_TEXTUREACCESS_STATIC. Ich könnte höchstens eine neue Textur erstellen...
mittels SDL_CreateTexture und dann die Zugriffsberechtigung auf SDL_TEXTUREACCESS_STREAMING setzen, allerdings hätte dann die Textur das Format SDL_PIXELFORMAT_RGB24 ... und ich vermute mal stark, dass mir dann der Alpha Kanal fehlt... Wie kann ich also die SDL_RenderReadPixels Funktion nutzen und jeden Pixel auslesen?
pPixels habe ich mir beim debuggen in jedem Schleifendurchlauf angeschaut. Mir ist klar, dass ich die Variable noch nicht nutze. Es ist aber wie gesagt immer der gleiche Wert, Pixel für Pixel.
-
Ich denke mal du musst pPixels allozieren. Bei 32bit Pixels als unsigned int, oder so (wobei ich mir hier nicht sicher bin). SDL_RenderReadPixels schreibt dann in pPixels einfach rein, afaik.
unsigned int pPixels[anzahlZuLesendenPixel] = {0}; ... SDL_RenderReadPixels(pRenderer, pPixelPos, 0, pPixels, 4);
Nebenbei ist mir aufgefallen, dass du SDL_RenderReadPixels ziemlich ineffektiv verwendest. Du rufst für jeden einzelnen Pixel diese Funktion auf, welche bei accelerated rendering die Daten von der Grafikkarte an den Hauptspeicher liefert.
Sowas ist ziemlich langsam.
Wenn du dir SDL_RenderReadPixels genau ansiehst merkst du, dass der zweite Parameter ein Rechteck definiert, welches die zu lesenden Pixeldaten angibt.Du könntest dir also die beiden Schleifen sparen und pPixelPos->w auf width, sowie pPixelPos->h auf height setzen.
Wenn du aber sowieso nur ein Bild laden und dort Pixel rauslesen willst, bleib bei SDL_Surface. SDL_Surface hat als member void * pixels, hinter dem sich die Pixeldaten verbergen. In eine SDL_Texture umwandeln brauchst du es nur, wenn du das Bild auch rendern möchtest.
-
Jop, das war ein guter Tipp mit dem SDL_Surface das direkt zu machen. Ich wusste nicht, dass SDL_Surface->pixels einfach ein eindimensionales Array ist und man das Byte für Byte auslesen kann. Problem war dann halt nur, dass SDL_Surfaces standardmäßig auf SDL_PIXELFORMAT_RGB24 gesetzt sind und ich aber den Alpha Kanal brauchte.
Hab dann irgendwo in den tieeeefen Winkeln der SDL Dokumentation die Funktion SDL_ConvertSurfaceFormat() gefunden.
SDL_Surface * pSurfRGBA = SDL_ConvertSurfaceFormat(pSurfImg, SDL_PIXELFORMAT_RGBA8888, 0); Uint8 * pPixels = (Uint8*) pSurfRGBA->pixels; Uint8 pixel = *(pPixels + 6);
So kann ich schön alles Byte für Byte auslesen, perfekt! Anordnung der Bytes ist übrigens umgekehrt. (ABGR)
Dass das ein sehr langsamer Prozess ist, ist mir klar. Das passiert bei mir auch nur im initialisieren-Teil meines Programmes und soll eine (hoffentlich) bessere Kollisionserkennung vorbereiten, wo ich den Alpha Kanal rausfiltern will. Das kommt in der Programmschleife nicht vor.
-
Kleiner Tip: Pixelgenaue Kollisionserkennung über Alpha-Kanal ist für den Spieler meist eher nervig.