Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: SDL-ongelma: piirto samalle pinnalle useasti

Tumpelo [11.03.2008 18:30:20]

#

Olen nyt kaksi päivää taistellut ongelman kanssa. Koodailen tilepohjaista peliä SDL:llä ja C++:lla. Minulla on kaksiulotteinen taulukko, jossa sijaitsee tieto tileistä. Kahdessa for-loopissa piirrän taulukon tiedon mukaisesti BaseMapSurfacelle koko kartan. Lopuksi siirrän BaseMapSurfacen screen-surfacelle oikeaan kohtaan. Ongelma on se, että BaseMapSurfacelle piirto onnistuu vain kerran, heti seuraavalla yrityksellä ohjelma jäätyy. Eli jos piirrän kartan ennen pelilooppia, se toimii, mutta jos loopin sisällä, piirtyy kartta kerran näytölle ja sitten ohjelma jäätyy. En kerta kaikkiaan ole keksinyt mistä tämä johtuisi...

Tässä piirtofunktio:

void DrawImage(SDL_Surface *image, SDL_Surface *target, int x, int y) {

    SDL_Rect area;
    area.x = x;
    area.y = y;
    SDL_BlitSurface(image, NULL, target, &area);
}

Tässä itse pelistä:

int MapWidth = 40;
int MapHeight = 40;
int BaseMap[100][100] = {0};

SDL_Surface *BaseMapSurface = NULL;
BaseMapSurface = SDL_CreateRGBSurface(SDL_HWSURFACE, MapWidth * 50, MapHeight * 50, 32, 0, 0, 0, 255);

while (!Exit) {

// Update basemap
for (int y = 0; y < MapHeight; y++) {

	for (int x = 0; x < MapWidth; x++) {

                if (BaseMap[y][x] == 0) DrawImage(Sea_Tile, BaseMapSurface, x * 50, y * 50);
	        else if (BaseMap[y][x] == 1) DrawImage(Open_Tile, BaseMapSurface, x * 50, y * 50);
	}
}

// Piirretään kartta
DrawImage(BaseMapSurface, screen, -Navigation.GetOffsetX() * 50, -Navigation.GetOffsetY() * 50);

// Päivitetään näyttö
SDL_Flip(screen);
}

Riisuin koodista kaiken epäolennaisen pois, tuossa pitäisi olla kaikki piirtoon vaikuttavat tekijät.

Metabolix [11.03.2008 20:50:06]

#

En näe mitään varsinaista syytä sille, että tieto pinnalta katoaisi. Oletko kokeillut SDL_SWSURFACEa? Jos SDL käyttää DDraw'ta, on mahdollista, että tietyissä tilanteissa data katoaa pinnalta ja se täytyy täyttää uudestaan. Sinänsä pinnan kyllä pitäisi säilyä, ellet tee sille mitään erityistä.

Mitä tarkoitat ohjelman jäätymisellä? Jumittuminen johtuu luultavasti jostain muusta. Oletko debug-tulosteilla tai debuggerilla tarkistanut, että ongelma on juuri piirtovaiheessa?

Tumpelo [11.03.2008 21:01:23]

#

Se että tieto joka loopissa piirretään uudestaan, johtuu ihan muista syistä - karsitusta koodista se ei käy ilmi, mutta tuo on karttaeditorista, jossa siis täytyy päivittää grafiikat koska muutenhan käyttäjän tekemät muutokset eivät näkyisi. Olen myös tarkistanut hyvin tarkkaan, että nimenomaan BaseMapSurfacelle piirto aiheuttaa ohjelman jäätymisen. Jos vaihdan sen tilalle screenin, ohjelma toimii. Ja jäätymisellä tarkoitan että ohjelma ja käyttöjärjestelmä menee aivan jumiin, hiiren osoitin tosin liikkuu mutta Linuxissa tuohon auttaa vain ctrl + alt + backspace.

Metabolix [11.03.2008 23:01:53]

#

Aivan, tulkitsin ja luin viestiäsi tälläkin kertaa väärin. Yritän ensi kerralla kovemmin. :)

En osaa ilman debuggeria kuin keksiä arvauksia, koska pintojen sinänsä pitäisi kyllä säilyä aivan hyvin.

