SDL2 Kleiner Fehler in Drehroutine (sin() & cos()) für BMP



  • Hallo zusammen 🙂 ,

    ich übersetze gerade den Code eines Tutorials nach SDL2, es geht um eine kleine Routine um eine Bitmap mit sin() und cos() selbst zu drehen. Bisher hat alles gut geklappt aber kurz vor dem Ende bekomme ich ein Problem.
    Das Beispiel Sin, cos and bitmaps: rotate_sprite Circ9.c funktioniert nicht richtig. Die Bitmap wird zwar gedreht aber leider völlig falsch. Es handelt sich wahrscheinlich nur um einen kleinen Fehler aber ich finde ihn einfch nicht 😕 .

    Ich habe zwei kleine Header SDL_CRAP und PIXEL_CRAP geschrieben um in dem Hauptcode überichtlicher zu gestalten und den Fokus nur auf das Beispiel aus dem Tutorial zu legen.

    Der Fehler liegt garantiert in der Drehroutine in der main(), die anderen Teile habe ich getestet und bekam keine Fehler!!!

    Ich nutze VisualStudio 2015 CE und Windows 10.

    Wäre klasse wenn Ihr mir helfen könntet.

    Vielen Dank für Eure Mühe und Hilfe vorab,
    Spliffer

    Tutorial:

    http://www.helixsoft.nl/articles/circle/sincos.htm

    Testimage (muss ins .bmp-Format konvertiert werden):

    https://picload.org/view/rciroidw/test.png.html

    Hauptcode:

    #include<windows.h>
    #include "SDL_CRAP.h"
    #include "PIXEL_CRAP.h"
    
    int main(int argc, char* argv[])
    {
    	SDL_Crap sdlCrap;
    	PIXEL_Crap pixelCrap;
    
    	sdlCrap.init();
    	sdlCrap.loadMedia();
    
    	// Ziel_Surface erstellen
    	int width = 256;
    	int height = 128;
    	SDL_Surface* DestImageSurface;
    	DestImageSurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
    	if (DestImageSurface == NULL) 
    	{
    		SDL_Log("SDL_CreateRGBSurfaceWithFormat() failed: %s", SDL_GetError());
    		exit(1);
    	}
    
    	//	Um direkten Zugriff auf die Pixel zu haben d.h. um diese bearbeiten zu können
    	//	muss die betreffende Oberfläche abgeschlossen werden (SDL_MUSTLOCK)
    
    	if (SDL_MUSTLOCK(sdlCrap.SrcImageSurface) == true)	// Test ob Oberfläche geschlossen/ geöffnet werden muss
    	{
    		SDL_LockSurface(sdlCrap.SrcImageSurface);	// Oberfläche schließen
    		SDL_LockSurface(DestImageSurface);	// Oberfläche schließen
    	}
    
    	int src_x, src_y;// current position in the source bitmap
    	int dest_x, dest_y;// current position in the destination bitmap
    
    	// src_x and src_y will change each time by dx and dy
    	int dx, dy;
    
    	// src_x and src_y will be initialized to start_x and start_y
    	// at the beginning of each new line
    	int start_x = 0, start_y = 0;
    
    	// We create a bit mask to make sure x and y are in bounds.
    	// Unexpected things will happen
    	// if the width or height are not powers of 2.
    	int x_mask = sdlCrap.SrcImageSurface->w - 1;
    	int y_mask = sdlCrap.SrcImageSurface->h - 1;
    
    	// calculate increments for the coordinates in the source bitmap
    	// for when we move right one pixel on the destination bitmap
    	dx = (cos(1)* 5);
    	dy = (sin(1)* 5);
    
    	for (dest_y = 0; dest_y < DestImageSurface->h; dest_y++)
    	{
    		// set the position in the source bitmap to the
    		// beginning of this line
    		src_x = start_x;
    		src_y = start_y;
    
    		for (dest_x = 0; dest_x < DestImageSurface->w; dest_x++)
    		{
    			// Copy a pixel.
    			// This can be optimized a lot by using
    			// direct bitmap access.
    			pixelCrap.putpixel(DestImageSurface, dest_x, dest_y, pixelCrap.getpixel(sdlCrap.SrcImageSurface, (src_x) & x_mask,
    				(src_y) & y_mask));
    
    			// advance the position in the source bitmap
    			src_x += dx;
    			src_y += dy;
    		}
    
    		// for the next line we have a different starting position
    		start_x -= dy;
    		start_y += dx;
    	}
    
    	if (SDL_MUSTLOCK(sdlCrap.SrcImageSurface) == true)	// Test ob Oberfläche geschlossen/ geöffnet werden muss
    	{
    		SDL_UnlockSurface(sdlCrap.SrcImageSurface);	// Oberfläche öffnen
    	}
    
    	SDL_BlitSurface(DestImageSurface, NULL, sdlCrap.ScreenSurface, NULL);	//	Image auf SrcImageSurface blitten
    	SDL_UpdateWindowSurface(sdlCrap.BasicWindow);	//	Basisfenster  erneuern (updaten)
    	//sdlCrap.SrcImageSurface
    
    	SDL_Delay(10000);		//	10.000 Millisekunden warten
    	sdlCrap.close();			//	aufräumen
    
    	return 0;
    }
    

    SDL_CRAP:

    #pragma once
    
    #include "cstdio"
    #include "../packages/sdl2.2.0.5/build/native/include/SDL.h"
    
    class SDL_Crap
    {
    private:
    
    	// Success Flags
    	bool initSuccess = true;
    	bool mediaSuccess = true; 
    
    public:
    
    	SDL_Crap() = default;
    	~SDL_Crap() = default;
    
    	int SCREEN_X = 800;
    	int SCREEN_Y = 600;
    
    	SDL_Window* BasicWindow = nullptr;	//	Fenster auf dem wir die Grafik wiedergeben wollen
    	SDL_Surface* ScreenSurface = nullptr;	//	Oberfläche die im Basisfenster enthalten ist
    	SDL_Surface* SrcImageSurface = nullptr;	//	Oberfläche für das Image das geladen werden soll
    
    	bool init();
    	bool loadMedia();
    	void close();
    };
    
    inline bool SDL_Crap::init()
    {
    	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    	{
    		printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
    		initSuccess = false;
    	}
    	else
    	{
    		//	Create window
    		BasicWindow = SDL_CreateWindow("SDL_2 Image On Screen!!!!",
    		                               SDL_WINDOWPOS_CENTERED,
    		                               SDL_WINDOWPOS_CENTERED,
    		                               SCREEN_X,
    		                               SCREEN_Y,
    		                               SDL_WINDOW_SHOWN);
    		if (BasicWindow == nullptr)
    		{
    			printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
    			initSuccess = false;
    		}
    		else
    		{
    			ScreenSurface = SDL_GetWindowSurface(BasicWindow);
    		}
    	}
    	return initSuccess;
    }
    
    inline bool SDL_Crap::loadMedia()
    {
    	 //	Load splash image
    	SrcImageSurface = SDL_LoadBMP("Test.bmp");
    	if (SrcImageSurface == nullptr)
    	{
    		printf("Unable to load image %s! SDL Error: %s\n", "girl.bmp", SDL_GetError());
    		mediaSuccess = false;
    	}
    	return mediaSuccess;
    }
    
    inline void SDL_Crap::close()
    {
    	SDL_FreeSurface(SrcImageSurface); //	Deallocate surface
    	SrcImageSurface = nullptr;
    
    	SDL_DestroyWindow(BasicWindow); //	Destroy window
    	BasicWindow = nullptr;
    
    	SDL_Quit(); //	Quit SDL subsystems
    }
    

    PIXEL_CRAP:

    #pragma once
    
    #include "SDL_CRAP.h"
    
    class PIXEL_Crap
    {
    private:
    
    public:
    	PIXEL_Crap() = default;
    	~PIXEL_Crap() = default;
    
    //	Return the pixel value at (x, y)
    //	NOTE: The surface must be locked before calling this!
    
    	Uint32 getpixel(SDL_Surface *surface, int x, int y);
    
    	/*
    	* Set the pixel at (x, y) to the given value
    	* NOTE: The surface must be locked before calling this!
    	*/
    	void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
    
    };
    
    inline Uint32 PIXEL_Crap::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;
    
    	case 2:
    		return *(Uint16 *)p;
    
    	case 3:
    		{
    			if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
    				return p[0] << 16 | p[1] << 8 | p[2];
    			return p[0] | p[1] << 8 | p[2] << 16;
    		}
    
    	case 4:
    		return *(Uint32 *)p;
    
    	default:
    		return 0; /* shouldn't happen, but avoids warnings */
    	} // switch
    }
    
    inline void PIXEL_Crap::putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
    {
    	int bpp = surface->format->BytesPerPixel;
    	/* Here p is the address to the pixel we want to set */
    	Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
    
    	switch (bpp) {
    	case 1:
    		*p = pixel;
    		break;
    
    	case 2:
    		*(Uint16 *)p = pixel;
    		break;
    
    	case 3:
    		if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
    			p[0] = (pixel >> 16) & 0xff;
    			p[1] = (pixel >> 8) & 0xff;
    			p[2] = pixel & 0xff;
    		}
    		else {
    			p[0] = pixel & 0xff;
    			p[1] = (pixel >> 8) & 0xff;
    			p[2] = (pixel >> 16) & 0xff;
    		}
    		break;
    
    	case 4:
    		*(Uint32 *)p = pixel;
    		break;
    
    	default:
    		break;           /* shouldn't happen, but avoids warnings */
    	} // switch
    
    }
    

  • Mod

    Spliffer schrieb:

    Das Beispiel Sin, cos and bitmaps: rotate_sprite Circ9.c funktioniert nicht richtig. Die Bitmap wird zwar gedreht aber leider völlig falsch. Es handelt sich wahrscheinlich nur um einen kleinen Fehler aber ich finde ihn einfch nicht 😕 .

    wenn du den fehler beschreiben wuerdest, haettest du bessere chancen hilfe zu erhalten 😉 (ich hab z.b. nichtmal sdl2 installiert und nur zum compilieren deines quellcodes nicht so recht lust das zu tun).

    grob eine checkliste:
    -sin cos sind in radian, fuetterst du die richtig?
    -benutzt du die richtigen formate fuer variablen?



  • Hallo rapso,

    ja ich denke schon daß ich sin() & cos() richtig füttere und die Variablen müssten auch die richtigen Formate haben sonst würde überhaupr nichts klappen.

    Fehlerbeschreibung:

    Die Farben des Images sind nicht an der richtigen Stelle und das Image wird auch völlig verkehrt gezeichnet. Es sieht irgendwie eher gespiegelt als gedreht aus.

    ich hab z.b. nichtmal sdl2 installiert und nur zum compilieren deines quellcodes nicht so recht lust das zu tun

    Klar das verstehe ich! Ich suche mich schon dusslig nach einem SDL2 Forum da man dort wahrscheinlich den Code compilieren würde. Für OpenGL und DX gibt es sowas füe SDL anscheinend nicht. Es ist sehr schwer in Detail zu erklären was nicht funktioniert!

    Vielen Dank für Eure Mühe und Hilfe,
    Spliffer



  • Alles klar jetzt klappts 🙂 !!!!

    Grüße,
    Spliffer


Log in to reply