Multimediální knihovna Pyglet plně podporuje práci s rastrovými obrázky, které mohou sloužit buď ve funkci spritů (pohybující se objekty ve scéně s volitelnou velikostí, rotací a průhledností) nebo je možné rastrové obrázky použít pro vytvoření textur nanášených na trojrozměrná tělesa. Dnes se s některými základními vlastnostmi rastrových obrázků v Pygletu seznámíme a ukážeme si způsoby jejich použití na devíti demonstračních příkladech.

Obsah

1. Multimediální knihovna Pyglet: práce s rastrovými obrázky a sprity

2. Podporované formáty rastrových obrázků

3. Načtení obrázku z externího souboru

4. První demonstrační příklad: načtení obrázku z externího souboru

5. Vykreslení obrázku operací blit

6. Druhý demonstrační příklad: vykreslení obrázku operací blit

7. Použití spritů v knihovně Pyglet

8. Třetí demonstrační příklad: vytvoření a vykreslení spritu

9. Posun spritů, rotace a změna měřítka

10. Čtvrtý a pátý demonstrační příklad: animace rotace spritu

11. Šestý a sedmý demonstrační příklad: animace změny měřítka spritu

12. Osmý demonstrační příklad: bouncy ball

13. Kombinace vykreslovaní přes OpenGL se sprity

14. Repositář s demonstračními příklady

15. Odkazy na Internetu

1. Multimediální knihovna Pyglet: práce s rastrovými obrázky a sprity

Prakticky každá knihovna určená pro tvorbu multimediálních aplikací nebo her podporuje práci s rastrovými obrázky. Ostatně již v několika předchozích článcích jsme si popisovali „herní“ knihovnu Pygame, která rastrové obrázky taktéž podporuje [1] [2]. I v knihovně Pyglet samozřejmě můžeme s rastrovými obrázky pracovat, a to poměrně komfortním způsobem. Rastrové obrázky zde dokonce mají několik významů, protože bitmapy lze konvertovat na takzvané sprity, popř. mohou obrázky sloužit ve funkci zdrojových dat pro dvoudimenzionální textury, které lze nanášet na 3D tělesa při použití knihovny OpenGL (což je pro mnoho aplikací mnohem důležitější a přitom velmi užitečná vlastnost).

Obrázek 1: Tento rastrový obrázek bude použit v dnešních demonstračních příkladech.

2. Podporované formáty rastrových obrázků

Knihovna Pyglet dokáže na Linuxu pracovat s následujícími formáty rastrových obrázků. Pokud je však navíc nainstalována knihovna PIL (Python Imaging Library), lze použít všechny formáty podporované i touto knihovnou:

Používaná koncovka Jméno formátu
.bmp Windows Bitmap
.dds Microsoft DirectDraw Surface
.gif Graphics Interchange Format
.jpg .jpeg JPEG/JIFF Image
.png Portable Network Graphic
.pnm PBM Portable Any Map Graphic Bitmap
.ras Sun raster graphic
.tif .tiff Tagged Image File Format
.xbm X11 bitmap
.xpm X11 icon

V praxi se nejčastěji setkáme s použitím formátů PNG, GIT a JPEG.

Poznámka: na operačních systémech Microsoft Windows a MacOS je množina podporovaných formátů nepatrně odlišná, ovšem minimálně s podporou BMP, GIF, JPEG a PNG lze počítat. Pokud tedy chcete vytvářet aplikace kompatibilní napříč různými platformami, je nejlepší se skutečně držet právě těchto formátů.

3. Načtení obrázku z externího souboru

Načtení rastrového obrázku probíhá ve dvou krocích. Nejdříve je nutné otevřít soubor obsahující obrázek pro čtení a pro jistotu i v binárním režimu (na Linuxu nemá volba binárního či textového režimu význam, ale na jiných OS ano). Režim čtení binárního souboru je popsán řetězcem „rb“:

image_stream = open("gnome-globe.png", "rb")