Mitkä tekijät vaikuttavat asiaan? Voiko piirtosilmukkaa pyörittää monta kertaa omassa silmukassaan ennen ruudulle piirtämistä? Toimiiko ohjelma, jos jätät piirtämättä apupinnan ruudulle? Voitko piirtää silmukassa sekä apupintaan että ruudulle? Entä jos piirrätkin ruudulle pelkkää tyhjää apupintaa?

Vilkaisu SDL:n lähdekoodiin kertoo, että sen X11-rajapinta ei tue HW-pintoja, paitsi jossakin tilanteessa näyttöpintaa. Tämän ei tietenkään pitäisi vaikuttaa asioihin, koska pinnasta tulee automaattisesti SW-pinta, mutta kuitenkin koodissa näyttää olevan myös sellainen aukko, että luontifunktio ei varsinaisesti tarkista, onko HW-pinnan luominen mahdollista, vaan yrittää ja epäonnistuu. Asetukset kuitenkin tehdään HW-pinnan optimoinnin kannalta, joten esimerkiksi värien maskit näyttivät minulla asettuvan näyttöpinnan mukaisesti BGR-järjestykseen ilman alfakanavaa, vaikka muuta pyysinkin.

(SDL:n kehittäjät tekisivät viisaasti, kun kirjoittaisivat kirjastonsa järjen kanssa uudestaan. -.- Monin paikoin koodi on käsittämätöntä purukumia, tekee aivan käsittämättömiä oletuksia ja esimerkiksi juuri yllä kuvatun kaltaisia virheitä tilanteissa, joissa se ei voi tarjota täsmälleen sitä, mitä käyttäjä haluaa. Voisi edes valita lähimmän vaihtoehdon eli tuossa tapauksessa pyydetyillä ominaisuuksilla varustetun SW-pinnan.)

Tumpelo [12.03.2008 16:50:08]

#

Noniin, päivitystä. Kokeilin muuttaa kaikki pinnat SWSurfaceksi, mutta tällä ei ollut vaikutusta. Sitten poistin koodista tuon kohdan joka piirtää BaseMapSurfacen näytölle, ei vaikutusta. Kokeilin myös asettaa BaseMapSurface = NULL, jolloin ohjelma ei kaadu mutta ei myöskään piirrä mitään. Hmmh..

Metabolix [12.03.2008 19:04:59]

#

Eipä tule enempää mieleen kuin että jossain kohti tehdään pinnalle jotain tyhmää (vapautetaan tai muutetaan vahingossa osoitinta). Seuraava veto olisi kääntää ohjelma debuggausta varten (ilman optimointia ja debug-lipulla -g), laittaa breakpoint ennen piirtosilmukkaa ja vertailla pinnan osoitetta ja sisältöä aluksi ja ennen kaatumista. Jos gdb ei ole tuttu, niin tässä pieni esimerkki:

# gdb ./ohjelma
(gdb) break main.cpp:123
Breakpoint 1 at 0x8058264: file main.cpp, line 123.

(gdb) run
...
Breakpoint 1 at main.cpp:123
123             for (int y = 0; ...)

(gdb) print pinta
$1 = (SDL_Surface *) 0x8072b68

(gdb) print *pinta
$2 = {flags = 4096, format = 0x8072ba8, w = 32, h = 32, pitch = 96,
  pixels = 0x80668f8, offset = 0, hwdata = 0x0, clip_rect = {x = 0, y = 0,
    w = 32, h = 32}, unused1 = 0, locked = 0, map = 0x8072bd8,
  format_version = 4, refcount = 1}

(gdb) print *pinta->format
$3 = {palette = 0x0, BitsPerPixel = 24 '\030', BytesPerPixel = 3 '\003',
  Rloss = 0 '\0', Gloss = 0 '\0', Bloss = 0 '\0', Aloss = 8 '\b',
  Rshift = 16 '\020', Gshift = 8 '\b', Bshift = 0 '\0', Ashift = 0 '\0',
  Rmask = 16711680, Gmask = 65280, Bmask = 255, Amask = 0,
  colorkey = 16711935, alpha = 255 '&#65533;'}

(gdb) continue
...

Vastaus

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

Tietoa sivustosta