Volání funkcí
Většinu funkcí obsažených v PyOpenGL můžete volat podobně jako v C a můžeme očekávat také podobný výstup. Samozřejmě zde existují rozdíly, které jsou dány rozdíly mezi jazyky C a Python. Jedním z těchto rozdílů je pojetí přístupu k polím. V C například použijeme tento funkční prototyp:
void foo(int count, const int *args);
A v pythonu zase toto volání:
foo(args) -> None
Jak je vidět, v C se předává velikost pole. Důvod spočívá v samotné implementaci polí v jazyce, kdy jsou pole předávána odkazem (čili je předávána pouze jejich adresa) a záleží jen na programátorovi, jak si sám obhospodaří rozsah pole.
Naproti tomu v Pythonu není potřeba předávat funkci velikost pole, protože objekt pole si tuto informaci uchovává. Hodnotu lze z objektu získat metodou pole.__len__() nebo jednodušeji vestavěnou funkcí len(pole).
Výjimky
Chyby v programu jsou předávány pro Python zcela přirozeným způsobem – výjimkami. Funkce glGetError není z důvodů použití výjimek potřebná (nevracela by nic jiného než GL_NO_ERROR). Při konverzi z kódu používajícího tuto funkci musíte zaměnit volání glGetError za řádné zachytávání výjimky. Výjimky:
- GL.GLerror
- ve všech modulech.
- GLU.GLUerror
- vyvolávána několika funkcemi v GLU. Funkce v modulu GLU však i nadále používají GL.GLerror.
Předávání parametrů funkcí
Funkcí nastavujících ukazatele na pole existuje mnoho variant (lišících se typem pole). Pro zjednodušení práce programátora byly zavedeny různé zápisy stejné funkce lišící se koncovkami: glXPointer{ub|b|us|s|ui|i|f|d}. Díky tomuto zápisu funkce přijímá pouze jeden argument (vícerozměrné pole). Koncovky představují typ a velikost jedné buňky pole – ub-unsigned byte, b-byte, us-unsigned short,s-short, ui-unsigned int, i-int, f-float, d-double. Typy lze předat také jako parametr funkce, která však neobsahuje koncovku. Můžete si tedy vybrat to, co vám více vyhovuje.
glColorPointer(size, type, stride, pointer) -> None glColorPointerub(pointer[][]) -> None glColorPointerb(pointer[][]) -> None glColorPointerus(pointer[][]) -> None glColorPointers(pointer[][]) -> None glColorPointerui(pointer[][]) -> None glColorPointeri(pointer[][]) -> None glColorPointerf(pointer[][]) -> None glColorPointerd(pointer[][]) -> None
Samozřejmě, že se nemusí jednat pouze o vícerozměrná pole:
glDrawElements(mode, count, type, indices) -> None glDrawElementsub(mode, indices[]) -> None glDrawElementsus(mode, indices[]) -> None glDrawElementsui(mode, indices[]) -> None
Stejné schéma lze použít i u funkcí kreslících či pracujících s texturami. Např. funkce glDrawPixels přijímá řetězec obsahující data-pixely: glDrawPixels(width, height, format, type, pixels) → None. Tato funkce respektuje parametry nastavené funkcí glPixelStore{i|f}.
Místo dvojice těchto funkcí můžete použít jednu (v různých obměnách), která přejímá jako parametr vícerozměrné pole a nastaví glPixelStore{i|f} automaticky. glDrawPixelsub(format, pixels[][][]) → None – nyní už nemusíme předávat width a height, protože jsou dány rozměry pole a nemusíme předávat typ – ten je GLubyte.
Buffery
Pro použití selektivního bufferu můžete v OpenGL zapsat:
GLuint buffer[SIZE]; glSelectBuffer(SIZE, buffer); glRenderMode(GL_SELECT); /* něco nakreslí */ GLint count = glRenderMode(GL_RENDER); /* analyzuje selekční buffer */
V Pythonu bude však kód vypadat jinak:
glSelectBuffer(SIZE) # alokuje selekční buffer o SIZE elementech glRenderMode(GL_SELECT) # něco nakreslí buffer = glRenderMode(GL_RENDER) for hit_record in buffer: min_depth, max_depth, names = hit_record # pracuje se záznamem
Co se týče feedback bufferů, používá se stejný princip, přičemž každý prvek bufferu je n-tice (token, value).
Rozšíření OpenGL
Knihovna obsahuje podporu pro mnoho rozšíření základních modulů GL, GLU a WGL. Tato rozšíření mohou být implementována jako podmoduly jednotlivých balíčků. Např. rozšíření GL_ARB_multitexture může být uloženo jako GL.ARB.multitexture. Nezáleží na tom, zda je příslušné rozšíření implementováno jako uživatelská knihovna, nebo ne, vždy musí příslušný modul v balíčkovém stromě existovat. Modul bude také existovat, pokud nebude definovat nové tokeny nebo funkce. Pokud není ono rozšíření podporováno aktuálním kontextem, bude vyvolána výjimka GLerror s kódem GL_INVALID_OPERATION.
Každá implementace OpenGL má vlastní metodu pro linkování rozšiřujících knihoven. Může se jednat o dynamické linkování, statické linkování nebo o jakousi dynamicko-statickou kombinaci. Bez ohledu na tuto implementaci je nutné před použítím rozšíření zjistit, zda je podporováno aktuálním kontextem. Můžete to většinou provést voláním funkce glGetString(GL_EXTENSIONS) a hledáním jména rozšíření ve vráceném řetězci.
Rožšíření jsou potenciálně závislá na kontextu, což znamená, že rozšíření podporované jedním kontextem nemusí být funkční v jiném. To znamená, že pro každý kontext musíte kontrolovat funkcionalitu rozšíření. Pro každé rozšíření musíte tedy provést tyto tři kroky:
- ověření, že je rozšíření podporováno aktuálním kontextem
- načtení všech adres procedur, které mají být použity
- vrácení úspěchu či neúspěchu předcházejících kroků
Funkce v následujícím příkladě přejímá jako parametr jméno rozšíření a vrací jméno inicializační funkce. Je použito pojmenovávací schéma OpenGL.
def init_name(extension_name): parts = string.split(extension_name, '_') return string.join([string.lower(parts[0]), 'Init'] + map(string.capitalize, parts[2:]) + [parts[1]], '') >>> init_name('GL_ARB_multitexture') 'glInitMultitextureARB' >>> init_name('GLU_SGI_filter4_parameters') 'gluInitFilter4ParametersSGI'
Jako další příklad je zde program používající knihovnu GLUT, který ke svému běhu potřebuje rozšíření GL_ARB_multitexture:
from OpenGL.GLUT import * from OpenGL.GL.ARB.multitexture import * import sys # inicializuje GLUT argv = glutInit(sys.argv) # vytvoří okno, je potřeba před glInitMultitextureARB glutCreateWindow('foo') # zjistí, zda je GL_ARB_multitexture podporováno if not glInitMultitextureARB(): # chyba - není podpora print "Help, I'm lost without GL_ARB_multitexture!" sys.exit(1) # pracuje s GL_ARB_multitexture