Dále je nutné provést načtení obrázku z otevřeného souboru a vytvoření objektu typu AbstractImage (přesněji řečeno některého potomka této třídy):

image = pyglet.image.load('gnome-globe.png', file=image_stream)

U tohoto řádku se na chvíli zastavíme. Proč je vlastně nutné znovu uvádět jméno souboru? Interně se totiž o načítání obrázků může starat několik kodeků (codecs) a je tedy nutné vědět, který kodek se má použít. Každý kodek se automaticky zaregistruje ještě před spuštěním vašich programů a přitom uvede, které formáty (a tím pádem i koncovky souborů) podporuje. A první parametru funkce pyglet.image.load() slouží právě k tomu, aby se rozhodlo, který kodek se má v tomto konkrétním případě použít.

4. První demonstrační příklad: načtení obrázku z externího souboru

První demonstrační příklad je značně jednoduchý, protože si v něm pouze ukážeme, jakým způsobem je možné v knihovně Pyglet načíst rastrový obrázek. Kvůli jednoduchosti se ani nesnažíme o kontrolu, zda se otevření souboru podařilo, zda soubor obsahuje korektní data atd. Korektní práce se soubory je popsána zde. Po načtení obrázku (předpokládejme tedy pro jednoduchost, že se načtení skutečně povedlo) vypíšeme na standardní výstup jeho rozměry:

#!/usr/bin/env python

import pyglet

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

print("Loaded image with size %d x %d pixels" % (image.width, image.height))

Po spuštění tohoto příkladu by se měla vypsat následující informace:

Loaded image with size 96 x 96 pixels

5. Vykreslení obrázku operací blit

Většina historických i velká část soudobých počítačových her s dvoudimenzionální (2D) grafikou je charakteristická tím, že objekty v těchto hrách jsou reprezentovány s využitím rastrových obrázků (bitmap) o různé velikosti, které se postupně vykreslují do vytvářené dvoudimenzionální scény. Aby bylo přes některé části těchto rastrových obrázků viditelné i pozadí, používají se tři metody pro zajištění úplné či částečné průhlednosti. Buď je stanoveno, že určitá hodnota (tj. barva) pixelů má být zcela průhledná (typicky se jedná o jasně fialovou barvu, která se v typických scénách stejně nikde neobjevuje), dále je alternativně možné jeden bit v hodnotě pixelu použít pro určení průhlednosti (typické pro 16bitovou hloubku), nebo se může stanovit průhlednost pixelů doplněním bitmapy o takzvaný alfa kanál (alpha channel).

06

Obrázek 2: Rastrové obrázky (zde zvětšené), které tvoří základ jedné RPG. Vykreslují se funkcí blit/BitBLT.

S využitím grafické operace blit neboli BitBLT (Bit Block Transfer) lze provádět, jak ostatně její název naznačuje, blokové přenosy bitmap nebo jejich výřezů, popř. v rámci přenosu nad bitmapami provádět různé další operace, například zpracování alfa kanálu. První implementace operace BitBLT byla použita v roce 1975 ve Smalltalku-72 a od té doby ji najdeme prakticky v každé implementaci tohoto programovacího jazyka, která obsahuje i knihovny pro práci s grafikou (mj. se jedná i o Squeak). Pro Smalltalk-74 vytvořil Daniel Ingalls optimalizovanou variantu operace BitBLT implementovanou v mikrokódu. Operace BitBLT se tak stala součástí operačního systému a bylo ji možné volat jak z assembleru, tak i z programů napsaných v jazyce BCPL a samozřejmě i ze Smalltalku (právě tuto implementaci můžeme považovat za vůbec první grafickou akceleraci). Posléze se díky své univerzalitě tato funkce rozšířila i do mnoha dalších operačních systémů a grafických knihoven.

07

Obrázek 3: Hra Warcraft II také používá téměř výhradně bitmapy pro zobrazení budov i postaviček.

