home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / OpenGL / Tk / __init__.py
Encoding:
Python Source  |  2008-12-07  |  13.3 KB  |  559 lines

  1. #!/usr/bin/env python
  2.  
  3. # This is statement is required by the build system to query build info
  4. if __name__ == '__build__':
  5.     raise Exception
  6.  
  7. # A class that creates an opengl widget.
  8. # Mike Hartshorn
  9. # Department of Chemistry
  10. # University of York, UK
  11.  
  12. from OpenGL.GL import *
  13. from OpenGL.GLU import *
  14. from Tkinter import _default_root
  15. from Tkinter import *
  16. import math
  17. import os,sys
  18.  
  19. #
  20.  
  21. def glTranslateScene(s, x, y, mousex, mousey):
  22.     glMatrixMode(GL_MODELVIEW)
  23.     mat = glGetDoublev(GL_MODELVIEW_MATRIX)
  24.     glLoadIdentity()
  25.     glTranslatef(s * (x - mousex), s * (mousey - y), 0.0)
  26.     glMultMatrixd(mat)
  27.  
  28.  
  29. def glRotateScene(s, xcenter, ycenter, zcenter, x, y, mousex, mousey):
  30.     glMatrixMode(GL_MODELVIEW)
  31.     mat = glGetDoublev(GL_MODELVIEW_MATRIX)
  32.     glLoadIdentity()
  33.     glTranslatef(xcenter, ycenter, zcenter)
  34.     glRotatef(s * (y - mousey), 1., 0., 0.)
  35.     glRotatef(s * (x - mousex), 0., 1., 0.)
  36.     glTranslatef(-xcenter, -ycenter, -zcenter)
  37.     glMultMatrixd(mat)
  38.  
  39.  
  40. def sub(x, y):
  41.     return map(lambda a, b: a-b, x, y)
  42.  
  43.  
  44. def dot(x, y):
  45.     t = 0
  46.     for i in range(len(x)):
  47.         t = t + x[i]*y[i]
  48.     return t
  49.  
  50.  
  51. def glDistFromLine(x, p1, p2):
  52.     f = map(lambda x, y: x-y, p2, p1)
  53.     g = map(lambda x, y: x-y, x, p1)
  54.     return dot(g, g) - dot(f, g)**2/dot(f, f)
  55.  
  56.  
  57. # Keith Junius <junius@chem.rug.nl> provided many changes to Togl
  58. TOGL_NORMAL = 1
  59. TOGL_OVERLAY = 2
  60.  
  61. def v3distsq(a,b):
  62.     d = ( a[0] - b[0], a[1] - b[1], a[2] - b[2] )
  63.     return d[0]*d[0] + d[1]*d[1] + d[2]*d[2]
  64.  
  65. # new version from Daniel Faken (Daniel_Faken@brown.edu) for static 
  66. # loading comptability
  67. if _default_root is None:
  68.     _default_root = Tk()
  69.  
  70. # add this file's directory to Tcl's search path
  71. # on Linux Togl is installed in ./linux2-tk8.0
  72. # on Windows (Python2.0) in ./win32-tk8.3  
  73. try:
  74.     TOGL_DLL_PATH = os.path.join(
  75.         os.path.dirname(__file__),
  76.         sys.platform + "-tk" + _default_root.getvar("tk_version")
  77.     )
  78. except NameError, err:
  79.     # no __file__, likely running as an egg
  80.     TOGL_DLL_PATH = ""
  81. _default_root.tk.call('lappend', 'auto_path', TOGL_DLL_PATH)
  82. try:
  83.     _default_root.tk.eval('load {} Togl')
  84. except TclError:
  85.     pass
  86. _default_root.tk.call('package', 'require', 'Togl')
  87.  
  88. # This code is needed to avoid faults on sys.exit()
  89. # [DAA, Jan 1998]
  90. import sys
  91. oldexitfunc = None
  92. if hasattr(sys, 'exitfunc'):
  93.     oldexitfunc = sys.exitfunc
  94. def cleanup():
  95.     from Tkinter import _default_root, TclError
  96.     import Tkinter
  97.     try: 
  98.         if _default_root: _default_root.destroy()
  99.     except TclError:
  100.         pass
  101.     Tkinter._default_root = None
  102.     if oldexitfunc: oldexitfunc()
  103. sys.exitfunc = cleanup
  104. # [end DAA]
  105.  
  106. class Togl(Widget):
  107.     """
  108.     Togl Widget
  109.     Keith Junius
  110.     Department of Biophysical Chemistry
  111.     University of Groningen, The Netherlands
  112.     Very basic widget which provides access to Togl functions.
  113.     N.B. this requires a modified version of Togl 1.5 to gain access to the
  114.     extra functionality. This support should be included in Togl 1.6, I hope.
  115.     """
  116.  
  117.  
  118.     def __init__(self, master=None, cnf={}, **kw):
  119.         Widget.__init__(self, master, 'togl', cnf, kw)
  120.  
  121.  
  122.     def render(self):
  123.         return
  124.  
  125.  
  126.     def swapbuffers(self):
  127.         self.tk.call(self._w, 'swapbuffers')
  128.  
  129.  
  130.     def makecurrent(self):
  131.         self.tk.call(self._w, 'makecurrent')
  132.  
  133.  
  134.     def alloccolor(self, red, green, blue):
  135.         return self.tk.getint(self.tk.call(self._w, 'alloccolor', red, green, blue))
  136.  
  137.  
  138.     def freecolor(self, index):
  139.         self.tk.call(self._w, 'freecolor', index)
  140.  
  141.  
  142.     def setcolor(self, index, red, green, blue):
  143.         self.tk.call(self._w, 'setcolor', index, red, green, blue)
  144.  
  145.  
  146.     def loadbitmapfont(self, fontname):
  147.         return self.tk.getint(self.tk.call(self._w, 'loadbitmapfont', fontname))
  148.  
  149.  
  150.     def unloadbitmapfont(self, fontbase):
  151.         self.tk.call(self._w, 'unloadbitmapfont', fontbase)
  152.  
  153.  
  154.     def uselayer(self, layer):
  155.         self.tk.call(self._w, 'uselayer', layer)
  156.  
  157.  
  158.     def showoverlay(self):
  159.         self.tk.call(self._w, 'showoverlay')
  160.  
  161.  
  162.     def hideoverlay(self):
  163.         self.tk.call(self._w, 'hideoverlay')
  164.  
  165.  
  166.     def existsoverlay(self):
  167.         return self.tk.getboolean(self.tk.call(self._w, 'existsoverlay'))
  168.  
  169.  
  170.     def getoverlaytransparentvalue(self):
  171.         return self.tk.getint(self.tk.call(self._w, 'getoverlaytransparentvalue'))
  172.  
  173.  
  174.     def ismappedoverlay(self):
  175.         return self.tk.getboolean(self.tk.call(self._w, 'ismappedoverlay'))
  176.  
  177.  
  178.     def alloccoloroverlay(self, red, green, blue):
  179.         return self.tk.getint(self.tk.call(self._w, 'alloccoloroverlay', red, green, blue))
  180.  
  181.  
  182.     def freecoloroverlay(self, index):
  183.         self.tk.call(self._w, 'freecoloroverlay', index)
  184.  
  185.  
  186.  
  187. class RawOpengl(Widget, Misc):
  188.     """Widget without any sophisticated bindings\
  189.     by Tom Schwaller"""
  190.  
  191.  
  192.     def __init__(self, master=None, cnf={}, **kw):
  193.         Widget.__init__(self, master, 'togl', cnf, kw)
  194.         self.bind('<Map>', self.tkMap)
  195.         self.bind('<Expose>', self.tkExpose)
  196.         self.bind('<Configure>', self.tkExpose)
  197.  
  198.  
  199.     def tkRedraw(self, *dummy):
  200.         # This must be outside of a pushmatrix, since a resize event
  201.         # will call redraw recursively. 
  202.         self.update_idletasks()
  203.         self.tk.call(self._w, 'makecurrent')
  204.         _mode = glGetDoublev(GL_MATRIX_MODE)
  205.         try:
  206.             glMatrixMode(GL_PROJECTION)
  207.             glPushMatrix()
  208.             try:
  209.                 self.redraw()
  210.                 glFlush()
  211.             finally:
  212.                 glPopMatrix()
  213.         finally:
  214.             glMatrixMode(_mode)
  215.         self.tk.call(self._w, 'swapbuffers')
  216.  
  217.  
  218.     def tkMap(self, *dummy):
  219.         self.tkExpose()
  220.  
  221.  
  222.     def tkExpose(self, *dummy):
  223.         self.tkRedraw()
  224.  
  225.  
  226.  
  227.  
  228. class Opengl(RawOpengl):
  229.     """\
  230. Tkinter bindings for an Opengl widget.
  231. Mike Hartshorn
  232. Department of Chemistry
  233. University of York, UK
  234. http://www.yorvic.york.ac.uk/~mjh/
  235. """
  236.  
  237.     def __init__(self, master=None, cnf={}, **kw):
  238.         """\
  239.         Create an opengl widget.
  240.         Arrange for redraws when the window is exposed or when
  241.         it changes size."""
  242.  
  243.         #Widget.__init__(self, master, 'togl', cnf, kw)
  244.         apply(RawOpengl.__init__, (self, master, cnf), kw)
  245.         self.initialised = 0
  246.  
  247.         # Current coordinates of the mouse.
  248.         self.xmouse = 0
  249.         self.ymouse = 0
  250.  
  251.         # Where we are centering.
  252.         self.xcenter = 0.0
  253.         self.ycenter = 0.0
  254.         self.zcenter = 0.0
  255.  
  256.         # The _back color
  257.         self.r_back = 1.
  258.         self.g_back = 0.
  259.         self.b_back = 1.
  260.  
  261.         # Where the eye is
  262.         self.distance = 10.0
  263.  
  264.         # Field of view in y direction
  265.         self.fovy = 30.0
  266.  
  267.         # Position of clipping planes.
  268.         self.near = 0.1
  269.         self.far = 1000.0
  270.  
  271.         # Is the widget allowed to autospin?
  272.         self.autospin_allowed = 0
  273.  
  274.         # Is the widget currently autospinning?
  275.         self.autospin = 0
  276.  
  277.         # Basic bindings for the virtual trackball
  278.         self.bind('<Map>', self.tkMap)
  279.         self.bind('<Expose>', self.tkExpose)
  280.         self.bind('<Configure>', self.tkExpose)
  281.         self.bind('<Shift-Button-1>', self.tkHandlePick)
  282.         #self.bind('<Button-1><ButtonRelease-1>', self.tkHandlePick)
  283.         self.bind('<Button-1>', self.tkRecordMouse)
  284.         self.bind('<B1-Motion>', self.tkTranslate)
  285.         self.bind('<Button-2>', self.StartRotate)
  286.         self.bind('<B2-Motion>', self.tkRotate)
  287.         self.bind('<ButtonRelease-2>', self.tkAutoSpin)
  288.         self.bind('<Button-3>', self.tkRecordMouse)
  289.         self.bind('<B3-Motion>', self.tkScale)
  290.  
  291.  
  292.     def help(self):
  293.         """Help for the widget."""
  294.  
  295.         import Dialog
  296.         d = Dialog.Dialog(None, {'title': 'Viewer help',
  297.                                  'text': 'Button-1: Translate\n'
  298.                                          'Button-2: Rotate\n'
  299.                                          'Button-3: Zoom\n'
  300.                                          'Reset: Resets transformation to identity\n',
  301.                                  'bitmap': 'questhead',
  302.                                  'default': 0,
  303.                                  'strings': ('Done', 'Ok')})
  304.  
  305.  
  306.     def activate(self):
  307.         """Cause this Opengl widget to be the current destination for drawing."""
  308.  
  309.         self.tk.call(self._w, 'makecurrent')
  310.  
  311.  
  312.     # This should almost certainly be part of some derived class.
  313.     # But I have put it here for convenience.
  314.     def basic_lighting(self):
  315.         """\
  316.         Set up some basic lighting (single infinite light source).
  317.  
  318.         Also switch on the depth buffer."""
  319.    
  320.         self.activate()
  321.         light_position = (1, 1, 1, 0)
  322.         glLightfv(GL_LIGHT0, GL_POSITION, light_position)
  323.         glEnable(GL_LIGHTING)
  324.         glEnable(GL_LIGHT0)
  325.         glDepthFunc(GL_LESS)
  326.         glEnable(GL_DEPTH_TEST)
  327.         glMatrixMode(GL_MODELVIEW)
  328.         glLoadIdentity()
  329.  
  330.  
  331.     def report_opengl_errors(message = "OpenGL error:"):
  332.         """Report any opengl errors that occured while drawing."""
  333.  
  334.         print 'report_opengl_errors is now useless.  glGetError replaced by GLexception'
  335. #        while 1:
  336. #            err_value = glGetError()
  337. #            if not err_value: break     
  338. #            print message, gluErrorString(err_value)
  339.  
  340.  
  341.     def set_background(self, r, g, b):
  342.         """Change the background colour of the widget."""
  343.  
  344.         self.r_back = r
  345.         self.g_back = g
  346.         self.b_back = b
  347.  
  348.         self.tkRedraw()
  349.  
  350.  
  351.     def set_centerpoint(self, x, y, z):
  352.         """Set the new center point for the model.
  353.         This is where we are looking."""
  354.  
  355.         self.xcenter = x
  356.         self.ycenter = y
  357.         self.zcenter = z
  358.  
  359.         self.tkRedraw()
  360.  
  361.  
  362.     def set_eyepoint(self, distance):
  363.         """Set how far the eye is from the position we are looking."""
  364.  
  365.         self.distance = distance
  366.         self.tkRedraw()
  367.  
  368.  
  369.     def reset(self):
  370.         """Reset rotation matrix for this widget."""
  371.  
  372.         glMatrixMode(GL_MODELVIEW)
  373.         glLoadIdentity()
  374.         self.tkRedraw()
  375.  
  376.  
  377.     def tkHandlePick(self, event):
  378.         """Handle a pick on the scene."""
  379.  
  380.         if hasattr(self, 'pick'):
  381.             # here we need to use glu.UnProject
  382.  
  383.             # Tk and X have their origin top left, 
  384.             # while Opengl has its origin bottom left.
  385.             # So we need to subtract y from the window height to get
  386.             # the proper pick position for Opengl
  387.  
  388.             realy = self.winfo_height() - event.y
  389.  
  390.             p1 = gluUnProject(event.x, realy, 0.)
  391.             p2 = gluUnProject(event.x, realy, 1.)
  392.  
  393.             if self.pick(self, p1, p2):
  394.                 """If the pick method returns true we redraw the scene."""
  395.  
  396.                 self.tkRedraw()
  397.  
  398.  
  399.     def tkRecordMouse(self, event):
  400.         """Record the current mouse position."""
  401.  
  402.         self.xmouse = event.x
  403.         self.ymouse = event.y
  404.  
  405.  
  406.     def StartRotate(self, event):
  407.         # Switch off any autospinning if it was happening
  408.  
  409.         self.autospin = 0
  410.         self.tkRecordMouse(event)
  411.  
  412.  
  413.     def tkScale(self, event):
  414.         """Scale the scene.  Achieved by moving the eye position.
  415.  
  416.         Dragging up zooms in, while dragging down zooms out
  417.         """
  418.         scale = 1 - 0.01 * (event.y - self.ymouse)
  419.         # do some sanity checks, scale no more than
  420.         # 1:1000 on any given click+drag
  421.         if scale < 0.001:
  422.             scale = 0.001
  423.         elif scale > 1000:
  424.             scale = 1000
  425.         self.distance = self.distance * scale
  426.         self.tkRedraw()
  427.         self.tkRecordMouse(event)
  428.  
  429.  
  430.     def do_AutoSpin(self):
  431.         s = 0.5
  432.         self.activate()
  433.  
  434.         glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, self.yspin, self.xspin, 0, 0)
  435.         self.tkRedraw()
  436.  
  437.         if self.autospin:
  438.             self.after(10, self.do_AutoSpin)
  439.  
  440.  
  441.     def tkAutoSpin(self, event):
  442.         """Perform autospin of scene."""
  443.  
  444.         self.after(4)
  445.         self.update_idletasks()
  446.  
  447.         # This could be done with one call to pointerxy but I'm not sure
  448.         # it would any quicker as we would have to split up the resulting
  449.         # string and then conv
  450.  
  451.         x = self.tk.getint(self.tk.call('winfo', 'pointerx', self._w))
  452.         y = self.tk.getint(self.tk.call('winfo', 'pointery', self._w))
  453.  
  454.         if self.autospin_allowed:
  455.             if x != event.x_root and y != event.y_root:
  456.                 self.autospin = 1
  457.  
  458.         self.yspin = x - event.x_root
  459.         self.xspin = y - event.y_root
  460.  
  461.         self.after(10, self.do_AutoSpin)
  462.  
  463.  
  464.     def tkRotate(self, event):
  465.         """Perform rotation of scene."""
  466.  
  467.         self.activate()
  468.         glRotateScene(0.5, self.xcenter, self.ycenter, self.zcenter, event.x, event.y, self.xmouse, self.ymouse)
  469.         self.tkRedraw()
  470.         self.tkRecordMouse(event)
  471.  
  472.  
  473.     def tkTranslate(self, event):
  474.         """Perform translation of scene."""
  475.  
  476.         self.activate()
  477.  
  478.         # Scale mouse translations to object viewplane so object tracks with mouse
  479.         win_height = max( 1,self.winfo_height() )
  480.         obj_c      = ( self.xcenter, self.ycenter, self.zcenter )
  481.         win        = gluProject( obj_c[0], obj_c[1], obj_c[2])
  482.         obj        = gluUnProject( win[0], win[1] + 0.5 * win_height, win[2])
  483.         dist       = math.sqrt( v3distsq( obj, obj_c ) )
  484.         scale      = abs( dist / ( 0.5 * win_height ) )
  485.  
  486.         glTranslateScene(scale, event.x, event.y, self.xmouse, self.ymouse)
  487.         self.tkRedraw()
  488.         self.tkRecordMouse(event)
  489.  
  490.  
  491.     def tkRedraw(self, *dummy):
  492.         """Cause the opengl widget to redraw itself."""
  493.  
  494.         if not self.initialised: return
  495.         self.activate()
  496.  
  497.         glPushMatrix()            # Protect our matrix
  498.         self.update_idletasks()
  499.         self.activate()
  500.         w = self.winfo_width()
  501.         h = self.winfo_height()
  502.         glViewport(0, 0, w, h)
  503.  
  504.         # Clear the background and depth buffer.
  505.         glClearColor(self.r_back, self.g_back, self.b_back, 0.)
  506.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  507.  
  508.         glMatrixMode(GL_PROJECTION)
  509.         glLoadIdentity()
  510.         gluPerspective(self.fovy, float(w)/float(h), self.near, self.far)
  511.  
  512.         if 0:
  513.             # Now translate the scene origin away from the world origin
  514.             glMatrixMode(GL_MODELVIEW)
  515.             mat = glGetDoublev(GL_MODELVIEW_MATRIX)
  516.             glLoadIdentity()
  517.             glTranslatef(-self.xcenter, -self.ycenter, -(self.zcenter+self.distance))
  518.             glMultMatrixd(mat)
  519.         else:
  520.             gluLookAt(self.xcenter, self.ycenter, self.zcenter + self.distance,
  521.                 self.xcenter, self.ycenter, self.zcenter,
  522.                 0., 1., 0.)
  523.             glMatrixMode(GL_MODELVIEW)
  524.     
  525.         # Call objects redraw method.
  526.         self.redraw(self)
  527.         glFlush()                # Tidy up
  528.         glPopMatrix()            # Restore the matrix
  529.  
  530.         self.tk.call(self._w, 'swapbuffers')
  531.     def redraw( self, *args, **named ):
  532.         """Prevent access errors if user doesn't set redraw fast enough"""
  533.  
  534.  
  535.     def tkMap(self, *dummy):
  536.         """Cause the opengl widget to redraw itself."""
  537.  
  538.         self.tkExpose()
  539.  
  540.  
  541.     def tkExpose(self, *dummy):
  542.         """Redraw the widget.
  543.         Make it active, update tk events, call redraw procedure and
  544.         swap the buffers.  Note: swapbuffers is clever enough to
  545.         only swap double buffered visuals."""
  546.  
  547.         self.activate()
  548.         if not self.initialised:
  549.             self.basic_lighting()
  550.             self.initialised = 1
  551.         self.tkRedraw()
  552.  
  553.  
  554.     def tkPrint(self, file):
  555.         """Turn the current scene into PostScript via the feedback buffer."""
  556.  
  557.         self.activate()
  558.