Created
February 16, 2010 22:11
-
-
Save vanne02135/305997 to your computer and use it in GitHub Desktop.
Playing around with Pyglet and it's OpenGL interface to show some photos. Requires Pyglet and PIL. Displays some public photos from my flickr photostream.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__author__="vanne" | |
__date__ ="$16.2.2010 22:02:26$" | |
from pyglet.gl import * | |
import pyglet | |
from pyglet.window import * | |
from pyglet import image | |
import os | |
from math import sin | |
import math | |
import Image | |
import tempfile | |
import glob | |
import threading | |
import sys | |
window = pyglet.window.Window(width=640, height=480, resizable=True) | |
class Photo: | |
thumbnailSize = 512 | |
def __init__(self, filename): | |
self.filename = filename | |
self.thumbnailtex = "" | |
self.thumbOk = False | |
self.createThumbnailTex() | |
self.location = [0, 0, 0] | |
self.dims = [5, 5] | |
def createThumbnailTex(self): | |
thread = threading.Thread(target=self.resize) | |
thread.start() | |
def draw(self): | |
if self.thumbOk: | |
glBindTexture(GL_TEXTURE_2D, self.thumbnailtex.id) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) | |
glEnable(GL_TEXTURE_2D) | |
else: | |
try: | |
self.thumbnailtex = self.im.get_texture() | |
self.thumbOk = True | |
except: # self.im not loaded apparently | |
glDisable(GL_TEXTURE_2D) | |
glColor3f(0.2, 0.2, 0.2) | |
try: | |
w = self.width; h = self.height | |
if w > h: | |
ww = 1.0 | |
hh = h/float(w) | |
else: | |
ww = w/float(h) | |
hh = 1.0 | |
except AttributeError: | |
# image not yet loaded | |
ww = 1.0 | |
hh = 1.0 | |
bl = (self.location[0] - self.dims[0]*0.5*ww, self.location[1] - self.dims[1]*0.5*hh, self.location[2]) | |
br = (self.location[0] + self.dims[0]*0.5*ww, self.location[1] - self.dims[1]*0.5*hh, self.location[2]) | |
tr = (self.location[0] + self.dims[0]*0.5*ww, self.location[1] + self.dims[1]*0.5*hh, self.location[2]) | |
tl = (self.location[0] - self.dims[0]*0.5*ww, self.location[1] + self.dims[1]*0.5*hh, self.location[2]) | |
## remember: with blending the drawing sequence DOES matter. Draw the farthest first | |
glEnable(GL_BLEND) | |
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR) | |
glBegin(GL_QUADS) | |
glTexCoord2f(0.0, 0.0); glVertex3f(bl[0], bl[1], bl[2]) # bottom left | |
glTexCoord2f(ww*1.0, 0.0); glVertex3f(br[0], br[1], br[2]) #bottom right | |
glTexCoord2f(ww*1.0, hh*1.0); glVertex3f(tr[0], tr[1], tr[2]) #top right | |
glTexCoord2f(0.0, hh*1.0); glVertex3f(tl[0], tl[1], tl[2]) #top left | |
glEnd() | |
#glDisable(GL_BLEND) | |
if True: | |
# draw picture frame | |
glColor3f(1.0, 1.0, 1.0) | |
epsilon = 1e-2 | |
framewidth = .05; | |
glBegin(GL_QUADS) | |
glVertex3f(bl[0]-framewidth, bl[1]-framewidth, bl[2]-epsilon) # bottom left | |
glVertex3f(br[0]+framewidth, br[1]-framewidth, br[2]-epsilon) #bottom right | |
glVertex3f(tr[0]+framewidth, tr[1]+framewidth, tr[2]-epsilon) #top right | |
glVertex3f(tl[0]-framewidth, tl[1]+framewidth, tl[2]-epsilon) #top left | |
glEnd() | |
def resize(self): | |
im = Image.open(self.filename) | |
(b1, b2, self.width, self.height) = im.getbbox() | |
im.thumbnail((Photo.thumbnailSize, Photo.thumbnailSize)) | |
tmpfile = tempfile.NamedTemporaryFile() | |
tmpfilename = tmpfile.name | |
tmpfile.file.close() # just kikkailua | |
im.save(tmpfilename, "JPEG") | |
import time | |
import random | |
# just making sure the threaded loading works.. | |
time.sleep(random.random()) | |
self.im = image.load(tmpfilename) | |
print "loaded %s" % tmpfilename | |
os.remove(tmpfilename) | |
class PhotoLayout: | |
def __init__(self, photos, type = "grid"): | |
self.type = type | |
self.photos = photos | |
def update(self): | |
N = len(self.photos) | |
if N == 0: | |
return | |
w = int(math.sqrt(N)) | |
h = int(math.ceil(N/float(w))) | |
if self.type == "grid": | |
tl = (-w/2.0 * 5.0, h/2.0 * 5.0, 0) | |
for n in range(N): | |
col = n % w | |
row = n / w | |
self.photos[n].location = add(tl, [col*5.0, -row*5.0, 0]) | |
#print "%d : %s" % (n, self.photos[col*w+row].location) | |
elif self.type == "queue": | |
for n in xrange(N): | |
self.photos[n].location = (0, 0, n) | |
class Camera: | |
def __init__(self, x, y, z, xrot=0, yrot=0, zrot=0): | |
self.x = x | |
self.y = y | |
self.z = z | |
self.xrot = xrot | |
self.yrot = yrot | |
self.zrot = zrot | |
self.xspeed = self.yspeed = self.zspeed = 0.0 | |
self.t = 0.0 # time variable for sin() stuff | |
def setup(self): | |
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT) | |
glLoadIdentity() | |
#glTranslatef(view_x, 0.0, -zoom) # Move left 1.5 units and into the screen 6.0 | |
glTranslatef(self.x, self.y, self.z) # Move left 1.5 units and into the screen 6.0 | |
glRotatef(self.xrot, 1.0, 0.0, 0.0) | |
glRotatef(self.yrot, 0.0, 1.0, 0.0) | |
glRotatef(self.zrot, 0.0, 0.0, 1.0) | |
def update(self, dt): | |
self.zrot+=self.zspeed | |
self.yrot+=self.yspeed | |
self.xrot+=self.xspeed | |
self.t += 0.08 | |
#self.zoom = sin(zt)-10.0 | |
self.z -= 0.5*sin(self.t) | |
def setSpeed(self, rv): | |
if len(rv) != 3: | |
raise Exception("3d vector assumed") | |
self.xspeed = rv[0] | |
self.yspeed = rv[1] | |
self.zspeed = rv[2] | |
def reset(self): | |
self.xspeed = self.yspeed = self.zspeed = 0.0 | |
self.x = self.y = self.z = 0.0 | |
self.xrot = self.yrot = self.zrot = 0.0 | |
def add(a, b): | |
if len(a)!=len(b): | |
raise Exception("size mismatch") | |
return [a[i]+b[i] for i in xrange(len(a))] | |
def load_photos(): | |
global myphotos | |
myphotos = list() | |
if False: | |
if len(sys.argv) == 1: | |
files = glob.glob("../data/*.jpg") | |
else: | |
files = glob.glob(sys.argv[1] + "/*.jpg") | |
print files | |
xloc = -5.0 | |
for file in files: | |
myphoto = Photo(file) | |
myphoto.location[0] = xloc | |
myphotos.append(myphoto) | |
xloc += 5.0 | |
else: | |
def flickrload(): | |
import flickrapi | |
import urllib2 | |
api_key = '12159663e48d19398dfac28562ba8f5e' | |
flickr = flickrapi.FlickrAPI(api_key) | |
ajvanne_id = '78714167@N00' | |
photos = flickr.walk(user_id=ajvanne_id) | |
for k in xrange(16): | |
photo = photos.next() | |
print "%s : %s" %(photo.get("id"), photo.get("title")) | |
sizes = flickr.photos_getSizes(photo_id=photo.get("id")) | |
#print "%s : %s" %(sizes[0][k].get("label"), sizes[0][k].get("url")) | |
url = sizes[0][2].get("source") | |
print "%s" % url | |
#tempfid = tempfile.NamedTemporaryFile() | |
filename = "temppi" + str(k) + ".jpg" | |
fid = open(filename, "wb") | |
fid.write(urllib2.urlopen(url).read()) | |
fid.close() | |
myphotos.append(Photo(filename)) | |
threading.Thread(target=flickrload).start() | |
@window.event | |
def on_mouse_drag(x, y, dx, dy, buttons, modifiers): | |
if buttons & mouse.LEFT: | |
global mycam | |
mycam.x += dx/50.0 | |
mycam.y += dy/50.0 | |
@window.event | |
def on_key_press(symbol, modifiers): | |
global mycam | |
if symbol == key.RETURN and not modifiers: | |
exit() | |
elif symbol == key.UP and not modifiers: | |
mycam.y -= 5.0 | |
elif symbol == key.DOWN and not modifiers: | |
mycam.y += 5.0 | |
elif symbol == key.RIGHT and not modifiers: | |
mycam.x -= 5.0 | |
elif symbol == key.LEFT and not modifiers: | |
mycam.x += 5.0 | |
elif symbol == key.LEFT and (modifiers & key.MOD_SHIFT): | |
mycam.zspeed += 0.1 | |
elif symbol == key.RIGHT and (modifiers & key.MOD_SHIFT): | |
mycam.zspeed -= 0.1 | |
elif symbol == key.UP and (modifiers & key.MOD_SHIFT): | |
mycam.xspeed += 0.1 | |
elif symbol == key.DOWN and (modifiers & key.MOD_SHIFT): | |
mycam.xspeed -= 0.1 | |
elif symbol == key.Z and not modifiers: | |
mycam.z -= 1.0 | |
elif symbol == key.Z and (modifiers & key.MOD_SHIFT): | |
mycam.z += 1.0 | |
elif symbol == key.X and not modifiers: | |
mycam.x += 5.0 | |
elif symbol == key.R and not modifiers: | |
mycam.reset() | |
def update(dt): | |
mycam.update(dt) | |
# Spin the objects with a constant speed | |
pyglet.clock.schedule(update) | |
@window.event | |
def on_resize(width, height): | |
if height==0: | |
height = 1 | |
glViewport(0, 0, width, height) | |
glMatrixMode(GL_PROJECTION) | |
glLoadIdentity() | |
# Calculate the aspect ratio of the window | |
gluPerspective(45.0, 1.0*width/height, 0.1, 100.0) | |
glMatrixMode(GL_MODELVIEW) | |
glLoadIdentity() | |
return pyglet.event.EVENT_HANDLED | |
def lay_photos(): | |
global myphotos, mylayout | |
#mylayout = PhotoLayout(myphotos, "queue") | |
mylayout = PhotoLayout(myphotos, "grid") | |
mylayout.update() | |
def setup(): | |
global window | |
global mycam | |
mycam = Camera(0.0, 0.0, -5.0) | |
glEnable(GL_TEXTURE_2D) | |
load_photos() | |
lay_photos() | |
#glShadeModel(GL_SMOOTH) # Enables smooth shading | |
glClearColor(0.0, 0.0, 0.0, 0.0) #Black background | |
glClearDepth(1.0) # Depth buffer setup | |
glEnable(GL_DEPTH_TEST) # Enables depth testing | |
glDepthFunc(GL_LESS) # The type of depth test to do | |
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) # Really nice perspective calculations | |
@window.event | |
def on_draw(): | |
mycam.setup() | |
global myphotos | |
global mylayout | |
mylayout.update() | |
for myphoto in myphotos: | |
myphoto.draw() | |
return pyglet.event.EVENT_HANDLED | |
if __name__ == "__main__": | |
setup() | |
pyglet.app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment