Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C: SDL: kuvan viistotus

Metabolix [30.04.2007 13:21:45]

#

Koska joku aiheesta keskustelussa kysyi enkä jaksanut selvittää, onko jossakin SDL:n lisäkirjastossa valmiiksi tällaista, päätin tehdä oman version. Funktio siis viistottaa kuvaa vaakasuunnassa eli siten, että korkeus säilyy samana. Vastaava funktio olisi jokseenkin yhtä helppo tehdä myös pystysuunnassa. Reunanpehmennyksen lisääminen vaatisi hieman ylimääräistä aritmetiikkaa, mutta sekään ei olisi suuri lisäys.

Funktion parametriksi annetaan alkuperäinen kuva ja vasemman alakulman uusi x-koordinaatti. Oletusarvoisesti siis vasemman yläkulman katsotaan pysyvän paikallaan. Funktion palauttama pinta tulee lopuksi vapauttaa (kuten kaikki muutkin SDL-pinnat näyttöpintaa lukuun ottamatta).

Funktio itse

#include <SDL.h>

SDL_Surface *MySDL_Viistota(SDL_Surface *k, int vas_ala_x)
{
	SDL_Surface *ret;
	char *pix;
	int leveys, i;

	// Tarkistuksia
	if (!k || (SDL_MUSTLOCK(k) && !SDL_LockSurface(k))) {
		return 0;
	}

	// Luodaan uusi pinta ; leveys pitää laskea (lisätään siirron itseisarvo)
	leveys = k->w + ((vas_ala_x < 0) ? -vas_ala_x : vas_ala_x);
	ret = SDL_CreateRGBSurface(k->flags, leveys, k->h, k->format->BitsPerPixel, k->format->Rmask, k->format->Gmask, k->format->Bmask, k->format->Amask);

	// Onnistuiko, vai pitääkö lopettaa?
	if (!ret || (SDL_MUSTLOCK(ret) && !SDL_LockSurface(ret))) {
		if (ret) {
			SDL_FreeSurface(ret);
		}
		if (SDL_MUSTLOCK(k)) {
			SDL_UnlockSurface(k);
		}
		return 0;
	}

	// Jos siirtymä olisi nolla, kopioidaan suoraan
	if (vas_ala_x == 0) {
		memcpy(ret->pixels, k->pixels, (k->h - 1) * k->pitch + (k->w * k->format->BytesPerPixel));
		goto lopetus_ja_palautus;
	}

	if (vas_ala_x < 0) {
		// Negatiivisella siirretään piirtokohtaa hieman, ettei mene ulkopuolelle
		pix = (char*)ret->pixels - (vas_ala_x * ret->format->BytesPerPixel);
	} else {
		// Oikea siirtokohta kelpaa positiivisilla
		pix = ret->pixels;
	}

	// Rivi kerrallaan
	for (i = 0; i < k->h; ++i) {
		memcpy(
		/* kohde-Y = i */  pix + (i * ret->pitch)
		/* kohde-X ... */  + (((i * vas_ala_x) + (vas_ala_x / 2)) / (ret->h - 1)) * ret->format->BytesPerPixel,
		/* lähde = 0,i */  (char*)k->pixels + (i * k->pitch),
		/* Rivin koko  */  k->format->BytesPerPixel * k->w);
	}

lopetus_ja_palautus:
	if (SDL_MUSTLOCK(ret)) {
		SDL_UnlockSurface(ret);
	}
	if (SDL_MUSTLOCK(k)) {
		SDL_UnlockSurface(k);
	}
	return ret;
}

Käyttöesimerkki

// Alustus
SDL_Surface *ruutu = SDL_SetVideoMode(...);
SDL_Surface *kuva = SDL_LoadBMP("kuva.bmp");
SDL_Surface *viistokuva;

// Kivan viistotuksen laskenta (ajan mukaan)
// viistous = [-4000, 3999]
int viistous = (SDL_GetTicks() % 8000) - 4000;

// viistous = [0, 4000]
if (viistous < 0) {
	viistous = -viistous;
}
// viistous = [-kuva->w, kuva->w]
viistous = (viistous * (2 * kuva->w) / 4000) - kuva->w;

// Viistotus, piirto ja vapautus
viistokuva = MySDL_Viistota(kuva, viistous);
SDL_BlitSurface(viistokuva, 0, ruutu, 0);
SDL_FreeSurface(viistokuva);

// Loppuvapautus
SDL_FreeSurface(kuva);

Vastaus

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

Tietoa sivustosta