diff --git a/demo.py b/demo.py index 070ea0c..3402a0d 100644 --- a/demo.py +++ b/demo.py @@ -6,45 +6,46 @@ """ import sys, math, time -if sys.version_info[0] < 3 : +if sys.version_info[0] < 3: from Tkinter import Tk, YES, BOTH else: from tkinter import Tk, YES, BOTH from OpenGL import GL, GLU from pyopengltk import OpenGLFrame + class AppOgl(OpenGLFrame): def initgl(self): - GL.glViewport( 0, 0, self.width, self.height) - GL.glClearColor(1.0,1.0,1.0,0.0) - GL.glColor3f(0.0,0.0, 0.0) + GL.glViewport(0, 0, self.width, self.height) + GL.glClearColor(1.0, 1.0, 1.0, 0.0) + GL.glColor3f(0.0, 0.0, 0.0) GL.glPointSize(4.0) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() - GLU.gluOrtho2D(-5,5,-5,5) + GLU.gluOrtho2D(-5, 5, -5, 5) self.start = time.time() self.nframes = 0 - def redraw(self): GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glBegin(GL.GL_POINTS) npt = 100 for i in range(npt): - x = -5.0 + i*10.0/npt - y = math.sin(x+ time.time())*5/2 - GL.glVertex2f( x, y ) + x = -5.0 + i * 10.0 / npt + y = math.sin(x + time.time())*5/2 + GL.glVertex2f(x, y) GL.glEnd() GL.glFlush() - self.nframes+=1 + self.nframes += 1 tm = time.time() - self.start - print("fps",self.nframes / tm, end="\r" ) + print("fps", self.nframes / tm, end="\r") + if __name__ == '__main__': root = Tk() app = AppOgl(root, width=320, height=200) app.pack(fill=BOTH, expand=YES) - app.animate=1 + app.animate = 1 app.after(100, app.printContext) app.mainloop() diff --git a/pyopengltk.py b/pyopengltk.py index c455636..7d2debf 100644 --- a/pyopengltk.py +++ b/pyopengltk.py @@ -14,7 +14,7 @@ # Python + Tkinter (no pyopengl) # http://github.com/arcanosam/pytkogl/ # (The Code Project Open License) -# Article at +# Article at # http://www.codeproject.com/Articles/1073475/OpenGL-in-Python-with-TKinter # # Large parts copied from pyopengl/Tk/__init__.py @@ -22,14 +22,18 @@ from __future__ import print_function - -__all__ = [ 'OpenGLFrame', 'RawOpengl', 'Opengl', - 'glTranslateScene','glRotateScene','v3distsq' ] - +__all__ = [ + 'OpenGLFrame', + 'RawOpengl', + 'Opengl', + 'glTranslateScene', + 'glRotateScene', + 'v3distsq', +] import sys, math, os, logging -_log = logging.getLogger( 'pyopengltk' ) +_log = logging.getLogger('pyopengltk') from OpenGL import GL, GLU @@ -41,70 +45,70 @@ from tkinter import dialog as dialog - -class baseOpenGLFrame(tk.Frame): +class BaseOpenGLFrame(tk.Frame): """ Common code for windows/x11 """ def __init__(self, *args, **kw): - # Set background to empty string to avoid + # Set background to empty string to avoid # flickering overdraw by Tk - kw['bg'] ="" - tk.Frame.__init__( self, *args, **kw ) - self.bind('', self.tkMap ) - self.bind('', self.tkResize ) - self.bind('', self.tkExpose ) + kw['bg'] = "" + tk.Frame.__init__(self, *args, **kw) + self.bind('', self.tkMap) + self.bind('', self.tkResize) + self.bind('', self.tkExpose) self.animate = 0 self.cb = None - def tkMap( self, evt ): + def tkMap(self, evt): """" Called when frame goes onto the screen """ self._wid = self.winfo_id() - self.tkCreateContext( ) + self.tkCreateContext() self.initgl() def printContext(self, extns=False): """ For debugging """ exts = GL.glGetString(GL.GL_EXTENSIONS) if extns: - print("Extension list:") + print("Extension list:") for e in sorted(exts.split()): - print( "\t", e ) + print("\t", e) else: - print("Number of extensions:",len(exts.split())) - print( "GL_VENDOR :",GL.glGetString(GL.GL_VENDOR)) - print( "GL_RENDERER:",GL.glGetString(GL.GL_RENDERER)) - print( "GL_VERSION :",GL.glGetString(GL.GL_VERSION)) + print("Number of extensions:", len(exts.split())) + + print("GL_VENDOR :", GL.glGetString(GL.GL_VENDOR)) + print("GL_RENDERER:", GL.glGetString(GL.GL_RENDERER)) + print("GL_VERSION :", GL.glGetString(GL.GL_VERSION)) try: - print(" GL_MAJOR_VERSION:", GL.glGetIntegerv( GL.GL_MAJOR_VERSION )) - print(" GL_MINOR_VERSION:", GL.glGetIntegerv( GL.GL_MINOR_VERSION )) - print(" GL_SHADING_LANGUAGE_VERSION :", - GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)) + print(" GL_MAJOR_VERSION:", GL.glGetIntegerv(GL.GL_MAJOR_VERSION)) + print(" GL_MINOR_VERSION:", GL.glGetIntegerv(GL.GL_MINOR_VERSION)) + print(" GL_SHADING_LANGUAGE_VERSION :", + GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)) msk = GL.glGetIntegerv(GL.GL_CONTEXT_PROFILE_MASK) print(" GL_CONTEXT_CORE_PROFILE_BIT :", - bool( msk & GL.GL_CONTEXT_CORE_PROFILE_BIT) ) + bool(msk & GL.GL_CONTEXT_CORE_PROFILE_BIT)) print(" GL_CONTEXT_COMPATIBILITY_PROFILE_BIT :", - bool( msk & GL.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ) + bool(msk & GL.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)) except: print("Old context errors arose") # raise - def tkCreateContext( self ): + def tkCreateContext(self): # Platform dependent part raise NotImplementedError - def tkMakeCurrent( self ): + def tkMakeCurrent(self): # Platform dependent part raise NotImplementedError - def tkSwapBuffers( self ): + def tkSwapBuffers(self): # Platform dependent part raise NotImplementedError - def tkExpose( self, evt): + def tkExpose(self, evt): if self.cb: self.after_cancel(self.cb) self._display() - def tkResize( self, evt ): + def tkResize(self, evt): """ Things to do on window resize: Adjust viewport: @@ -120,18 +124,18 @@ def tkResize( self, evt ): """ self.width, self.height = evt.width, evt.height if self.winfo_ismapped(): - GL.glViewport( 0, 0, self.width, self.height ) + GL.glViewport(0, 0, self.width, self.height) self.initgl() - + def _display(self): self.update_idletasks() self.tkMakeCurrent() self.redraw() - self.tkSwapBuffers( ) + self.tkSwapBuffers() if self.animate > 0: - self.cb = self.after(self.animate, self._display ) - - def initgl(self): + self.cb = self.after(self.animate, self._display) + + def initgl(self): # For the user code raise NotImplementedError @@ -139,14 +143,15 @@ def redraw(self): # For the user code raise NotImplementedError + ############################################################################### # Windows specific code here: -if sys.platform.startswith( 'win32' ): +if sys.platform.startswith('win32'): from ctypes import WinDLL, c_void_p, sizeof from ctypes.wintypes import HDC, BOOL from OpenGL.WGL import PIXELFORMATDESCRIPTOR, ChoosePixelFormat, \ - SetPixelFormat, SwapBuffers, wglCreateContext, wglMakeCurrent + SetPixelFormat, SwapBuffers, wglCreateContext, wglMakeCurrent _user32 = WinDLL('user32') GetDC = _user32.GetDC @@ -166,28 +171,29 @@ def redraw(self): pfd.iLayerType = PFD_MAIN_PLANE # Inherits the base and fills in the 3 platform dependent functions - class OpenGLFrame( baseOpenGLFrame ): - - def tkCreateContext( self ): + class OpenGLFrame(BaseOpenGLFrame): + + def tkCreateContext(self): self.__window = GetDC(self.winfo_id()) pixelformat = ChoosePixelFormat(self.__window, pfd) SetPixelFormat(self.__window, pixelformat, pfd) self.__context = wglCreateContext(self.__window) wglMakeCurrent(self.__window, self.__context) - def tkMakeCurrent( self ): + def tkMakeCurrent(self): if self.winfo_ismapped(): - wglMakeCurrent( self.__window, self.__context) - - def tkSwapBuffers( self ): + wglMakeCurrent(self.__window, self.__context) + + def tkSwapBuffers(self): if self.winfo_ismapped(): - SwapBuffers(self.__window) + SwapBuffers(self.__window) + # END Windows specific code ############################################################################### -# Linux/X11 specific code here: +# Linux/X11 specific code here: -if sys.platform.startswith( 'linux' ): +if sys.platform.startswith('linux'): from ctypes import c_int, c_char_p, c_void_p, cdll, POINTER, util, \ pointer, CFUNCTYPE, c_bool @@ -196,97 +202,101 @@ def tkSwapBuffers( self ): from OpenGL.raw._GLX import Display except: from OpenGL.raw.GLX._types import Display - - _x11lib = cdll.LoadLibrary(util.find_library( "X11" ) ) + + _x11lib = cdll.LoadLibrary(util.find_library("X11")) XOpenDisplay = _x11lib.XOpenDisplay XOpenDisplay.argtypes = [c_char_p] XOpenDisplay.restype = POINTER(Display) - + Colormap = c_void_p # Attributes for old style creation - att = [ GLX.GLX_RGBA, GLX.GLX_DOUBLEBUFFER, - GLX.GLX_RED_SIZE, 4, - GLX.GLX_GREEN_SIZE, 4, - GLX.GLX_BLUE_SIZE, 4, - GLX.GLX_DEPTH_SIZE, 16, - 0, - ] + att = [ + GLX.GLX_RGBA, GLX.GLX_DOUBLEBUFFER, + GLX.GLX_RED_SIZE, 4, + GLX.GLX_GREEN_SIZE, 4, + GLX.GLX_BLUE_SIZE, 4, + GLX.GLX_DEPTH_SIZE, 16, + 0, + ] # Attributes for newer style creations - fbatt = [ GLX.GLX_X_RENDERABLE , 1, - GLX.GLX_DRAWABLE_TYPE , GLX.GLX_WINDOW_BIT, - GLX.GLX_RENDER_TYPE , GLX.GLX_RGBA_BIT, - GLX.GLX_RED_SIZE , 1, - GLX.GLX_GREEN_SIZE , 1, - GLX.GLX_BLUE_SIZE , 1, - GLX.GLX_DOUBLEBUFFER , 1, - 0, - ] + fbatt = [ + GLX.GLX_X_RENDERABLE, 1, + GLX.GLX_DRAWABLE_TYPE, GLX.GLX_WINDOW_BIT, + GLX.GLX_RENDER_TYPE, GLX.GLX_RGBA_BIT, + GLX.GLX_RED_SIZE, 1, + GLX.GLX_GREEN_SIZE, 1, + GLX.GLX_BLUE_SIZE, 1, + GLX.GLX_DOUBLEBUFFER, 1, + 0, + ] # Inherits the base and fills in the 3 platform dependent functions - class OpenGLFrame( baseOpenGLFrame ): + class OpenGLFrame(BaseOpenGLFrame): - def tkCreateContext( self ): - self.__window = XOpenDisplay( self.winfo_screen().encode('utf-8')) + def tkCreateContext(self): + self.__window = XOpenDisplay(self.winfo_screen().encode('utf-8')) # Check glx version: major = c_int(0) minor = c_int(0) - GLX.glXQueryVersion( self.__window, major, minor ) - print("GLX version: %d.%d"%(major.value,minor.value)) - if major.value == 1 and minor.value < 3: # e.g. 1.2 and down - visual = GLX.glXChooseVisual( self.__window, 0, - (GL.GLint * len(att))(* att) ) + GLX.glXQueryVersion(self.__window, major, minor) + print("GLX version: %d.%d" % (major.value, minor.value)) + if major.value == 1 and minor.value < 3: # e.g. 1.2 and down + visual = GLX.glXChooseVisual(self.__window, 0, + (GL.GLint * len(att))(* att)) if not visual: - _log.error("glXChooseVisual call failed" ) + _log.error("glXChooseVisual call failed") self.__context = GLX.glXCreateContext(self.__window, visual, None, GL.GL_TRUE) GLX.glXMakeCurrent(self.__window, self._wid, self.__context) - return # OUT HERE FOR 1.2 and less + return # OUT HERE FOR 1.2 and less else: # 1.3 or higher # which screen - should it be winfo_screen instead ?? XDefaultScreen = _x11lib.XDefaultScreen XDefaultScreen.argtypes = [POINTER(Display)] XDefaultScreen.restype = c_int - screen = XDefaultScreen( self.__window ) - print("Screen is ",screen) - # Look at framebuffer configs - ncfg = GL.GLint(0) - cfgs = GLX.glXChooseFBConfig( self.__window, - screen, - (GL.GLint * len(fbatt))(* fbatt), - ncfg ) - print( "Number of FBconfigs",ncfg.value ) + screen = XDefaultScreen(self.__window) + print("Screen is ", screen) + # Look at framebuffer configs + ncfg = GL.GLint(0) + cfgs = GLX.glXChooseFBConfig( + self.__window, + screen, + (GL.GLint * len(fbatt))(* fbatt), + ncfg, + ) + print("Number of FBconfigs", ncfg.value) # # Try to match to the current window # ... might also be possible to set this for the frame # ... but for now we just take what Tk gave us - ideal = int(self.winfo_visualid(), 16) # convert from hex + ideal = int(self.winfo_visualid(), 16) # convert from hex best = -1 for i in range(ncfg.value): vis = GLX.glXGetVisualFromFBConfig(self.__window, cfgs[i]) if ideal == vis.contents.visualid: best = i - print("Got a matching visual: index %d %d xid %s"%( - best,vis.contents.visualid,hex(ideal) )) + print("Got a matching visual: index %d %d xid %s" % ( + best, vis.contents.visualid, hex(ideal))) if best < 0: - print("oh dear - visual does not match" ) + print("oh dear - visual does not match") # Take the first in the list (should be another I guess) - best=0 + best = 0 # Here we insist on RGBA - but didn't check earlier self.__context = GLX.glXCreateNewContext(self.__window, cfgs[best], GLX.GLX_RGBA_TYPE, - None, # share list - GL.GL_TRUE) # direct - print("Is Direct?: ", GLX.glXIsDirect( self.__window, self.__context )) + None, # share list + GL.GL_TRUE) # direct + print("Is Direct?: ", GLX.glXIsDirect(self.__window, self.__context)) # Not creating another window ... some tutorials do -# print("wid: ",self._wid) -# self._wid = GLX.glXCreateWindow( self.__window, cfgs[best], self._wid, None) -# print("wid: ",self._wid) - GLX.glXMakeContextCurrent( self.__window, self._wid, self._wid, - self.__context ) + # print("wid: ", self._wid) + # self._wid = GLX.glXCreateWindow(self.__window, cfgs[best], self._wid, None) + # print("wid: ", self._wid) + GLX.glXMakeContextCurrent(self.__window, self._wid, self._wid, + self.__context) print("Done making a first context") extensions = GLX.glXQueryExtensionsString(self.__window, screen) # Here we quit - getting a modern context needs further work below @@ -294,12 +304,12 @@ def tkCreateContext( self ): if "GLX_ARB_create_context" in extensions: # We can try to upgrade it ?? print("Trying to upgrade context") - s = "glXCreateContextAttribsARB" - p = GLX.glXGetProcAddress( c_char_p( s ) ) - + s = "glXCreateContextAttribsARB" + p = GLX.glXGetProcAddress(c_char_p(s)) + print(p) if not p: - p = GLX.glXGetProcAddressARB( ( GL.GLubyte * len(s)).from_buffer_copy(s) ) + p = GLX.glXGetProcAddressARB((GL.GLubyte * len(s)).from_buffer_copy(s)) print(p) if p: print(" p is true") @@ -309,30 +319,29 @@ def tkCreateContext( self ): GLX.GLXContext, c_bool, POINTER(c_int)] - arb_attrs = fbatt[:-1] + [ ] + arb_attrs = fbatt[:-1] + [] - # GLX.GLX_CONTEXT_MAJOR_VERSION_ARB , 3 + # GLX.GLX_CONTEXT_MAJOR_VERSION_ARB , 3 # GLX.GLX_CONTEXT_MINOR_VERSION_ARB , 1, # 0 ] # # GLX.GLX_CONTEXT_FLAGS_ARB # GLX.GLX_CONTEXT_PROFILE_MASK_ARB - #] + # ] # import pdb # pdb.set_trace() - self.__context = p( self.__window, cfgs[best], None, GL.GL_TRUE, - (GL.GLint * len(arb_attrs))(* arb_attrs) ) - + self.__context = p(self.__window, cfgs[best], None, GL.GL_TRUE, + (GL.GLint * len(arb_attrs))(* arb_attrs)) - def tkMakeCurrent( self ): + def tkMakeCurrent(self): if self.winfo_ismapped(): GLX.glXMakeCurrent(self.__window, self._wid, self.__context) - def tkSwapBuffers( self ): + def tkSwapBuffers(self): if self.winfo_ismapped(): - GLX.glXSwapBuffers( self.__window, self._wid) + GLX.glXSwapBuffers(self.__window, self._wid) -# Linux/X11 specific code ends +# Linux/X11 specific code ends ############################################################################### @@ -364,12 +373,12 @@ def glRotateScene(s, xcenter, ycenter, zcenter, x, y, mousex, mousey): GL.glMultMatrixd(mat) -def v3distsq(a,b): - d = ( a[0] - b[0], a[1] - b[1], a[2] - b[2] ) - return d[0]*d[0] + d[1]*d[1] + d[2]*d[2] +def v3distsq(a, b): + d = (a[0] - b[0], a[1] - b[1], a[2] - b[2]) + return d[0] * d[0] + d[1] * d[1] + d[2] * d[2] -class RawOpengl( OpenGLFrame ): +class RawOpengl(OpenGLFrame): """Widget without any sophisticated bindings\ by Tom Schwaller""" def __init__(self, master=None, cnf={}, **kw): @@ -410,7 +419,7 @@ def __init__(self, master=None, cnf={}, **kw): Arrange for redraws when the window is exposed or when it changes size.""" - #Widget.__init__(self, master, 'togl', cnf, kw) + # Widget.__init__(self, master, 'togl', cnf, kw) RawOpengl.__init__(*(self, master, cnf), **kw) self.initialised = 0 @@ -446,7 +455,7 @@ def __init__(self, master=None, cnf={}, **kw): # Basic bindings for the virtual trackball self.bind('', self.tkHandlePick) - #self.bind('', self.tkHandlePick) + # self.bind('', self.tkHandlePick) self.bind('', self.tkRecordMouse) self.bind('', self.tkTranslate) self.bind('', self.StartRotate) @@ -455,7 +464,6 @@ def __init__(self, master=None, cnf={}, **kw): self.bind('', self.tkRecordMouse) self.bind('', self.tkScale) - def help(self): """Help for the widget.""" @@ -474,7 +482,6 @@ def activate(self): """Cause this Opengl widget to be the current destination for drawing.""" self.tkMakeCurrent() - # This should almost certainly be part of some derived class. # But I have put it here for convenience. def basic_lighting(self): @@ -482,7 +489,7 @@ def basic_lighting(self): Set up some basic lighting (single infinite light source). Also switch on the depth buffer.""" - + self.activate() light_position = (1, 1, 1, 0) GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position) @@ -505,7 +512,6 @@ def set_background(self, r, g, b): self.tkRedraw() - def set_centerpoint(self, x, y, z): """Set the new center point for the model. This is where we are looking.""" @@ -516,14 +522,12 @@ def set_centerpoint(self, x, y, z): self.tkRedraw() - def set_eyepoint(self, distance): """Set how far the eye is from the position we are looking.""" self.distance = distance self.tkRedraw() - def reset(self): """Reset rotation matrix for this widget.""" @@ -531,7 +535,6 @@ def reset(self): GL.glLoadIdentity() self.tkRedraw() - def tkHandlePick(self, event): """Handle a pick on the scene.""" @@ -553,21 +556,18 @@ def tkHandlePick(self, event): self.tkRedraw() - def tkRecordMouse(self, event): """Record the current mouse position.""" self.xmouse = event.x self.ymouse = event.y - def StartRotate(self, event): # Switch off any autospinning if it was happening self.autospin = 0 self.tkRecordMouse(event) - def tkScale(self, event): """Scale the scene. Achieved by moving the eye position. @@ -584,18 +584,16 @@ def tkScale(self, event): self.tkRedraw() self.tkRecordMouse(event) - def do_AutoSpin(self): self.activate() - glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, - self.yspin, self.xspin, 0, 0) + glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, + self.yspin, self.xspin, 0, 0) self.tkRedraw() if self.autospin: self.after(10, self.do_AutoSpin) - def tkAutoSpin(self, event): """Perform autospin of scene.""" @@ -618,40 +616,40 @@ def tkAutoSpin(self, event): self.after(10, self.do_AutoSpin) - def tkRotate(self, event): """Perform rotation of scene.""" self.activate() - glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, - event.x, event.y, self.xmouse, self.ymouse) + glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, + event.x, event.y, self.xmouse, self.ymouse) self.tkRedraw() self.tkRecordMouse(event) - def tkTranslate(self, event): """Perform translation of scene.""" self.activate() - # Scale mouse translations to object viewplane so object tracks with mouse + # Scale mouse translations to object viewplane so object + # tracks with mouse - win_height = max( 1,self.winfo_height() ) - obj_c = ( self.xcenter, self.ycenter, self.zcenter ) - win = GLU.gluProject( obj_c[0], obj_c[1], obj_c[2]) - obj = GLU.gluUnProject( win[0], win[1] + 0.5 * win_height, win[2]) - dist = math.sqrt( v3distsq( obj, obj_c ) ) - scale = abs( dist / ( 0.5 * win_height ) ) + win_height = max(1, self.winfo_height()) + obj_c = (self.xcenter, self.ycenter, self.zcenter) + win = GLU.gluProject(obj_c[0], obj_c[1], obj_c[2]) + obj = GLU.gluUnProject(win[0], win[1] + 0.5 * win_height, win[2]) + dist = math.sqrt(v3distsq(obj, obj_c)) + scale = abs(dist / (0.5 * win_height)) glTranslateScene(scale, event.x, event.y, self.xmouse, self.ymouse) self.tkRedraw() self.tkRecordMouse(event) - def tkRedraw(self, *dummy): """Cause the opengl widget to redraw itself.""" - if not self.initialised: return + if not self.initialised: + return + self.activate() GL.glPushMatrix() # Protect our matrix @@ -678,11 +676,11 @@ def tkRedraw(self, *dummy): self.zcenter+self.distance)) glMultMatrixd(mat) else: - GLU.gluLookAt(self.xcenter, self.ycenter, self.zcenter+self.distance, - self.xcenter, self.ycenter, self.zcenter, - 0., 1., 0.) + GLU.gluLookAt(self.xcenter, self.ycenter, self.zcenter + self.distance, + self.xcenter, self.ycenter, self.zcenter, + 0., 1., 0.) GL.glMatrixMode(GL.GL_MODELVIEW) - + # Call objects redraw method. self.redraw(self) GL.glFlush() # Tidy up @@ -690,12 +688,9 @@ def tkRedraw(self, *dummy): self.tkSwapBuffers() - - def redraw( self, *args, **named ): + def redraw(self, *args, **named): """Prevent access errors if user doesn't set redraw fast enough""" - - def tkExpose(self, *dummy): """Redraw the widget. Make it active, update tk events, call redraw procedure and @@ -708,9 +703,6 @@ def tkExpose(self, *dummy): self.initialised = 1 self.tkRedraw() - def tkPrint(self, file): """Turn the current scene into PostScript via the feedback buffer.""" - self.activate() - diff --git a/setup.py b/setup.py index 77cc0f2..1db1a43 100644 --- a/setup.py +++ b/setup.py @@ -4,9 +4,9 @@ setup( name='pyopengltk', version='0.0.1', - author ='Jon Wright', - author_email = 'jonathan.wright@gmail.com', - url = 'http://github.com/jonwright/pyopengltk', + author='Jon Wright', + author_email='jonathan.wright@gmail.com', + url='http://github.com/jonwright/pyopengltk', license='MIT', description="An opengl frame for pyopengl-tkinter based on ctype", long_description=open('README.md').read(), diff --git a/shader_example.py b/shader_example.py index 613a230..84f6805 100644 --- a/shader_example.py +++ b/shader_example.py @@ -1,4 +1,4 @@ - +"""Example rotating a point cloud containing 100.000 points""" from __future__ import print_function, division from OpenGL import GL, GLUT @@ -14,13 +14,14 @@ else: import Tkinter as tk -# + # Avoiding glitches in pyopengl-3.0.x and python3.4 def bytestr(s): - return s.encode("utf-8")+b"\000" -# + return s.encode("utf-8") + b"\000" + + # Avoiding glitches in pyopengl-3.0.x and python3.4 -def compileShader( source, shaderType ): +def compileShader(source, shaderType): """ Compile shader source of given type source -- GLSL source-code for the shader @@ -41,15 +42,16 @@ def compileShader( source, shaderType ): # TODO: this will be wrong if the user has # disabled traditional unpacking array support. raise RuntimeError( - """Shader compile failure (%s): %s"""%( + """Shader compile failure (%s): %s""" % ( result, - GL.glGetShaderInfoLog( shader ), + GL.glGetShaderInfoLog(shader), ), source, shaderType, ) - return shader - + return shader + + vertex_shader = """#version 130 in vec3 position; varying vec3 vertex_color; @@ -66,53 +68,57 @@ def compileShader( source, shaderType ): varying vec3 vertex_color; void main() { - gl_FragColor = vec4(vertex_color,0.25f); + gl_FragColor = vec4(vertex_color,0.25f); } """ -NPTS=100000 +NPTS = 100000 + +vertices = (numpy.random.random(NPTS * 3).astype(numpy.float32)-.5) * 1.5 +vertices.shape = NPTS, 3 -vertices = (numpy.random.random( NPTS*3 ).astype(numpy.float32)-.5)*1.5 -vertices.shape = NPTS,3 def create_object(shader): # Create a new VAO (Vertex Array Object) and bind it vertex_array_object = GL.glGenVertexArrays(1) - GL.glBindVertexArray( vertex_array_object ) + GL.glBindVertexArray(vertex_array_object) # Generate buffers to hold our vertices vertex_buffer = GL.glGenBuffers(1) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vertex_buffer) - # Get the position of the 'position' in parameter of our shader and bind it. - position = GL.glGetAttribLocation(shader, bytestr('position') ) + # Get the position of the 'position' in parameter of our shader + # and bind it. + position = GL.glGetAttribLocation(shader, bytestr('position')) GL.glEnableVertexAttribArray(position) # Describe the position data layout in the buffer - GL.glVertexAttribPointer(position, 3, GL.GL_FLOAT, False, 0, ctypes.c_void_p(0)) + GL.glVertexAttribPointer(position, 3, GL.GL_FLOAT, False, + 0, ctypes.c_void_p(0)) # Send the data over to the buffer (bytes) vs = vertices.tostring() GL.glBufferData(GL.GL_ARRAY_BUFFER, len(vs), vs, GL.GL_STATIC_DRAW) # Unbind the VAO first (Important) - GL.glBindVertexArray( 0 ) + GL.glBindVertexArray(0) # Unbind other stuff GL.glDisableVertexAttribArray(position) GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0) return vertex_array_object - -def rot(a,b,c): - s=numpy.sin(a) - c=numpy.cos(a) - am = numpy.array((( c,s,0),(-s,c,0),(0,0,1)), numpy.float32) - s=numpy.sin(b) - c=numpy.cos(b) - bm = numpy.array((( c,0,s),(0,1,0),(-s,0,c)), numpy.float32) - s=numpy.sin(c) - c=numpy.cos(c) - cm = numpy.array((( 1,0,0 ),(0,c,s),(0,-s,c)), numpy.float32) - return numpy.dot(numpy.dot( am, bm ), cm ) + + +def rot(a, b, c): + s = numpy.sin(a) + c = numpy.cos(a) + am = numpy.array(((c, s, 0), (-s, c, 0), (0, 0, 1)), numpy.float32) + s = numpy.sin(b) + c = numpy.cos(b) + bm = numpy.array(((c, 0, s), (0, 1, 0), (-s, 0, c)), numpy.float32) + s = numpy.sin(c) + c = numpy.cos(c) + cm = numpy.array(((1, 0, 0), (0, c, s), (0, -s, c)), numpy.float32) + return numpy.dot(numpy.dot(am, bm), cm) class ShaderFrame(pyopengltk.OpenGLFrame): def initgl(self): -# GLUT.glutInit(sys.argv) + # GLUT.glutInit(sys.argv) GL.glClearColor(0.15, 0.15, 0.15, 1.0) GL.glEnable(GL.GL_DEPTH_TEST) GL.glEnable(GL.GL_PROGRAM_POINT_SIZE) @@ -122,7 +128,7 @@ def initgl(self): compileShader(fragment_shader, GL.GL_FRAGMENT_SHADER) ) self.vertex_array_object = create_object(self.shader) - self.proj = GL.glGetUniformLocation( self.shader, bytestr('proj')) + self.proj = GL.glGetUniformLocation(self.shader, bytestr('proj')) self.nframes = 0 self.start = time.time() @@ -131,29 +137,30 @@ def redraw(self): GL.glUseProgram(self.shader) t = time.time()-self.start s = 2. - p = rot(t*s/5.,t*s/6.,t*s/7.) + p = rot(t*s/5., t*s/6., t*s/7.) GL.glUniformMatrix3fv(self.proj, 1, GL.GL_FALSE, p) - GL.glBindVertexArray( self.vertex_array_object ) + GL.glBindVertexArray(self.vertex_array_object) GL.glDrawArrays(GL.GL_POINTS, 0, NPTS) - GL.glBindVertexArray( 0 ) - GL.glUseProgram( 0 ) - GL.glRasterPos2f(-0.99,-0.99); + GL.glBindVertexArray(0) + GL.glUseProgram(0) + GL.glRasterPos2f(-0.99, -0.99) if self.nframes > 1: t = time.time()-self.start - fps = "fps: %5.2f frames: %d"%(self.nframes / t, self.nframes) -# for c in fps: -# GLUT.glutBitmapCharacter(GLUT.GLUT_BITMAP_HELVETICA_18, ord(c)); + fps = "fps: %5.2f frames: %d" % (self.nframes / t, self.nframes) + # for c in fps: + # GLUT.glutBitmapCharacter(GLUT.GLUT_BITMAP_HELVETICA_18, ord(c)); self.nframes += 1 def main(): root = tk.Tk() - app = ShaderFrame(root, width=512,height=512) + app = ShaderFrame(root, width=512, height=512) app.pack(fill=tk.BOTH, expand=tk.YES) app.after(100, app.printContext) - app.animate=1000//60 - app.animate=1 + app.animate = 1000 // 60 + app.animate = 1 app.mainloop() + + if __name__ == '__main__': main() -