V případě knihovny Pyglet se operace blit volá ... nepřekvapivě ... metodou blit(), které se předá požadovaná pozice obrázku ve dvourozměrné scéně. Pokud potřebujeme ve scéně vykreslit pouze jeden obrázek na konstantním pozadí, bude celý kód triviální:

def on_draw():
    window.clear()
    image.blit(20, 20)

09

Obrázek 4 Část originálního kódu původní implementace operace BitBLT naprogramované Danielem Ingallsem.

6. Druhý demonstrační příklad: vykreslení obrázku operací blit

V dnešním druhém demonstračním příkladu nejprve načteme rastrový obrázek a posléze ho použijeme pro vykreslení jednoduché scény s textovým návěštím a bitmapou:

#!/usr/bin/env python

import pyglet

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

print("Loaded image with size %d x %d pixels" % (image.width, image.height))

label = pyglet.text.Label("Pyglet library",
                          font_name="Terminus",
                          font_size=36,
                          x=window.width//2,
                          y=window.height//2)

@window.event
def on_draw():
    window.clear()
    label.draw()
    image.blit(20, 20)

pyglet.app.run()

Obrázek 5: Screenshot dnešního druhého demonstračního příkladu.

7. Použití spritů v knihovně Pyglet

Při tvorbě 2D her (ale i v mnoha dalších typech aplikací) se většinou nepracuje s rastrovými obrázky přímo způsobem, který jsme si ukázali v předchozí kapitole, a to mj. i z toho důvodu, že při použití Pygletu máme k dispozici vylepšenou třídu, jejíž instance dokážou kromě vlastního rastrového obrázku držet i další užitečné informace, například zvětšení (měřítko), rotaci a především pak pozici ve vykreslované scéně. Tato třída se jmenuje Sprite (přesněji řečeno pyglet.sprite.Sprite) a její instanci je možné vytvořit přímo z vybraného obrázku konstruktorem pyglet.sprite.Sprite(objekt_typu_image):

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)

Interně vlastně jen dochází k obalení původního obrázku dalšími atributy, takže se nemusíte obávat, že by konverze obrázku do spritu byla časově či paměťově náročná. Ve chvíli, kdy je sprite vytvořen, je možné přistupovat k jeho atributům, mezi něž patří:

Atribut Význam
image obrázek s rastrovými daty spritu
width šířka spritu
height výška spritu
x pozice spritu v rámci celé scény
y pozice spritu v rámci celé scény
position pozice reprezentovaná dvojicí (n-ticí)
rotation rotace spritu (natočení)
scale měřítko spritu (identita, zvětšení, zmenšení)
color barva použitá při míchání (blendingu)
opacity neprůsvitnost použitá při míchání (blendingu)

Některé atributy má smysl i modifikovat, tj. zapisovat do nich. Týká se to především pozice spritu ve scéně a jeho transformací (rotace a změna měřítka).

8. Třetí demonstrační příklad: vytvoření a vykreslení spritu

Ve třetím příkladu se provedou čtyři základní kroky:

  1. Otevře se soubor s obrázkem.
  2. Obrázek se načte do proměnné typu pyglet.image.
  3. Obrázek se převede do spritu, tedy do proměnné typu pyglet.sprite.
  4. Následně se sprite vykreslí metodou sprite.draw()

Úplný zdrojový kód tohoto příkladu vypadá následovně:

#!/usr/bin/env python

import pyglet

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)

@window.event
def on_draw():
    window.clear()
    sprite.draw()

pyglet.app.run()

Obrázek 6: Screenshot dnešního třetího demonstračního příkladu. Sprite je vykreslen do levého spodního rohu okna na souřadnice [0,0].

9. Posun spritů, rotace a změna měřítka

Jak jsme si již řekli v sedmé kapitole, lze u spritů měnit některé atributy, které mají velký vliv na to, jakým způsobem se sprite vykreslí. V první řadě je prakticky nutné měnit pozici spritu ve vytvářené 2D či 3D scéně, což je ostatně patrné i z předchozího screenshotu – pokud totiž pozici nezměníme, vykreslí se sprite v levém spodním rohu okna. Sprite lze ovšem taktéž zvětšovat, zmenšovat či ho zrcadlit (středově) s využitím atributu scale, kterému je možné přiřadit prakticky libovolné reálné číslo. Posledním důležitým atributem je atribut rotation, kterým je možné sprite rotovat okolo svého referenčního bodu (anchor point):

Atribut Význam atributu
x pozice spritu v rámci celé scény
y pozice spritu v rámci celé scény
position pozice reprezentovaná dvojicí (n-ticí)
rotation rotace spritu (natočení ve stupních)
scale měřítko spritu (identita, zvětšení, zmenšení)

10. Čtvrtý a pátý demonstrační příklad: animace rotace spritu

Rotace spritu se provádí jednoduše změnou atributu rotation. Pokud tento atribut budeme kontinuálně měnit v callback funkci update(), bude sprite na obrazovce rotovat okolo svého referenčního bodu. Kontinuální volání funkce update() se v knihovně Pyglet řeší následovně, specifikací použité callback funkce a frekvence volání:

pyglet.clock.schedule_interval(update, 1/60.)

Samotná callback funkce vypadá následovně (parametr dt dnes ještě plně nepoužijeme):

def update(dt):
    sprite.rotation += 1

Následuje výpis zdrojového kódu dnešního čtvrtého demonstračního příkladu:

#!/usr/bin/env python

import pyglet

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)
sprite.x = window.width / 2
sprite.y = window.height / 2

@window.event
def on_draw():
    window.clear()
    sprite.draw()

def update(dt):
    sprite.rotation += 1

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 7: Screenshot dnešního čtvrtého demonstračního příkladu. Červeně je naznačena poloha referenčního bodu spritu.

Povšimněte si, že sprite nerotuje okolo svého středu, ale okolo levého horního rohu, jenž má v rámci lokálního souřadného systému spritu souřadnice [0,0]. Pokud potřebujete provést rotaci spritu okolo jiného bodu, je nutné změnit počátek souřadné soustavy obrázku, z něhož je sprite vytvořen. To lze provést například následujícím způsobem:

image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

Zdrojový kód se změní následovně (pouze se přidají dva výše uvedené příkazy):

#!/usr/bin/env python

import pyglet

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

sprite = pyglet.sprite.Sprite(image)
sprite.x = window.width / 2
sprite.y = window.height / 2

@window.event
def on_draw():
    window.clear()
    sprite.draw()

def update(dt):
    sprite.rotation += 1

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 8: Screenshot dnešního pátého demonstračního příkladu. Červeně je opět naznačena poloha referenčního bodu spritu.

11. Šestý a sedmý demonstrační příklad: animace změny měřítka spritu

Změna měřítka spritu se provede modifikací hodnoty atributu nazvaného scale. Pokud je měřítko nastaveno na hodnotu 1,0, je sprite vykreslen v původní velikosti, v případě větší hodnoty je sprite zvětšen, pro hodnoty mezi 0 a 1 pak zmenšen. Můžete použít i záporné znaménko měřítka, v takovém případě je sprite středově zrcadlen. Podívejme se na jednoduchý příklad, v němž se měřítko spritu postupně mění mezi hodnotami -5,0 až 5,0:

#!/usr/bin/env python

import pyglet
import math

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)
sprite.x = window.width / 2
sprite.y = window.height / 2
sprite.t = 0

@window.event
def on_draw():
    window.clear()
    sprite.draw()

def update(dt):
    sprite.t += 1
    sprite.scale = 5.0 * math.sin(sprite.t/10.)

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 9: Screenshot dnešního šestého demonstračního příkladu.

Opět platí, že pokud potřebujeme, aby se sprite zvětšoval od svého středu a nikoli levého spodního rohu, musíme posunout jeho referenční bod, resp. přesněji řečeno referenční bod obrázku, z něhož je sprite odvozen:

image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

Upravený příklad vypadá takto:

#!/usr/bin/env python

import pyglet
import math

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

image.anchor_x = image.width / 2
image.anchor_y = image.height / 2

sprite = pyglet.sprite.Sprite(image)
sprite.x = window.width / 2
sprite.y = window.height / 2
sprite.t = 0

@window.event
def on_draw():
    window.clear()
    sprite.draw()

def update(dt):
    sprite.t += 1
    sprite.scale = 5.0 * math.sin(sprite.t/10.)

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 10: Screenshot dnešního sedmého demonstračního příkladu.

12. Osmý demonstrační příklad: bouncy ball

V předposledním příkladu si ukážeme, jak je možné postupně měnit souřadnice spritu. Vytvoříme velmi jednoduché demo, v němž se sprite (glóbus) bude odrážet od stěn okna. K tomuto účelu ke spritu přidáme další dva atributy, které budou reprezentovat vektor pohybu:

sprite.dx = 1
sprite.dy = 1

Následně lze řešit odrážení od stěn okna takto:

sprite.x += sprite.dx * dt * 200
sprite.y += sprite.dy * dt * 200
if sprite.x < 0:
    sprite.x = 0
    sprite.dx = -sprite.dx
if sprite.y < 0:
    sprite.y = 0
    sprite.dy = -sprite.dy
if sprite.x + sprite.width > window.width:
    sprite.x = window.width - sprite.width
    sprite.dx = -sprite.dx
if sprite.y + sprite.height > window.height:
    sprite.y = window.height - sprite.height
    sprite.dy = -sprite.dy

Úplný zdrojový kód tohoto příkladu vypadá následovně:

#!/usr/bin/env python

import pyglet

window = pyglet.window.Window(width=640,
                              height=480,
                              caption="Pyglet library")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)
sprite.dx = 1
sprite.dy = 1

@window.event
def on_draw():
    window.clear()
    sprite.draw()

def update(dt):
    sprite.x += sprite.dx * dt * 200
    sprite.y += sprite.dy * dt * 200
    if sprite.x < 0:
        sprite.x = 0
        sprite.dx = -sprite.dx
    if sprite.y < 0:
        sprite.y = 0
        sprite.dy = -sprite.dy
    if sprite.x + sprite.width > window.width:
        sprite.x = window.width - sprite.width
        sprite.dx = -sprite.dx
    if sprite.y + sprite.height > window.height:
        sprite.y = window.height - sprite.height
        sprite.dy = -sprite.dy

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 11: Screenshot dnešního osmého demonstračního příkladu.

13. Kombinace vykreslovaní přes OpenGL se sprity

Vykreslování spritů je možné kombinovat s programovým kódem, který provádí vykreslování OpenGL primitiv. Následující funkci již známe, neboť jsme si ji ukazovali v části o OpenGL. Pouze poslední příkaz byl přidán – jedná se o vykreslení spritu. Sprite se přes scénu pohybuje stejným způsobem, jako v předchozím příkladu. Tím, že je sprite vykreslen jako poslední, překreslí všechna ostatní primitiva. To lze změnit ve chvíli, kdy se použije paměť hloubky, což je téma, které si podrobněji vysvětlíme příště:

@window.event
def on_draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()

    draw_points()

    draw_lines()
    draw_line_strip()
    draw_line_loop()

    draw_triangles()
    draw_triangle_strip()
    draw_triangle_fan()

    draw_quads()
    draw_quad_strip()

    draw_polygon()

    sprite.draw()

Úplný zdrojový kód tohoto příkladu vypadá následovně:

#!/usr/bin/env python

import pyglet
from pyglet.gl import *

window = pyglet.window.Window(width=450,
                              height=350,
                              caption="Pyglet+OpenGL")

image_stream = open("gnome-globe.png", "rb")
image = pyglet.image.load('gnome-globe.png', file=image_stream)

sprite = pyglet.sprite.Sprite(image)
sprite.dx = 1
sprite.dy = 1

