UrΦit∞ se vßm nelφbφ mφt vÜechny textury ulo₧enΘ v BMP souborech, kterΘ nejsou zrovna p°ßtelskΘ k mφstu na disku. Bohu₧el SDL ₧ßdn² jin² formßt p°φmo nepodporuje. NicmΘn∞ existuje malΘ rozÜφ°enφ v podob∞ knihovniΦky SDL Image poskytujφcφ funkci IMG_Load(), kterß umφ naΦφst v∞tÜinu pou₧φvan²ch grafick²ch formßt∙.
Pokud tuto knihovnu nemßte, m∙₧ete si ji stßhnout ze znßmΘ adresy http://www.libsdl.org/. ZaΦneme vlo₧enφm hlaviΦkov²ch soubor∙. Nezapome≥te krom∞ OpenGL a SDL p°ilinkovat i SDL_image.
#include <SDL.h>// Hlavnφ SDL knihovna
#include <SDL_opengl.h>// Vlo₧φ za nßs OpenGL
#include <SDL_image.h>// Abychom mohli pou₧φvat funkci IMG_Load()
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Daklarujeme prom∞nnou OpenGL textury.
GLuint gl_texture;// Textura
NapφÜeme funkci, kterß naΦte SDL\_Surface. Obrßzek musφme souΦasn∞ upravit, aby byl ve slo₧kßch RGB a nebyl vzh∙ru nohama.
SDL_Surface* LoadBitmap(const char *filename)// Funkce pro naΦteni bitmapy
{
Uint8 *rowhi, *rowlo;// Ukazatele na prohazovßni °ßdk∙
Uint8 *tmpbuf, tmpch;// DoΦasnß pam∞¥
int i, j;// ╪φdφcφ prom∞nnΘ pro cykly
SDL_Surface *image;// NaΦφtan² obrßzek
image = IMG_Load(filename);// NaΦtenφ dat obrßzku
if (image == NULL)// OÜet°enφ chyby p°i naΦφtßnφ
{
fprintf(stderr, "Nepodarilo se nacist %s: %s\n", filename, SDL_GetError());
return(NULL);
}
GL surfaces jsou vzh∙ru nohama, tak₧e budeme muset bitmapu p°evrßtit. Alokujeme dynamickou pam∞¥, do kterΘ odlo₧φme prßv∞ p°emis¥ovan² kousek. Jejφ velikost se neurΦφ podle image->w, ale podle image->pitch, proto₧e u SDL\_Surface se m∙₧e stßt, ₧e kv∙li zarovnßvßnφ v pam∞ti SDL zabere vφce mφsta, ne₧ je skuteΦn² rozm∞r obrßzku.
Image->pitch udßvß Üφ°ku zabranΘ pam∞ti, ale image->w udßvß Üφ°ku obrßzku.
tmpbuf = (Uint8 *)malloc(image->pitch);// Alokace pam∞ti
if (tmpbuf == NULL)// OÜet°enφ chyby
{
fprintf(stderr, "Nedostatek pameti\n");
return NULL;
}
// Nastavenφ prvnφho a poslednφho °ßdku
rowhi = (Uint8 *)image->pixels;
rowlo = rowhi + (image->h * image->pitch) - image->pitch;
for (i = 0; i < image->h/2; i++)
{
// P°evrßcenφ BGR na RGB
if (image->format->Bshift == 0)
{
for (j = 0; j < image->w; j++)
{
tmpch = rowhi[j*3];
rowhi[j*3] = rowhi[j*3+2];
rowhi[j*3+2] = tmpch;
tmpch = rowlo[j*3];
rowlo[j*3] = rowlo[j*3+2];
rowlo[j*3+2] = tmpch;
}
}
// Prohozenφ °ßdk∙
memcpy(tmpbuf, rowhi, image->pitch);
memcpy(rowhi, rowlo, image->pitch);
memcpy(rowlo, tmpbuf, image->pitch);
// Posun ukazatel∙ na °ßdky
rowhi += image->pitch;
rowlo -= image->pitch;
}
Zb²vß u₧ jen smazat doΦasn² odklßdacφ prostor a vrßtit naΦtenou bitmapu.
free(tmpbuf);// ┌klid
return image;// Vrßtφ naΦten² obrßzek
}
Te∩, kdy₧ mßme naΦten² obrßzek, vytvo°φme funkci, kterß z n∞j vytvo°φ OpenGL texturu. Hned na zaΦßtku se pokusφme naΦφst obrßzek prßv∞ napsanou funkcφ LoadBitmap(). Pokud tato oprace sel₧e, vrßtφme nulu.
GLuint CreateTexture(const char* file, int min_filter, int mag_filter, bool mipmaps)// Vytvo°φ texturu
{
SDL_Surface *surface;// Obrßzek
surface = LoadBitmap(file);// NaΦtenφ obrßzku
if (surface == NULL)// OÜet°enφ chyby
return 0;
Vytvo°φme mφsto pro novou texturu a nastavφme filtry podle parametr∙ funkce.
GLuint texture;// OpenGL textura
glGenTextures(1, &texture);// Generovßnφ jednΘ textury
glBindTexture(GL_TEXTURE_2D, texture);// Nastavenφ textury
// Nastavenφ po₧adovan²ch filtr∙
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
Vybereme podle p°ßnφ, jestli se majφ pou₧φvat mipmapy nebo ne.
if (mipmaps)// Mipmapovanß textura
{
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
}
else// ObyΦejnß textura
{
glTexImage2D(GL_TEXTURE_2D, 0, 3, surface->w, surface->h, 0, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
}
Nakonec vÜe uklidφme. Pro mazßnφ SDL\_Surface pou₧φvejte zßsadn∞ SDL\_FreeSurface() a nikdy delete nebo free. Data bitmapy m∙₧eme takΘ smazat, proto₧e nejsou pot°eba. OpenGL si je nakopφrovalo a my u₧ se o n∞ nemusφme starat.
SDL_FreeSurface(surface);// Smazßnφ SDL_Surface
surface = NULL;// Nastavenφ ukazatele na NULL
return texture;// Vrßtφ texturu
}
Funkce, kterß vykresluje OpenGL scΘnu. Obdoba DrawGLScene() z NeHe OpenGL Tutorißl∙.
void RenderScene()// Vykreslφ scΘnu
{
static float rott = 0.0f;// Statickß prom∞nnß pro ·hel rotace
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
glLoadIdentity();// Reset matice
glBindTexture(GL_TEXTURE_2D, gl_texture);// Zvolφ texturu
glTranslatef(0.0f, 0.0f, -6.0f);// P°esun do obrazovky
glRotatef(rott,-1.0, 0.0, 0.0);// NatoΦenφ scΘny
glRotatef(rott, 0.0, 1.0, 0.0);
glRotatef(rott, 0.0, 0.0,-1.0);
glBegin(GL_POLYGON);// Vykreslφ obdΘlnφk
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 0.0f,-1.0);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 0.0f, 1.0);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 0.0f, 1.0);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 0.0f,-1.0);
glEnd();
rott += 0.1;// Zv∞tÜφ rotaci
SDL_GL_SwapBuffers();// Prohozenφ buffer∙
}
Incializace SDL.
void InitSDL()// Inicializace SDL
{
// Inicializace SDL grafiky a SDL Timeru
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
fprintf(stderr, "Nepodarilo se inicializovat SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);// Nastavenφ funkce p°i volßnφ exit();
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);// Chceme doublebuffering s OpenGL
// Nastavenφ velikosti a stylu okna
unsigned int flags = SDL_OPENGL;// | SDL_FULLSCREEN; // P°φpadn∞ bitov∞ orovat s fullscreen
if (SDL_SetVideoMode(640, 480, 0, flags) == NULL)// Vytvo°φ okno
{
fprintf(stderr, "Nepodarilo se vytvorit OpenGL okno : %s\n", SDL_GetError());
SDL_Quit();
exit(2);
}
SDL_WM_SetCaption("Lesson - SDL_image", NULL);// Nastavenφ titulku okna
}
Incializace OpenGL.
void InitOpenGL()// Nastavenφ zßkladnφch parametr∙ OpenGL
{
glViewport(0, 0, 640, 480);
glEnable(GL_TEXTURE_2D);// Povolenφ textur
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);// ╚ernΘ pozadφ
glClearDepth(1.0);// Povolenφ mazßnφ hloubkovΘho bufferu
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);// Povolenφ testovßnφ hloubky
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHT0);// Povolenφ sv∞tel
glEnable(GL_COLOR_MATERIAL);// Povolenφ vybarvovßnφ materißl∙
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)640 / (GLfloat)480, 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
// NaΦtenφ textury
if ((gl_texture = CreateTexture("test.jpg", GL_LINEAR, GL_LINEAR, false)) == 0)
{
fprintf(stderr, "Nepodarilo se vytvorit texturu\n");
exit(1);
}
}
P°i zavφrßnφ programu volßme ShutDownApp(), kterß sma₧e texturu a ukonΦφ SDL.
void ShutDownApp()// Deinicializace
{
glDeleteTextures(1, &gl_texture);// Vymazßnφ textury
SDL_Quit();// UkonΦenφ SDL
}
NapφÜeme funkci, zpracovßvajφcφ zprßvy, kterΘ programu posφlß systΘm. Reagujeme na ukonΦenφ aplikace (SDL_QUIT), stisk klßvesy (SDL_KEYDOWN) Esc (SDLK_ESCAPE) a p°ekreslenφ okna SDL_VIDEOEXPOSE. Ostatnφ udßlosti nßs nezajφmajφ.
bool ProcessEvents()// Obsluha udßlostφ
{
SDL_Event event;// Prom∞nnß zprßvy
while (SDL_PollEvent(&event))// Dokud p°ichßzejφ zprßvy, zpracovßvat je
{
switch (event.type)// Jakß p°iÜla zprßva?
{
case SDL_QUIT:// U₧ivatel si p°eje ukonΦit aplikaci
return false;
break;
case SDL_KEYDOWN:// Stisknutß klßvesa
switch (event.key.keysym.sym)// Jakß klßvesa?
{
case SDLK_ESCAPE:// Esc
return false;
break;
}
break;
case SDL_VIDEOEXPOSE:// Pot°eba p°ekreslit okno
RenderScene();// Vykreslφ scΘnu
break;
}
}
return true;
}
Main() je prvnφ funkcφ, kterß se volß po spuÜt∞nφ programu. Po jejφm ukonΦenφ se ukonΦφ i program. Na zaΦßtku inicializujeme SDL a OpenGL. V hlavnφ smyΦce programu zpracovßvßme zprßvy a pokud ₧ßdnΘ nep°ijdou, p°ekreslφme scΘnu. Po p°φchodu zprßzy o ukonΦenφ nebo pokud u₧ivatel stiskl klßvesu Esc, uvolnφme zdroje, kterΘ program zabral a ukonΦφme aplikaci.
int main(int argc, char ** argv)// Hlavnφ funkce
{
InitSDL(); // Inicializace SDL
InitOpenGL();// Inicializace OpenGL
while (ProcessEvents())// Hlavnφ smyΦka programu
{
RenderScene();// Pokud nep°iÜla zprßva p°ekreslφ scΘnu
}
ShutDownApp();// Deinicializace
return 0;// Konec main() a programu
}
Tak to je asi vÜechno. V archivu zdrojovΘho k≤du najdete pouze CPP soubor s JPG obrßzkem, tak₧e musφte program jeÜt∞ p°elo₧it. Pro kompilaci v Linuxu napiÜte:
gcc `sdl-config --libs --cflags` -lSDL_image -L/usr/X11R6/lib -lGL -lGLU lessonSDL_image.cpp
Pracujete-li v jinΘm operaΦnφm systΘmu, nezapome≥te krom∞ OpenGL a SDL p°ilinkovat i knihovnu SDL_image.
napsal: Bernard Lidick² - Berny