Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

1

10.04.2009, 21:35

SDL putpixel/getpixel und drehung

hallo, ich habe mir für meine SpriteKlasse eine Funktion geschrieben, mit der das Sprite um einen bestimmten Winkel gedreht werden kann. zu diesem Zweck verwende ich auch zwei Funktionen getpixel und putpixel um die entsprechenden Farbinformationen der pixel des ursprungs-surface auf das gedrehte surface zu übertragen. dabei sind mir noch ein paar dinge unklar:

1. bei put- und getpixel musste ich, um den richtigen pixel zu addressieren die Variable lineoffset (=y*pitch/4) mit x/2 addieren. warum muss hier x nochmal durch 2 geteilt werden, ich dachte ein einfaches addieren von x waere ausreichend (die fehlersuche hat mich mind. 10 neue graue haare gekostet :? )?

2. wie kann ich die berechnung der rotation hinsichtlich berechnungsfehler noch optimieren; die rotation funktioniert prinzipiell, faengt sich aber teilweise kleine fehler ein, was sich gerade bei kleinen bitmaps in sehr haesslichen pixelfehlern widerspiegelt.

3. nach der Rotation kann ich der neuen surface keinen ColorKey für die Transparenz zuordnen (Zuordnung geht, aber die Farbe bleibt trotzdem sichtbar). Was muss ich hier noch beachten?

hier noch die wesentlichen code teile:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void CSprite::PutPixel (SDL_Surface *pImageIn,int x, int y,Uint32 pixel)
{
    Uint32 *ptr = (Uint32 *) pImageIn->pixels;
    int lineoffset = y * (pImageIn->pitch) / 4;
    int pixelpos = (lineoffset + x/2) ;
    ptr[pixelpos] = pixel;
}


Uint32 CSprite::GetPixel (SDL_Surface *pImageIn,int x, int y)
{
    Uint32 *ptr = (Uint32 *) pImageIn->pixels;
    int lineoffset = y * (pImageIn->pitch) / 4;
    int pixelpos = lineoffset + x/2 ;
    return ptr[pixelpos];
}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
SDL_Surface *CSprite::Rotate (SDL_Surface *pImageIn,float fWinkel)
{
    SDL_Surface *pImageOut;
    pImageOut=NULL;
    Uint32 pix;
        Uint32 rmask, gmask, bmask, amask;
        #if SDL_BYTEORDER == SDL_BIG_ENDIAN
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
    #else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
    #endif

    if (m_pRotated!=NULL)
    {
        SDL_FreeSurface(m_pRotated);
        pImageIn=m_pImage;
        m_pRotated=NULL;
        pImageOut=NULL;
    }
    
    int x2,y2;
    double h=(pImageIn->h);
    double w=(pImageIn->w);
    double width=(sqrtf((pImageIn->h * pImageIn->h+pImageIn->w * pImageIn->w)));
    double height=width;
    SDL_Surface *temp;
    //cout << height << "\t" << width << endl;

    temp = SDL_CreateRGBSurface(SDL_HWSURFACE,width, height, 32, rmask, gmask, bmask, amask);
    pImageOut=SDL_DisplayFormat(temp);
    SDL_FreeSurface(temp);
    SDL_FillRect(pImageOut,NULL,SDL_MapRGB (m_pScreen->format, 255, 0, 255));
    
    if(pImageOut == NULL) 
    {
        fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        return NULL;
    }

    if ( SDL_MUSTLOCK(pImageIn) ) 
    {
        if ( SDL_LockSurface(pImageIn) < 0 ) 
        {
            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
            return NULL;
        }
    }
    if ( SDL_MUSTLOCK(pImageOut) ) 
    {
        if ( SDL_LockSurface(pImageOut) < 0 ) 
        {
            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
            return NULL;
        }
    }
// Berechnung der neuen Koordinaten für die gedrehte Bitmap und //kopieren der Pixelinformation

    for (int y1=0;y1<h;y1++)
    {
        for (int x1=0;x1<w;x1++)
        {
            x2=static_cast<int> ((x1-(w/2))*cos(fWinkel)-(y1-(h/2))*sin(fWinkel)+(width/2));
            y2=static_cast<int> ((x1-(w/2))*sin(fWinkel)+(y1-(h/2))*cos(fWinkel)+(height/2));
            if (x2>0&&x2<width&&y2>0&&y2<height)
            {
                pix=GetPixel(pImageIn,x1,y1);
            }
            else
            {
                pix=SDL_MapRGB (m_pScreen->format, 0, 0, 0);    
            }
            PutPixel(pImageOut,x2,y2,pix);
        }
    }
    if ( SDL_MUSTLOCK(pImageOut) ) {
       SDL_UnlockSurface(pImageOut);
    }
    if ( SDL_MUSTLOCK(pImageIn) ) {
        SDL_UnlockSurface(pImageIn);
    }
    SDL_SetColorKey (pImageOut, SDL_SRCCOLORKEY, 
                   SDL_MapRGB (pImageOut->format, 255, 0, 255) );
    return pImageOut;
}

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

2

11.04.2009, 21:03

Frage 1.) hat sich grade erledigt; der screen war faelschlicherweise auf 16bit festgelegt...

bleiben noch 2.) und 3.) ... hier keinen einen tip für mich? :(

gruss
physX

Gotbread

Alter Hase

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

3

11.04.2009, 21:29

ich würde zumindestens im dehungscode mit double-werten arbeiten.

außerdem ware das programm um einiges schneller, wenn du die sinus
und kosinuswerte einmal zu beginn berechnest statt immer in der schleife.

desweiteren wäre es besser, einen zeiger auf die pixeldaten zu bekommen
statt die pixel einzeln abzuholen.
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

4

11.04.2009, 21:49

Danke für die Tips...

Zitat von »"Gotbread"«

ich würde zumindestens im dehungscode mit double-werten arbeiten.

das hatte ich mir bereits überlegt und bei mir schon geändert.

Zitat


außerdem ware das programm um einiges schneller, wenn du die sinus
und kosinuswerte einmal zu beginn berechnest statt immer in der schleife.

da hatte ich nicht dran gedacht; ist ein guter Tip; werd ich gleich ändern;

Zitat


desweiteren wäre es besser, einen zeiger auf die pixeldaten zu bekommen
statt die pixel einzeln abzuholen.

meinst du hier, dass ich erst die koordinaten berechnen soll und erst danach die pixel zuordnen? dann muss ich doch aber 2mal 2 Schleifen bauen, was dann vermultlich mehr zeit kostet. oder hab ich dich hier jetzt falsch verstanden?

Danke für die Hilfe

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

5

13.04.2009, 16:52

das problem mit der Transparenz der definierten Farbe hab ich jetzt folgendermaßen gelöst. Problem ist nur, dass es bei mir als etwa 10 objekten, die pro Frame sowohl gedreht als auch eine transparente Farbe zugewiesen bekommen, anfängt merklich zu ruckeln... Könnt ihr mir da noch etwas helfen, wie ich das etwas performance freundlicher gestalten kann? (die funktionen put-und getpixel sind wie bereits im ersten post angegeben; rotation wurde nochmal leicht modifiziert)

Bestimmung der transparenten Farbe; damit lassen sich auch sehr schön Abstufungen der Transparenz erstellen bzw. auch andere Farben zusätzlich ausblenden;

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void CSprite::SetTransparency(SDL_Surface *surface,Uint8 R,Uint8 G,Uint8 B)
{
    Uint8 r,g,b,a;
    SDL_LockSurface(surface);
    Uint32 *ptr = (Uint32 *) surface->pixels;
    int iMax=(surface->w*surface->h);
    for (int i=0; i<iMax;i++)
    {
        SDL_GetRGBA(ptr[i],surface->format,&r,&g,&b,&a);
        if (r==R&&g==G&&b==B) a=0;
        else a=255;
        ptr[i]=SDL_MapRGBA(surface->format,r,g,b,a);
    }
    SDL_UnlockSurface(surface);
}
void CSprite::SetTransparency(SDL_Surface *surface,Uint32 color)
{
    SDL_LockSurface(surface);
    Uint32 *ptr=(Uint32 *) surface->pixels;
    int iMax=surface->w*surface->h;
    for (int i=0; i<iMax;i++)
    {
        ptr[i]=ptr[i] | (0xFF000000);
        if (ptr[i]==(color)) ptr[i]=color & (0x00FFFFFF);
    }
    SDL_UnlockSurface(surface);
}


Code zur Drehung des surface

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
SDL_Surface *CSprite::Rotate (SDL_Surface *pImageIn,double dAngle)
{
    SDL_Surface *pImageOut;
    pImageOut=NULL;
    Uint32 pix;
    Uint32 rmask, gmask, bmask, amask;

    /* SDL interprets each pixel as a 32-bit number, so our masks must depend
       on the endianness (byte order) of the machine */

    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
    #else
        rmask = 0x000000ff;
        gmask = 0x0000ff00;
        bmask = 0x00ff0000;
        amask = 0xff000000;
    #endif

    if (m_pRotated!=NULL)
    {
        SDL_FreeSurface(m_pRotated);
        pImageIn=m_pImage;
        m_pRotated=NULL;
        pImageOut=NULL;
    }
    
    int x2,y2;

    double dHIn=pImageIn->h;
    double dWIn=pImageIn->w;
    double dWOut=sqrtf(dHIn*dHIn+dWIn*dWIn);
    double dHOut=dWOut;
    // calculate cos and sin ex for-loop to preserve some time 

    double dCosAngle=cos(dAngle);
    double dSinAngle=sin(dAngle);

    SDL_Surface *temp;
    temp = SDL_CreateRGBSurface(SDL_HWSURFACE,static_cast<int>(dWOut), static_cast<int>(dHOut), 32, rmask, gmask, bmask, amask);
    pImageOut=SDL_DisplayFormatAlpha(temp);
    SDL_FreeSurface(temp);
    SDL_FillRect(pImageOut,NULL,SDL_MapRGB (m_pScreen->format, 255, 0, 255));
    if(pImageOut == NULL) 
    {
        fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
        return NULL;
    }
    if ( SDL_MUSTLOCK(pImageIn) ) 
    {
        if ( SDL_LockSurface(pImageIn) < 0 ) 
        {
            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
            return NULL;
        }
    }
    if ( SDL_MUSTLOCK(pImageOut) ) 
    {
        if ( SDL_LockSurface(pImageOut) < 0 ) 
        {
            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
            return NULL;
        }
    }
// loop for rotation-transformation and color picking

    for (double y1=0;y1<dHIn;y1++)
    {
        for (double x1=0;x1<dWIn;x1++)
        {
            x2=static_cast<int> ((x1-dWIn/2)*dCosAngle-(y1-dHIn/2)*dSinAngle + dHOut/2);
            y2=static_cast<int> ((x1-dWIn/2)*dSinAngle+(y1-dHIn/2)*dCosAngle + dWOut/2);
            if (x2>=0&&x2<=dWOut&&y2>=0&&y2<=dHOut)
            {
                pix=GetPixel(pImageIn,x1,y1);
            }
            else
            {
                pix=SDL_MapRGB (m_pScreen->format, 0, 0, 0);    
            }
            PutPixel(pImageOut,x2,y2,pix);
        }
    }
    if ( SDL_MUSTLOCK(pImageOut) ) {
       SDL_UnlockSurface(pImageOut);
    }
    if ( SDL_MUSTLOCK(pImageIn) ) {
        SDL_UnlockSurface(pImageIn);
    }
    SetTransparency(pImageOut,0xFFFF00FF);
    return pImageOut;
}
[/cpp]

Werbeanzeige