def draw_points():
    glColor3f(1.0, 1.0, 1.0)                # nastaveni barvy pro kresleni
    glBegin(GL_POINTS)                      # nyni zacneme vykreslovat body
    glVertex2i( 50,  50)
    glVertex2i(100,  50)
    glVertex2i(100, 100)
    glVertex2i( 50, 100)
    glEnd()

def draw_lines():
    glColor3f(1.0, 0.0, 1.0)
    glBegin(GL_LINES)                       # nyni zacneme vykreslovat usecky
    glVertex2i(150,  50)
    glVertex2i(200,  50)
    glVertex2i(200, 100)
    glVertex2i(150, 100)
    glEnd()

def draw_line_strip():
    glColor3f(0.0, 1.0, 1.0)
    glBegin(GL_LINE_STRIP)                  # nyni vykreslime polycaru
    glVertex2i(250,  50)
    glVertex2i(300,  50)
    glVertex2i(300, 100)
    glVertex2i(250, 100)
    glEnd()

def draw_line_loop():
    glColor3f(1.0, 1.0, 0.0)
    glBegin(GL_LINE_LOOP)                   # nyni vykreslime uzavrenou polycaru
    glVertex2i(350,  50)
    glVertex2i(400,  50)
    glVertex2i(400, 100)
    glVertex2i(350, 100)
    glEnd()

def draw_triangles():
    glColor3f(0.0, 0.0, 1.0)
    glBegin(GL_TRIANGLES)                   # vykresleni trojuhelniku
    glVertex2i( 50, 150)
    glVertex2i(100, 150)
    glVertex2i(100, 200)
    glVertex2i( 50, 200)
    glEnd()

def draw_triangle_strip():
    glColor3f(0.0, 1.0, 0.0)
    glBegin(GL_TRIANGLE_STRIP)              # vykresleni pruhu trojuhelniku
    glVertex2i(150, 150)
    glVertex2i(150, 200)
    glVertex2i(200, 200)
    glVertex2i(200, 150)
    glEnd()

def draw_triangle_fan():
    glColor3f(1.0, 0.0, 0.0)
    glBegin(GL_TRIANGLE_FAN)                # vykresleni trsu trojuhelniku
    glVertex2i(300, 150)
    glVertex2i(250, 160)
    glVertex2i(270, 190)
    glVertex2i(290, 200)
    glVertex2i(310, 200)
    glVertex2i(330, 190)
    glVertex2i(350, 160)
    glEnd()

def draw_quads():
    glColor3f(1.0, 0.5, 0.5)
    glBegin(GL_QUADS)                       # vykresleni ctyruhelniku
    glVertex2i( 50, 250)
    glVertex2i(100, 250)
    glVertex2i(100, 300)
    glVertex2i( 50, 300)
    glEnd()

def draw_quad_strip():
    glColor3f(0.5, 0.5, 1.0)
    glBegin(GL_QUAD_STRIP)                  # vykresleni pruhu ctyruhleniku
    glVertex2i(150, 250)
    glVertex2i(150, 300)
    glVertex2i(200, 240)
    glVertex2i(200, 310)
    glVertex2i(250, 260)
    glVertex2i(250, 290)
    glVertex2i(300, 250)
    glVertex2i(300, 300)
    glEnd()

def draw_polygon():
    glColor3f(0.5, 1.0, 0.5)
    glBegin(GL_POLYGON)                     # vykresleni konvexniho polygonu
    glVertex2i(350, 260)
    glVertex2i(370, 240)
    glVertex2i(390, 240)
    glVertex2i(410, 260)
    glVertex2i(410, 280)
    glVertex2i(390, 300)
    glVertex2i(370, 300)
    glVertex2i(350, 280)
    glEnd()

@window.event
def on_draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()

    draw_points()

    draw_lines()
    draw_line_strip()
    draw_line_loop()

    draw_triangles()
    draw_triangle_strip()
    draw_triangle_fan()

    draw_quads()
    draw_quad_strip()

    draw_polygon()

    sprite.draw()

def update(dt):
    sprite.x += sprite.dx * dt * 200
    sprite.y += sprite.dy * dt * 200
    if sprite.x < 0:
        sprite.x = 0
        sprite.dx = -sprite.dx
    if sprite.y < 0:
        sprite.y = 0
        sprite.dy = -sprite.dy
    if sprite.x + sprite.width > window.width:
        sprite.x = window.width - sprite.width
        sprite.dx = -sprite.dx
    if sprite.y + sprite.height > window.height:
        sprite.y = window.height - sprite.height
        sprite.dy = -sprite.dy

pyglet.clock.schedule_interval(update, 1/60.)
pyglet.app.run()

Obrázek 12: Screenshot dnešního devátého demonstračního příkladu.

14. Repositář s demonstračními příklady

Všechny dnes popsané demonstrační příklady byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář. Pro jejich spuštění je nutné mít nainstalovanou jak knihovnu Pyglet, tak i podpůrné grafické knihovny OpenGL a GLU (což se většinou provede automaticky v rámci instalace balíčku s Pygletem, viz též úvodní díl tohoto seriálu):

Příklad Odkaz
27_pyglet_image_load.py https://github.com/tisnik/presentations/blob/master/pyglet/27_pyglet_image_load.py
28_pyglet_image_blit.py https://github.com/tisnik/presentations/blob/master/pyglet/28_pyglet_image_blit.py
29_sprite.py https://github.com/tisnik/presentations/blob/master/pyglet/29_sprite.py
30_sprite_rotation.py https://github.com/tisnik/presentations/blob/master/pyglet/30_sprite_rotation.py
31_sprite_rotation_origin.py https://github.com/tisnik/presentations/blob/master/pyglet/31_sprite_rotation_origin.py
32_sprite_scale.py https://github.com/tisnik/presentations/blob/master/pyglet/32_sprite_scale.py
33_sprite_scale_origin.py https://github.com/tisnik/presentations/blob/master/pyglet/33_sprite_scale_origin.py
34_sprite_move.py https://github.com/tisnik/presentations/blob/master/pyglet/34_sprite_move.py
35_sprites_and_OpenGL.py https://github.com/tisnik/presentations/blob/master/pyglet/35_sprites_and_OpenGL.py

Poznámka: všechny dnešní demonstrační příklady používají tento obrázek, který by měl být uložen ve stejném adresáři, v němž jsou zdrojové kódy demonstračních příkladů.

15. Odkazy na Internetu

  1. Pyglet Home Page
    https://bitbucket.org/pyglet/pyglet/wiki/Home
  2. Dokumentace k verzi 1.2
    https://pyglet.readthedocs.io/en/pyglet-1.2-maintenance/
  3. Dokumentace k verzi 1.2 ve formátu PDF
    https://readthedocs.org/projects/pyglet/downloads/pdf/pyglet-1.2-maintenance/
  4. PyOpenGL
    http://pyopengl.sourceforge.net/
  5. The #! magic, details about the shebang/hash-bang mechanism on various Unix flavours
    https://www.in-ulm.de/~mascheck/various/shebang/
  6. Shebang (Unix)
    https://en.wikipedia.org/wiki/Shebang_%28Unix%29
  7. Domovská stránka systému LÖVE
    http://love2d.org/
  8. Simple DirectMedia Layer (home page)
    http://www.libsdl.org/
  9. Simple DirectMedia Layer (Wikipedia)
    https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer
  10. Seriál Grafická knihovna OpenGL
    https://www.root.cz/serialy/graficka-knihovna-opengl/
  11. Pyglet event loop
    http://pyglet.readthedocs.io/en/latest/programming_guide/eventloop.html
  12. Decorators I: Introduction to Python Decorators
    http://www.artima.com/weblogs/viewpost.jsp?thread=240808
  13. 3D Programming in Python - Part 1
    https://greendalecs.wordpress.com/2012/04/21/3d-programming-in-python-part-1/
  14. A very basic Pyglet tutorial
    http://www.natan.termitnjak.net/tutorials/pyglet_basic.html
  15. Alpha blending
    https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending