Witam!
Tworzę w C++ klon pewnej starej gry znanej z 8-bitowców pt. "Boulder Dash". Jest to prosta gra 2D, w której ludzik chodzi po planszy (dwuwymiarowej tablicy) i musi zebrać określoną liczbę diamentów. Poszczególne pola tejże planszy odzwierciedlane są na ekranie poprzez sprite'y - właściwie w moim przypadku tekstury.
Oryginalna gra miała ubogą grafikę - wykorzystywanych było w sumie sześć czy siedem kolorów - ale dla urozmaicenia dla każdej planszy kolory te były zmieniane. Pisząc mój program chciałem się trzymać tej zasady. Zdefiniowałem zestaw takich obrazków, które ładuję w programie do tablicy o nazwie
sprites i wyświetlam na ekranie w najprostszy znany mi sposób przy użyciu funkcji (pisząc w skrócie)
glBegin(GL_QUADS) poprzedzonej przez
glBindTexture.
Po lekturze dostępnych w necie materiałów wymyśliłem też sposób na zmianę tych kolorów.
Mam strukturę, którą nazwałem
rgb oraz tablicę dla wartości siedmiu kolorów, które są zmienne. Mówiąc inaczej - wartości RGB dla siedmiu kolorów, które zapisuję w tablicy
wzorkol są wartościami, które chciałbym, aby przyjęły moje tekstury dla danej planszy gry.
struct rgb {
unsigned char r;
unsigned char g;
unsigned char b;
};
rgb wzorkol[ 7 ];
Samą zmianę kolorów realizują mi dwie funkcje:
UpdateTextures oraz
SetKolor. Pierwsza z nich iteracyjnie leci przez całą tablicę tekstur i dla każdej kolejnej tekstury sprawdza teksel po tekselu czy jego wartości RGB odpowiadają tym, które znajdują się we wzorcu
wzorkol. Jeśli tak, to wywoływana jest funkcja
SetKolor, która zmienia wartości RGB dla każdego konkretnego teksela. Kanał alpha jest tutaj nieużywany.
void cl_BDImage::setKolor( GLuint ID, GLint x, GLint y, uint8_t r, uint8_t g, uint8_t b, uint8_t a ) {
uint8_t data[ 3 ];
data[ 0 ] = r;
data[ 1 ] = g;
data[ 2 ] = b;
glBindTexture( GL_TEXTURE_2D, ID );
glTexSubImage2D( GL_TEXTURE_2D,
0,
x,
y,
1,
1,
GL_RGB,
GL_UNSIGNED_BYTE,
data );
}
void cl_BDImage::UpdateTextures( int wzorkol_id, unsigned char new_r, unsigned char new_g, unsigned char new_b ) {
for( int i = 1; i < max_img; i++ ) {
unsigned char * pData = NULL;
GLint uW, uH, uC, uF;
glBindTexture( GL_TEXTURE_2D, sprites[ i ] );
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, & uW );
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, & uH );
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS, & uC );
glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, & uF );
pData = new unsigned char[ uW * uH * uC ];
glGetTexImage( GL_TEXTURE_2D, 0, uF, GL_UNSIGNED_BYTE, pData );
for( int y = 0; y < uH; y++ ) {
for( int x = 0; x < uW; x++ ) {
rgb teksel;
int wektor = y * uW * 4 + x * 4;
teksel.r = pData[ wektor ];
teksel.g = pData[ wektor + 1 ];
teksel.b = pData[ wektor + 2 ];
if( teksel.r == wzorkol[ wzorkol_id ].r && teksel.g == wzorkol[ wzorkol_id ].g && teksel.b == wzorkol[ wzorkol_id ].b ) {
setKolor( sprites[ i ], x, y, new_r, new_g, new_b, 255 );
}
}
}
delete[] pData;
}
return;
}
No i to, co jest powyżej działa poprawnie. Pożądany efekt osiągnąłem, ale jest to (jak mawiał mój nauczyciel) tzw. metoda radziecka - nieekonomiczna i wolna. Tym wolniejsza im więcej jest tekstur i czym są one większych rozmiarów.
Chciałbym to przyspieszyć i z tym problemem zwracam się do Was. Może ktoś będzie w stanie mi coś podsunąć - ja napisałem to najlepiej jak umiałem, ale podejrzewam, że można znacznie lepiej podejść do tematu. Będę wdzięczny za wskazówki - dopiero zaczynam swoją przygodę z programowaniem w SDL/OGL i liczę na wyrozumiałość. Jeśli coś, z tego co napisałem powyżej jest niejasne też proszę o sygnał - uzupełnię o wszystkie potrzebne informacje.
pozdrawiam,
Piotrek