SDL Image

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

ZdrojovΘ k≤dy