SDL - SDL_MapRGBA RGBA in Hex umrechnen



  • Hallo Forum!

    Für meinen Prof. darf ich gerade ein Malprogramm schreiben. Es soll unter anderem die "Füllfkt." haben und damit ärgere ich mich gerade tierisch rum.

    Dieses Problem will ich lösen, in dem ich den Farbwert des Pixels x/y auslese und dann alle Pixel mit gleichem Farbwert in der Nachbarschaft mit der zu füllenden Farbe beschreibe.

    Das Auslesen des Farbwertes an der Stelle x/y klappt schon, aber wenn ich diesen 8-Bit RGBA-Farbwert versuche mit SDL-MapRGBA in Hex umzurechnen, kommt nur Mist raus:

    Uint32 farbe = 0xff0000f // Farbe ROT - Referenzwert
    Uint8 rc, gc, bc, ac
    
    SDL_LockSurface (s);
    SDL_PixelFormat *format =  s->format;
    
    Uint32 p = getpixel(s, positions.vx[0], positions.vy[0]);
    SDL_GetRGBA(p, format, &rc, &gc, &bc, &ac);
    SDL_UnlockSurface (s);
    cout << "r: " << (int)rc << " g: " << (int)gc << " b: " << (int)bc << " alpha: " << (int)ac << endl;
    
    Uint32 ausgabe = SDL_MapRGBA(s->format, rc, gc, bc, ac); //Umrechnen der 8-Bit Farbwerte in einen 32Bit Hex-Farbwert
    
    cout << "Ausgabe: " << hex << ausgabe << endl; //Das Surface an der Stelle x/y ist ebenfalls rot 0xff0000f
    cout << "Farbe: " << hex << farbe << endl; //Also sollte Ausgabe mit Farbe identisch sein. Ist es aber leider nicht!
    

    Ausgabe:

    r: 255 g: 0 b: 0 alpha: 255
    Ausgabe: f800
    Farbe: ff0000ff
    

    Die Ausgabe der einzelnen 8Bit Komponenten sind noch korrekt. Nur ist Ausgabe und Farbe nicht mehr gleich... Irgendwas geht beim umrechnen der 8Bit in den 32Bit Farbwert irgendwas schief.

    Für nen Tipp wäre ich echt dankbar!


  • Mod

    welches format uebergibst du denn?



  • Format?

    Meinst du den Rückgabewert von:

    SDL_PixelFormat *format =  s->format;
    

    ??

    Das surface habe ich wie folgt angelegt:

    screen = SDL_SetVideoMode(800, 600, 16, SDL_HWSURFACE);
    


  • Wie konvertierst du denn?
    Sicher dass du endianness beachtet hast?


  • Mod

    aves_aquila schrieb:

    Das surface habe ich wie folgt angelegt:

    screen = SDL_SetVideoMode(800, 600, 16, SDL_HWSURFACE);
    

    du willst also einen 16bit farbwert haben?
    wieso verwundert dich dass, das der nicht mit dem 24bit farbwert uebereinstimmt den du einfuetterst 😕



  • @rapso

    Du Fuchs! Das wars!

    screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    

    Da habe ich Trottel gar nicht drüber nachgedacht! Naja, danke für die Hilfe...

    Da habe ich aber noch eine Frage!

    Sollte mir:

    Uint32 ausgabe = SDL_MapRGBA(s->format, rc, gc, bc, ac);
    cout << "Ausgabe: " << hex << ausgabe << endl;
    

    Nicht Ausgabe der Form ff0000ff für volles rot bekommen?
    Die Ausgabe die ich bekomme lautet aber: ff0000 für rot...

    Wobei

    SDL_GetRGBA(p, format, &rc, &gc, &bc, &ac);
    

    Mir für Alpha( == ac) noch nen dezimalen Wert von 255 liefert.

    Das Surface habe ich dann auch mit nem 32Bit Farbraum angelegt, aber bei der Ausgabe des SDL_MapRGBA Ergebnisses fehlt irgendwie das letzte Octet für Alpha.

    Irgendwas scheine ich nicht zu beachten.



  • So, ich habe mal ein möglichst abgespecktes Demo-Programm geschrieben, mit dem sich mein Problem evtl. nachvollziehen lässt.

    Ich Zeichne die Referenzfarbe 0xff0000ff auf das surface um den Mittelpunkt w/2;h/2.
    Dann lese ich das Pixel in der Mitte aus, gebe den dezimalen Wert der einzelnen 8-Bit Kanäle aus und lasse mit SDL_MapRGBA wieder einen 32-Bit Farbwert generieren. Das Ergebnis hat dann aber leider nur 24-Bit. Wo ist der Alpha-Kanal geblieben???

    Ausgabe:

    Referenzfarbe: ff0000ff

    Ausgelesene einzelne 8-Bit Kanäle:
    r: 255 g: 0 b: 0 alpha: 255

    Ausgelesene Farbe: ff0000

    Interessant dürfte da die Fkt. getcolor ab Zeile 64 sein.
    Demoprogramm:

    #include <stdio.h>
    #include <stdlib.h>
    #include <iostream>
    #include <SDL/SDL_image.h>
    #include <SDL/SDL.h>
    #include <SDL/SDL_gfxPrimitives.h>
    
    using namespace std;
    
    Uint32 getpixel(SDL_Surface *surface, int x, int y);
    Uint32 getcolor(SDL_Surface *surface, int x, int y);
    
    int main(void) {
    	SDL_Surface *screen;
    	SDL_Event event;
    	Uint32 farbe = 0xff0000ff;
    
    	int x, y;
    	bool quit = false;
    
    	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    		cout << "Konnte SDL nicht initialisieren: %s\n" << SDL_GetError();
    		return EXIT_FAILURE;
    	}
    
    	atexit(SDL_Quit);
    
    	screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    	if (screen == NULL) {
    		cout << "Videomodus konnte nicht eingerichet werden: " << SDL_GetError()
    				<< endl;
    		return EXIT_FAILURE;
    	}
    
    	x = (screen->w / 2);
    	y = (screen->h / 2);
    
    	boxRGBA(screen, 0, 0, 800, 600, 255, 255, 255, 255);
    	SDL_WM_SetCaption("SDL_MapRGBA Test", 0);
    	filledCircleColor(screen, x, y, 250, farbe);
    	SDL_UpdateRect(screen, 0, 0, 0, 0);
    
    	cout << "Referenzfarbe: " << hex << farbe << endl;
    	cout << "Ausgelesene Farbe: " << hex << getcolor(screen, x, y) << endl;
    
    	while (!quit) {
    		if (SDL_WaitEvent(&event) && !quit) {
    			switch (event.type) {
    			case SDL_KEYDOWN:
    				switch (event.key.keysym.sym) {
    				case SDLK_ESCAPE:
    					quit = 1;
    					break;
    				default:
    					break;
    				}
    				break;
    			}
    		}
    	}
    	return EXIT_SUCCESS;
    }
    
    Uint32 getcolor(SDL_Surface *surface, int x, int y) {
    	Uint8 r, g, b, a;
    	SDL_LockSurface(surface);
    	SDL_PixelFormat *format = surface->format;
    	Uint32 p = getpixel(surface, x, y);
    
    	SDL_GetRGBA(p, format, &r, &g, &b, &a);
    	SDL_UnlockSurface(surface);
    
    	cout << endl;
    	cout << "Ausgelesene einzelne 8-Bit Kanäle:" << endl;
    	cout << "r: " << dec << (int) r << " g: " << (int) g << " b: " << (int) b
    			<< " alpha: " << (int) a << endl;
    	cout << endl;
    
    	Uint32 result = SDL_MapRGBA(surface->format, r, g, b, a);
    
    	return result;
    }
    
    Uint32 getpixel(SDL_Surface *surface, int x, int y) {
    	int bpp = surface->format->BytesPerPixel;
    	/* Here p is the address to the pixel we want to retrieve */
    	Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;
    
    	switch (bpp) {
    	case 1:
    		return *p;
    		break;
    
    	case 2:
    		return *(Uint16 *) p;
    		break;
    
    	case 3:
    		if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
    			return p[0] << 16 | p[1] << 8 | p[2];
    		else
    			return p[0] | p[1] << 8 | p[2] << 16;
    		break;
    
    	case 4:
    		return *(Uint32 *) p;
    		break;
    
    	default:
    		return 0; /* shouldn't happen, but avoids warnings */
    	}
    }
    


  • In der Beschreibung von SDL_MapRGBA (http://sdl.beuc.net/sdl.wiki/SDL_MapRGBA) habe ich folgendes entdeckt:

    If the specified pixel format has no alpha component the alpha value will be ignored (as it will be in formats with a palette).

    Aber wie könnte das sein? Ich nutze den Alpha-Kanal doch (siehe Zeile 38):

    boxRGBA(screen, 0, 0, 800, 600, 255, 255, 255, ALPHA);
    

    und je nachdem wie ich ALPHA setze (0-255), wird der Fensterinhalt mehr oder weniger Transparent.


Anmelden zum Antworten