Aloitin lukemaan NEHE:n OpenGL-tutoriaaleja, jotka oli käännetty SDL-muotoon (alkuperäiset käyttävät WinApia) ja sain kursittua parista tutoriaalista kasaan yksinkertaisen pyörivän tekstuurineliön.
Käytin ohjelmassani 256*256-kokoista bittikarttakuvaa tutoriaalin mallin mukaan. Muutin kuvan kokoa pienemmäksi ja tuloksena oli valkoinen neliö pyörimässä keskellä ruutua. Ongelmanani on tämä koko. Tekisi mieli muuttaa kuva paljon pienemmäksi, mutten tiedä miten! Koodissa ei tunnu olevan elementtejä, jotka vaikuttaisivat tähän.
Tässä käyttämäni koodi. Muokattu suoraan NEHE:n tutoriaaleista ja osa kommenteista suomennettu:
/* uusi opengl-rotoa käyttävä sp-moottori. */ #include <SDL/SDL.h> #include <GL/gl.h> #include <GL/glu.h> /* varataan paikka yhdelle tekstuurille. */ GLuint tekstuuri[1]; SDL_Surface *LoadBMP(char *nimi) { Uint8 *a,*b,*c; Uint8 d; int i,j; SDL_Surface *k; k=SDL_LoadBMP(nimi); /* ogl-pinnat on ylösalaisia ja rgb-värisiä (ei bgr). */ c=(Uint8 *)malloc(k->pitch); a=(Uint8 *)k->pixels; b=a+(k->h*k->pitch)-k->pitch; for (i=0;i<k->h/2;++i) { for (j=0;j<k->w;++j) { d=a[j*3]; a[j*3]=a[j*3+2]; a[j*3+2]=d; d=b[j*3]; b[j*3]=b[j*3+2]; b[j*3+2]=d; } memcpy(c,a,k->pitch); memcpy(a,b,k->pitch); memcpy(b,c,k->pitch); a=a+k->pitch; b=b-k->pitch; } free(c); return(k); } /* funktio ogl-tekstuurien lataamiseen. * (lataa bittikartan ja muuntaa sen tekstuuriksi) **/ void ogl_tekstuurit(void) { SDL_Surface *k1; k1=LoadBMP("kuva.bmp"); glGenTextures(1,&tekstuuri[0]); glBindTexture(GL_TEXTURE_2D,tekstuuri[0]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); /* 2d-tekstuuri, tarkkuus, komponentit (rgb), x-koko, y-koko, reunus, * rgb-väridata, unsigned byte -data, ja itse data. **/ glTexImage2D(GL_TEXTURE_2D,0,3,k1->w,k1->h,0,GL_RGB, GL_UNSIGNED_BYTE,k1->pixels); } /* funktio opengl:n valmisteluun. * (olettaa resoluution olevan 800*600) **/ void starttaa_ogl(void) { glViewport(0,0,800,600); /* ladataan tekstuurit */ ogl_tekstuurit(); glEnable(GL_TEXTURE_2D); glClearColor(0.0f,0.0f,0.0f,0.0f); glClearDepth(1.0); glDepthFunc(GL_LESS); glShadeModel(GL_SMOOTH); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)800/(GLfloat)600,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); } /* hoidetaan hommat, beibi */ void piirto(float kulma) { glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-5.0f); glRotatef(kulma,0.0f,0.0f,1.0f); /* piirretään tämmönen : * --- * | | * | | * ---, mut neliö. **/ glBindTexture(GL_TEXTURE_2D,tekstuuri[0]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); SDL_GL_SwapBuffers(); } int main(int argc,char *argv[]) { float kulma; Uint32 hidaste; SDL_Init(SDL_INIT_VIDEO); SDL_Event ta; SDL_SetVideoMode(800,600,0,SDL_OPENGL); SDL_WM_SetCaption("opengl-rotoz",NULL); starttaa_ogl(); kulma=0; while (1) { piirto(kulma); if (kulma>358) kulma=0; else kulma=kulma+1; SDL_PollEvent(&ta); if (ta.type==SDL_QUIT) break; else if (ta.type==SDL_KEYDOWN) if (ta.key.keysym.sym==SDLK_ESCAPE) break; hidaste=SDL_GetTicks()+20; while (SDL_GetTicks()<hidaste); } SDL_Quit(); return 0; }
Sori tästä kooditulvasta. Kaikki apu on tarpeen ja kokeilkaa olla ymmärtäväisiä ja kärsivällisiä minun OpenGL-taitojeni kanssa. :)
No haukutaanpa ensin muistivuodosta: et vapauta pintaa, paha juttu. Sinun olisi ehdottomasti syytä vapauttaa se SDL_FreeSurface-funktiolla, kun olet saanut tekstuurisi luotua. Sitten haukutaan epäselvästä koodista. Miksi ihmeessä noin?
Itse virheestä, niin kristallipallo valehtelee sellaista, että kuvasi sivu ei ole kakkosen kokonaispotenssi. OpenGL:n speksi käskee niin, ja sitä kannattaa siis myös noudattaa.
Annetaan sitten vaikkapa parempi vaihtoehto, joka ehkä toimiikin, jos hyvin sattuu. Tämä siis korvaa glTexImage2D-funktion, kuten sisällöstä voi päätellä:
void SDL_glTexImage2D(SDL_Surface *kuva) { const Uint32 #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000, gmask = 0x00ff0000, bmask = 0x0000ff00, amask = 0x000000ff; #else rmask = 0x000000ff, gmask = 0x0000ff00, bmask = 0x00ff0000, amask = 0xff000000; #endif Uint32 w, h; for (w = 1; w < kuva->w; w <<= 1); // Lähin kakkosen potenssi for (h = 1; h < kuva->h; h <<= 1); SDL_Surface *apu; apu = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, rmask, gmask, bmask, amask); SDL_BlitSurface(kuva, 0, apu, 0); // Stretch olisi tietysti kiva, mutta mitä turhia, käytä valmiiksi sopivaa kuvaa. glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, apu->pixels); SDL_FreeSurface(apu); }
SDL_Surface *kuva = SDL_LoadBMP("kuva.bmp"); SDL_glTexImage2D(kuva); SDL_FreeSurface(kuva);
Wou Wou, ei tarvii sentään kaikesta haukkua! :)
Tuota muistivuotoa en huomannut ollenkaan. Parsin nämä aikalailla yhteen niistä tutoriaaleista. Ehkä en huomannut jotain kohtaa ja jäi tyhjennykset väliin.
Toiseksi haukut epäselvästä koodista. Mitäs epäselvää tuossa on? Kyllähän mä olen saanut ennenkin tyhjentävää kommenttia yksimerkkisistä muuttujanimistä ja siitä, että mä kirjoitan kaiken yhteen ( for (i=0;i<2;i=i+1); ), mutta en mä mun koodeja pahemmin näyttele julkisesti. Poikkeuksia lukuunottamatta.
Mutta pakkohan mun on kiittää sua tosta koodista, joka toimii aivan täydellisesti. Nyt pystyy käyttämään pienempiä kuvia, joiden sivut säädän kakkosen kokonaispotenssien mukaisesti. En tiennyt tuotakaan. :)
Toinen kysymys tähän perään:
Kun tuo tekstuuripulma tuli hoideltua, niin onko keinoa, jolla saisi kuvan pyörimään keskikohtansa ympärillä? Tuo kulman ympäri pyöriminen on ärsyttävää.
Heitän tämän kysymyksen teille samalla, kun itse kokeilen pohtia tätä. Villejä ehdotuksia otetaan vastaan.
Siirrot ja pyöritykset vaikuttavat matriisiin, jolla jokainen antamasi piste kerrotaan. Siis kun käännät kuvaa glRotatella, matriisi muuttuu siten, että jokainen piste kääntyy sen verran. glTranslate taas siirtää pistettä tietyn verran. Järjestyksellä on merkitystä, sen voit kokeilemallakin todeta.
Sinun täytyy siis siirtää neliösi niin, että sen keskikohta on origossa (tai z-akselilla), pyörittää sitä ja siirtää se takaisin. Kokeilepa, mikä on näille oikea järjestys.
Edit. Ai anteeksi, sehän oli jo. No mutta silloin vika on itsessäsi, kyllä sen nimittäin pitäisi keskikohdan ympäri pyöriä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.