Created
November 8, 2013 01:22
-
-
Save Jerdak/7364746 to your computer and use it in GitHub Desktop.
OpenGL screenshots using python
This file contains hidden or 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
#! /usr/bin/env python | |
''' | |
Simple example demonstrating how to take a screenshot | |
''' | |
import time | |
import sys | |
import os | |
import argparse | |
#OpenGL | |
import OpenGL | |
from OpenGL.GL import * | |
from OpenGL.GLU import * | |
from OpenGL.GLUT import * | |
from OpenGL.GLUT.special import * | |
from OpenGL.GL.shaders import * | |
from PIL import Image | |
#format loaders | |
sys.path.append("./formatloaders") | |
from fl_wavefront_obj import * | |
#Other | |
import screenshot_ini_loader | |
OpenGL.FORWARD_COMPATIBLE_ONLY = True | |
OpenGL.ERROR_ON_COPY = True | |
# global object display list | |
g_dlObject = None | |
# global y-axis rotation (weeee, spinning) | |
g_Rotate = [0.0,0.0,0.0] | |
g_Translate = [0.0,0.0,-2.0] | |
# Screenshot variables | |
g_screenshot = 0 | |
g_screens = None | |
g_take_screenshot = False | |
g_maintain_window = False | |
# A general OpenGL initialization function. Sets all of the initial parameters. | |
def InitGL(Width, Height): # We call this right after our OpenGL window is created. | |
glClearColor(0.0, 0.0, 0.0, 0.0) # This Will Clear The Background Color To Black | |
glClearDepth(1.0) # Enables Clearing Of The Depth Buffer | |
glShadeModel(GL_SMOOTH) # Enables Smooth Color Shading | |
glEnable(GL_DEPTH_TEST) | |
glEnable(GL_NORMALIZE) | |
glDepthFunc(GL_LEQUAL) | |
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST) | |
glMatrixMode(GL_PROJECTION) | |
glLoadIdentity() # Reset The Projection Matrix | |
InitLightModel() | |
# Calculate The Aspect Ratio Of The Window | |
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0) | |
glMatrixMode(GL_MODELVIEW) | |
# Init basic lighting scene, assumes data sits between -1,1 on all axes. | |
def InitLightModel(): | |
cAmbientLight = GLfloat_4(0.5,0.5,0.5,1.0) | |
glLightfv(GL_LIGHT1,GL_AMBIENT,cAmbientLight) | |
cDiffuseLight = GLfloat_4(0.5,0.5,0.5,1.0) | |
glLightfv(GL_LIGHT1,GL_DIFFUSE,cDiffuseLight) | |
vLightPos = GLfloat_4(1,3,4,1) | |
glLightfv(GL_LIGHT1, GL_POSITION,vLightPos ); | |
glEnable(GL_LIGHT1) | |
glEnable(GL_LIGHTING) | |
def InitScreenShots(): | |
global g_screens,g_take_screenshot | |
g_screens = screenshot_ini_loader.load("screenshotty.ini") | |
if g_screens == None: | |
print "Could not initialize screenshot array due to errors in ini loader, fix and try again" | |
#sys.exit(1) | |
else: | |
g_take_screenshot = True | |
# Generate debug display list using 'teapot' | |
def dbgInitDisplayList(): | |
global g_dlObject | |
g_dlObject = glGenLists(1) | |
glNewList(g_dlObject,GL_COMPILE) | |
glutSolidTeapot(1.0) | |
glEndList() | |
# Generate display list for any obj | |
def InitDisplayList(filename): | |
global g_dlObject,g_take_screenshot | |
obj = WaveFront() | |
obj.NormalizeVertices = True | |
obj.load(filename) | |
g_dlObject = glGenLists(1) | |
glNewList(g_dlObject,GL_COMPILE) | |
glBegin(GL_TRIANGLES) | |
ct = 0 | |
progress = "" | |
if obj.Colors != None: | |
print "Object has texture, attempting render" | |
for face in obj.Faces: | |
if ct % (len(obj.Faces)/20) == 0: | |
progress += "=" | |
space = "" | |
for i in range(len(progress),20): | |
space += " " | |
sys.stdout.write("Initializing Normals 0[" + progress + ">" + space + "]100\r"); | |
ct+= 1 | |
v1 = [obj.Vertices[face[0]-1][0],obj.Vertices[face[0]-1][1],obj.Vertices[face[0]-1][2]] | |
v2 = [obj.Vertices[face[1]-1][0],obj.Vertices[face[1]-1][1],obj.Vertices[face[1]-1][2]] | |
v3 = [obj.Vertices[face[2]-1][0],obj.Vertices[face[2]-1][1],obj.Vertices[face[2]-1][2]] | |
if obj.Colors != None: | |
c1 = [obj.Colors[face[0]-1][0],obj.Colors[face[0]-1][1],obj.Colors[face[0]-1][2]] | |
c2 = [obj.Colors[face[1]-1][0],obj.Colors[face[1]-1][1],obj.Colors[face[1]-1][2]] | |
c3 = [obj.Colors[face[2]-1][0],obj.Colors[face[2]-1][1],obj.Colors[face[2]-1][2]] | |
if len(obj.Normals) != 0: | |
n = [obj.Normals[face[0]-1][0],obj.Normals[face[0]-1][1],obj.Normals[face[0]-1][2]] | |
else: | |
# calculate normals on the fly (slow as hell on any decently size models.) | |
e1 = [v2[0] - v1[0],v2[1] - v1[1],v2[2] - v1[2]] | |
e2 = [v3[0] - v1[0],v3[1] - v1[1],v3[2] - v1[2]] | |
n = cross(e1,e2) | |
length = sqrt(n[0]*n[0] + n[1] * n[1] + n[2] * n[2]) | |
if length > 0.0: | |
n[0] = n[0] / length | |
n[1] = n[1] / length | |
n[2] = n[2] / length | |
glNormal3f(n[0],n[1],n[2]) | |
if obj.Colors != None: | |
glColor3f(c1[0],c1[1],c1[2]) | |
glVertex3f(v1[0],v1[1],v1[2]) | |
if obj.Colors != None: | |
glColor3f(c2[0],c2[1],c2[2]) | |
glVertex3f(v2[0],v2[1],v2[2]) | |
if obj.Colors != None: | |
glColor3f(c3[0],c3[1],c3[2]) | |
glVertex3f(v3[0],v3[1],v3[2]) | |
glEnd() | |
glEndList() | |
print "\nObj loaded" | |
# The function called when our window is resized (which shouldn't happen if you enable fullscreen, below) | |
def ReSizeGLScene(Width, Height): | |
if Height == 0: # Prevent A Divide By Zero If The Window Is Too Small | |
Height = 1 | |
glViewport(0, 0, Width, Height) # Reset The Current Viewport And Perspective Transformation | |
glMatrixMode(GL_PROJECTION) | |
glLoadIdentity() | |
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0) | |
glMatrixMode(GL_MODELVIEW) | |
#dump back buffer to image | |
def ScreenShot(filename): | |
width = 800 | |
height = 600 | |
glReadBuffer(GL_FRONT) | |
pixels = glReadPixels(0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE) | |
image = Image.fromstring("RGB", (width, height), pixels) | |
image = image.transpose( Image.FLIP_TOP_BOTTOM) | |
image.save(filename) | |
g_screenshot = 0 | |
g_screenshot_name = ["screenx.jpg","screeny.jpg","screenz.jpg"] | |
g_screenshot_angle = [[90,1,0,0],[90,0,1,0],[90,0,0,1]] | |
# The main drawing function. | |
def DrawGLScene(): | |
global g_Rotate,g_Translate,g_take_screenshot,g_screenshot | |
glColorMaterial ( GL_FRONT, GL_AMBIENT ) | |
glEnable ( GL_COLOR_MATERIAL ) | |
glDrawBuffer(GL_BACK) | |
glMatrixMode(GL_MODELVIEW) | |
glLoadIdentity() | |
# Clear The Screen And The Depth Buffer | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) | |
#glDisable(GL_LIGHTING) | |
glTranslatef(g_Translate[0],g_Translate[1],g_Translate[2]) | |
#glMultMatrixf(g_Transform) | |
if g_take_screenshot: | |
print "Obj was loaded, getting first file:",g_screens[g_screenshot][0] | |
glMultMatrixf(g_screens[g_screenshot][1]) | |
#anglev = g_screenshot_angle[g_screenshot] | |
#glRotatef(90,0,0,1) | |
# Draw list | |
glCallList(g_dlObject) | |
# Swap buffers | |
glutSwapBuffers() | |
glFlush() | |
ScreenShot(g_screens[g_screenshot][0]) | |
g_screenshot += 1 | |
if g_screenshot >= len(g_screens): | |
if not g_maintain_window: | |
sys.exit(1) | |
g_take_screenshot=False | |
else: | |
if g_maintain_window: | |
glCallList(g_dlObject) | |
# Swap buffers | |
glutSwapBuffers() | |
# The function called whenever a key is pressed. Note the use of Python tuples to pass in: (key, x, y) | |
def keyPressed(*args): | |
# If escape is pressed, kill everything. | |
if args[0] == '\x1b': | |
sys.exit() | |
def windowClose(*args): | |
print "Window closing" | |
return | |
def main(args): | |
global window | |
global falloffValue | |
global g_take_screenshot,g_maintain_window | |
# Force hide window to fake "background" rendering | |
if not args.unhide: | |
glutHideWindow() | |
else: | |
g_maintain_window = True | |
glutInit() | |
# Select type of Display mode: | |
# Double buffer | |
# RGBA color | |
# Alpha components supported | |
# Depth buffer | |
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH) | |
# get a 800 x 600 window | |
glutInitWindowSize(800, 600) | |
# the window starts at the upper left corner of the screen | |
glutInitWindowPosition(0, 0) | |
# Okay, like the C version we retain the window id to use when closing, but for those of you new | |
# to Python (like myself), remember this assignment would make the variable local and not global | |
# if it weren't for the global declaration at the start of main. | |
window = glutCreateWindow("Display List Test") | |
# Register the drawing function with glut, BUT in Python land, at least using PyOpenGL, we need to | |
# set the function pointer and invoke a function to actually register the callback, otherwise it | |
# would be very much like the C version of the code. | |
glutDisplayFunc(DrawGLScene) | |
# Uncomment this line to get full screen. | |
#glutFullScreen() | |
# When we are doing nothing, redraw the scene. | |
glutIdleFunc(DrawGLScene) | |
# Register the function called when our window is resized. | |
glutReshapeFunc(ReSizeGLScene) | |
# Load screenshot array | |
InitScreenShots() | |
# Load display list w/ model | |
InitDisplayList(args.filename) | |
# Initialize our window. | |
InitGL(800, 600) | |
# Start Event Processing Engine | |
glutMainLoop() | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description= | |
"Take screenshots* of a Wavefront .obj file\n" | |
"\n" | |
"*Screenshots must be defined in screenshots.ini.\n" | |
"This file must reside at the same level as\n" | |
"screenshotty.py (See file for examples)", | |
formatter_class=argparse.RawTextHelpFormatter) | |
parser.add_argument('filename', metavar='<obj file>', type=str, | |
help='Wavefront .obj file to load') | |
parser.add_argument('-u','--unhide',action="store_true",help="Unhide background rendering window") | |
args = parser.parse_args() | |
print "Hit ESC key to quit." | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment