Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: SDL-piirtopulma

Burton [29.09.2010 18:48:41]

#

Hei kaikille.

Mistä johtuu, ettei alla oleva koodi toimi? Tarkoituksena on kopioida bmp-kuva Uint32-muuttujiin muistiin ja piirtää se niiden avulla ruudulle.

/* getpixel- ja putpixel-rutiinit on lainattu pekin "tuli -efekti"-koodivinkistä */
void _fastcall putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    // p on osoitin pikseliin, jonka haluamme asettaa
    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;
    }
}

Uint32 _fastcall getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    // p on osoitin pikseliin, jonka haluamme kopioida
    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];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       // ei pitäisi tapahtua.
    }
}

/* Tämä funktio poimii pikselien väriarvot (?) kuvasta */
void haePikselit(SDL_Surface *kuva, Uint32 *varit) {
  int x, y;
  for (y = 0; y < kuva->h; y++) {
    for (x = 0; x < kuva->w; x++) {
      varit[kuva->w * y + x] = getpixel(kuva, x, y);
    }
  }
}

void piirraKuva(void) {
  SDL_Surface *kuva = SDL_LoadBMP("kuva.bmp");
  Uint32 *varit;
  int x, y;

  if ((varit = (Uint32 *)malloc(kuva->w * kuva->h)) == NULL)
    exit(1);

  haePikselit(kuva, varit);

  for (y = 0; y < kuva->h; y++) {
    for (x = 0; x < kuva->w; x++) {
      /* ruutu on globaali muuttuja, johon on alustettu SDL_SetVideoMode SWSURFACE-lipulla */
      putpixel(ruutu, x + 100, y + 100, varit[kuva->w * y + x]);
    }
  }

  SDL_Flip(ruutu);
  SDL_Delay(2000);
}

Ohjelma vilahtaa nopeasti ja sulkeutuu tuottamatta haluttua tulosta. Jäljitin vian haePikselit-funktioon, jossa varit-taulukkoa täytetään getpixel-arvoilla. Kirjoitin rivin printf("%3i, %3i\n", x, y); ennen getpixeliä ja stdout.txt paljastaa, että ohjelma kaatuu kohdassa 97, 77. Kuva on mitoiltaan 278x284.

Jännä juttu kuitenkin on se, että ohjelma toimii, jos Uint32-tyypin vaihtaa muotoon Uint8, mutta ei kuitenkaan täydellisesti, sillä kuva tulostuu sävyiltään sinisenä. Tämä taitaa johtua Uint8:n rajoista?

Metabolix [29.09.2010 18:56:00]

#

Varaat muistia w*h tavua, kun sitä pitäisi varata w*h*sizeof(Uint32) tavua eli nelinkertainen määrä. Et tarkista myöskään ikkunan kokoa, joten saatat vahingossa kirjoittaa senkin muistialueen yli. Lisäksi olet unohtanut vapauttaa varaamasi muistin free-funktiolla.

Burton [29.09.2010 19:00:57]

#

Ups, tosiaan. Olen kuitenkin omassa koodissani vapauttanut muistin free-funktiolla. Unohdin vain kopioida sen tähän.

Kiitos avusta.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta