PageRenderTime 294ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/gl/renderer.py

https://bitbucket.org/dexteris/forma
Python | 442 lines | 356 code | 49 blank | 37 comment | 49 complexity | 6db8c260f83febc8ed04a1455c8377fd MD5 | raw file
  1. # Copyright (c) 2010 Galen Clark Haynes
  2. # 2010 Dexteris Robotics, LLC
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright
  11. # notice, this list of conditions and the following disclaimer in the
  12. # documentation and/or other materials provided with the distribution.
  13. # * Neither the name of Dexteris Robotics, LLC nor the names of its
  14. # contributors may be used to endorse or promote products derived from
  15. # this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. # POSSIBILITY OF SUCH DAMAGE.
  28. from OpenGL.GL import *
  29. from OpenGL.GLU import *
  30. from OpenGL.GLUT import *
  31. import math
  32. import time
  33. from forma.common import Forma
  34. class GLRenderer(object):
  35. def __init__(self, viewport):
  36. self.viewport = viewport
  37. glEnable(GL_NORMALIZE)
  38. glEnable(GL_DEPTH_TEST)
  39. glDepthFunc(GL_LEQUAL);
  40. glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  41. #glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  42. glEnable(GL_BLEND)
  43. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  44. glShadeModel(GL_SMOOTH)
  45. LightAmbient= [0.5, 0.5, 0.5, 1.0]
  46. LightDiffuse = [1.0, 1.0, 1.0, 1.0]
  47. LightSpecular = [0.5, 0.5, 0.5, 1.0]
  48. LightSpecular = LightDiffuse
  49. LightPosition = [1.5, -1.5, 1.0, 1.0]
  50. glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
  51. glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
  52. glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);
  53. glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
  54. glEnable(GL_LIGHT1);
  55. glEnable(GL_LIGHTING);
  56. glClearColor(0.2,0.2,0.2,1.0)
  57. MatAmbientDiffuse = [0.5, 0.5, 0.5, 1.0]
  58. MatSpecular = [0.5,0.5,0.5,1.0]
  59. MatEmission = [0.05,0.05,0.05,1.0]
  60. MatShininess = 25
  61. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, MatAmbientDiffuse);
  62. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MatSpecular)
  63. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, MatEmission);
  64. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MatShininess);
  65. self.do_grid = False
  66. self.grid_spacing = [1.0,1.0,0.1]
  67. self.grid_span = [5.0,5.0,1.5]
  68. self.top_text = 'Forma by Dexteris Robotics'
  69. def enable_grid(self):
  70. self.do_grid = True
  71. def disable_grid(self):
  72. self.do_grid = False
  73. def do_render(self,fobj):
  74. self.pre_render(fobj)
  75. for f in fobj.attachments:
  76. self.do_render(f)
  77. self.post_render(fobj)
  78. def pre_render(self,fobj):
  79. try:
  80. glPushMatrix()
  81. except GLerror, error:
  82. print error
  83. sys.exit(-1)
  84. #super(type(self),self).pre_render(fobj)
  85. if not hasattr(fobj,'_glforma'):
  86. create_glforma(fobj)
  87. fobj._glforma.pre_render()
  88. def post_render(self,fobj):
  89. #super(type(self),self).post_render(fobj)
  90. fobj._glforma.post_render()
  91. glPopMatrix()
  92. def render(self, scene):
  93. self.do_perspective()
  94. glLoadIdentity()
  95. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  96. if self.do_grid:
  97. self.draw_grid(self.grid_spacing,self.grid_span)
  98. if self.top_text != None:
  99. self.draw_text(0,10,self.top_text)
  100. try:
  101. glPushMatrix()
  102. except Exception, error:
  103. print error
  104. sys.exit(-1)
  105. try:
  106. self.do_render(scene)
  107. except Exception, e:
  108. import traceback
  109. traceback.print_tb(sys.exc_info()[2])
  110. print e
  111. sys.exit(-1)
  112. glPopMatrix()
  113. def draw_text(self,*args):
  114. glPushMatrix()
  115. if len(args) > 3:
  116. glRasterPos3d(args[0],args[1],args[2])
  117. else:
  118. self.do_orthographic()
  119. glRasterPos2d(args[0],args[1])
  120. text = args[-1]
  121. for c in text:
  122. glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10,ord(c))
  123. glPopMatrix()
  124. if len(args) == 3:
  125. self.do_perspective()
  126. def do_orthographic(self):
  127. glMatrixMode(GL_PROJECTION)
  128. glLoadIdentity()
  129. gluOrtho2D(0,self.viewport.width,0,self.viewport.height)
  130. glScalef(1,-1,1)
  131. glTranslatef(0,-self.viewport.height,0)
  132. glMatrixMode(GL_MODELVIEW)
  133. def do_perspective(self):
  134. glMatrixMode(GL_PROJECTION)
  135. glLoadIdentity()
  136. gluPerspective(70,float(self.viewport.width)/float(self.viewport.height),0.01,100)
  137. deg2rad = math.pi / 180.
  138. global lookAt
  139. upVec = [0,0,1]
  140. eyePos = self.viewport.controller.eye()
  141. lookAt = self.viewport.controller.center
  142. gluLookAt(eyePos[0],eyePos[1],eyePos[2],lookAt[0],lookAt[1],lookAt[2],upVec[0],upVec[1],upVec[2])
  143. glMatrixMode(GL_MODELVIEW)
  144. def draw_grid(self,spacing,span):
  145. global lookAt
  146. x = span[0] / 2.0
  147. xs = spacing[0]
  148. y = span[1] / 2.0
  149. ys = spacing[1]
  150. z = span[2] / 2.0
  151. zs = spacing[2] # draw single line in Z direction
  152. glBegin(GL_LINES)
  153. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, [0.5,0.5,0.5,1.0]);
  154. glVertex(lookAt[0],lookAt[1],lookAt[2]-z)
  155. glVertex(lookAt[0],lookAt[1],lookAt[2]+z)
  156. notchpos = math.ceil((lookAt[2]-z) / zs) * zs;
  157. while notchpos < lookAt[2]+z:
  158. glVertex(lookAt[0]-spacing[0]/20.0,lookAt[1],notchpos)
  159. glVertex(lookAt[0]+spacing[0]/20.0,lookAt[1],notchpos)
  160. glVertex(lookAt[0],lookAt[1]-spacing[0]/20.0,notchpos)
  161. glVertex(lookAt[0],lookAt[1]+spacing[0]/20.0,notchpos)
  162. notchpos += zs
  163. minx = math.ceil((lookAt[0]-x) / xs) * xs
  164. miny = math.ceil((lookAt[1]-y) / ys) * ys
  165. maxx = math.floor((lookAt[0]+x) / xs) * xs
  166. maxy = math.ceil((lookAt[1]+y) / ys) * ys
  167. notchpos = minx
  168. while notchpos <= maxx:
  169. glVertex(notchpos,miny,lookAt[2])
  170. glVertex(notchpos,maxy,lookAt[2])
  171. notchpos += xs
  172. notchpos = miny
  173. while notchpos <= maxy:
  174. glVertex(minx,notchpos,lookAt[2])
  175. glVertex(maxx,notchpos,lookAt[2])
  176. notchpos += ys
  177. glEnd()
  178. notchpos = math.ceil((lookAt[2]-z) / zs) * zs
  179. while notchpos < lookAt[2]+z:
  180. self.draw_text(lookAt[0],lookAt[1],notchpos,'%.1f' % notchpos)
  181. notchpos += zs
  182. def create_glforma(fobj):
  183. """
  184. Switchyard function
  185. """
  186. fobj_type = type(fobj).__name__
  187. # fixme, there should be a way to do this by adding 'GL' to fobj_type
  188. if fobj_type is 'Box':
  189. globj = GLBox(fobj)
  190. elif fobj_type is 'Cylinder':
  191. globj = GLCylinder(fobj)
  192. elif fobj_type is 'Polygon':
  193. globj = GLPolygon(fobj)
  194. elif fobj_type is 'Circle':
  195. globj = GLCircle(fobj)
  196. elif fobj_type is 'Sphere':
  197. globj = GLSphere(fobj)
  198. elif fobj_type is 'Cone':
  199. globj = GLCone(fobj)
  200. elif fobj_type is 'Transformation':
  201. globj = GLTransformation(fobj)
  202. elif fobj_type is 'Translation':
  203. globj = GLTranslation(fobj)
  204. elif fobj_type is 'Rotation':
  205. globj = GLRotation(fobj)
  206. elif fobj_type is 'LineTrace':
  207. globj = GLLineTrace(fobj)
  208. elif fobj_type is 'Label':
  209. globj = GLLabel(fobj)
  210. else:
  211. #print 'object %s not known, using default GLForma' % fobj_type
  212. globj = GLForma(fobj)
  213. class GLForma(object):
  214. def __init__(self,fobj):
  215. #print 'CREATED GL OBJECT: %s' % type(fobj).__name__
  216. self._forma = fobj
  217. fobj._glforma = self
  218. def pre_render(self):
  219. pass
  220. def post_render(self):
  221. pass
  222. def set_color(self):
  223. if hasattr(self._forma,'color'):
  224. if len(self._forma.color) == 3:
  225. self._forma.color = [self._forma.color[0],self._forma.color[1],self._forma.color[2],1.0]
  226. color = self._forma.color
  227. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
  228. else:
  229. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, [0.5,0.5,0.5,1.0]);
  230. class GLTransformation(GLForma):
  231. def __init__(self,fobj):
  232. super(type(self),self).__init__(fobj)
  233. def pre_render(self):
  234. glPushMatrix()
  235. # glMultMatrix wants column major. Numpy by default will use row-major when flattening, so do it manually
  236. glMultMatrixf(self._forma.transmat.flatten('F'))
  237. def post_render(self):
  238. glPopMatrix()
  239. class GLTranslation(GLForma):
  240. def __init__(self,fobj):
  241. super(type(self),self).__init__(fobj)
  242. def pre_render(self):
  243. glPushMatrix()
  244. x,y,z = self._forma.x, self._forma.y, self._forma.z
  245. glTranslatef(x,y,z)
  246. def post_render(self):
  247. glPopMatrix()
  248. class GLRotation(GLForma):
  249. def __init__(self,fobj):
  250. super(type(self),self).__init__(fobj)
  251. def pre_render(self):
  252. import numpy
  253. rotmat = self._forma.rotmat
  254. x,y,z = self._forma.x, self._forma.y, self._forma.z
  255. x *= 180./math.pi
  256. y *= 180./math.pi
  257. z *= 180./math.pi
  258. glPushMatrix()
  259. if (x != 0.0 or y != 0.0 or z != 0.0):
  260. glRotatef(x,1.,0.,0.)
  261. glRotatef(y,0.,1.,0.)
  262. glRotatef(z,0.,0.,1.)
  263. else:
  264. t = numpy.eye(4)
  265. t[0:3,0:3] = rotmat
  266. glMultMatrixf(t.flatten('F'))
  267. def post_render(self):
  268. glPopMatrix()
  269. class GLPolygon(GLForma):
  270. def __init__(self,fobj):
  271. super(type(self),self).__init__(fobj)
  272. def pre_render(self):
  273. points = self._forma.points
  274. normal = self._forma.normal
  275. self.set_color()
  276. glBegin(GL_POLYGON)
  277. glNormal3fv(normal)
  278. for i in xrange(points.shape[1]):
  279. glVertex3f(points[0,i],points[1,i],points[2,i])
  280. glVertex3f(points[0,0],points[1,0],points[2,i])
  281. glEnd()
  282. class GLCircle(GLForma):
  283. def __init__(self,fobj):
  284. super(type(self),self).__init__(fobj)
  285. def pre_render(self):
  286. import numpy
  287. arc = self._forma.arc
  288. radius = self._forma.radius
  289. self.set_color()
  290. subdiv = 30
  291. subdiv = int(subdiv * arc / (2.0*math.pi))
  292. if subdiv < 4:
  293. subdiv = 4
  294. angleset = numpy.linspace(0,arc,subdiv)
  295. glBegin(GL_POLYGON)
  296. glNormal3f(0.0,0.0,1.0)
  297. for a in angleset:
  298. glVertex3f(radius*math.cos(a),radius*math.sin(a),0.0)
  299. glEnd()
  300. class GLSphere(GLForma):
  301. def __init__(self,fobj):
  302. super(type(self),self).__init__(fobj)
  303. def pre_render(self):
  304. r = self._forma.radius
  305. self.set_color()
  306. glutSolidSphere(r,30,30)
  307. class GLCone(GLForma):
  308. def __init__(self,fobj):
  309. super(type(self),self).__init__(fobj)
  310. def pre_render(self):
  311. r = self._forma.radius
  312. h = self._forma.height
  313. if (r != self._forma.c.radius):
  314. self._forma.c.radius = r
  315. self.set_color()
  316. glutSolidCone(r,h,30,5)
  317. class GLBox(GLForma):
  318. def __init__(self,fobj):
  319. super(type(self),self).__init__(fobj)
  320. def pre_render(self):
  321. w = self._forma.width
  322. h = self._forma.height
  323. l = self._forma.length
  324. self.set_color()
  325. glBegin(GL_QUADS)
  326. for side in [-w/2,w/2]:
  327. glNormal3f(side/(w/2),0,0)
  328. glVertex3f(side,l/2,h/2)
  329. glVertex3f(side,-l/2,h/2)
  330. glVertex3f(side,-l/2,-h/2)
  331. glVertex3f(side,l/2,-h/2)
  332. for height in [-h/2,h/2]:
  333. glNormal3f(0,0,height/(h/2));
  334. glVertex3f(w/2,l/2,height)
  335. glVertex3f(-w/2,l/2,height)
  336. glVertex3f(-w/2,-l/2,height)
  337. glVertex3f(w/2,-l/2,height)
  338. for length in [-l/2, l/2]:
  339. glNormal3f(0,length/(l/2),0);
  340. glVertex3f(w/2,length,h/2)
  341. glVertex3f(w/2,length,-h/2)
  342. glVertex3f(-w/2,length,-h/2)
  343. glVertex3f(-w/2,length,h/2)
  344. glEnd()
  345. class GLCylinder(GLForma):
  346. def __init__(self,fobj):
  347. super(type(self),self).__init__(fobj)
  348. def pre_render(self):
  349. import numpy
  350. radius = self._forma.radius
  351. height = self._forma.height
  352. arc = self._forma.arc
  353. self.set_color()
  354. subdiv = 30
  355. subdiv = int(subdiv * arc / (2.0*math.pi))
  356. if subdiv < 4:
  357. subdiv = 4
  358. angleset = numpy.linspace(0,arc,subdiv)
  359. glBegin(GL_QUAD_STRIP)
  360. count = 0
  361. for a in angleset:
  362. normal_angle = angleset[count]
  363. glNormal3f(math.cos(normal_angle),math.sin(normal_angle),0.0)
  364. for s in [-height/2,height/2]:
  365. glVertex3f(radius*math.cos(a),radius*math.sin(a),s)
  366. count += 1
  367. glEnd()
  368. class GLLineTrace(GLForma):
  369. def __init__(self,fobj):
  370. super(type(self),self).__init__(fobj)
  371. def pre_render(self):
  372. x_trace = self._forma.x_trace
  373. y_trace = self._forma.y_trace
  374. z_trace = self._forma.z_trace
  375. self.set_color()
  376. glBegin(GL_LINE_STRIP)
  377. for i in range(len(x_trace)):
  378. glVertex3f(x_trace[i],y_trace[i],z_trace[i])
  379. glEnd()
  380. class GLLabel(GLForma):
  381. def __init__(self,fobj):
  382. super(type(self),self).__init__(fobj)
  383. def pre_render(self):
  384. x = self._forma.x
  385. y = self._forma.y
  386. z = self._forma.z
  387. label = self._forma.label
  388. self.set_color()
  389. glPushMatrix()
  390. glRasterPos3d(x,y,z)
  391. for c in label:
  392. glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10,ord(c))
  393. glPopMatrix()