1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
8 from Cura.util.resources import getPathForImage
12 OpenGL.ERROR_CHECKING = False
13 from OpenGL.GLUT import *
14 from OpenGL.GLU import *
15 from OpenGL.GL import *
16 from OpenGL.GL import shaders
17 glutInit() #Hack; required before glut can be called. Not required for all OS.
19 class GLReferenceCounter(object):
28 return self._refCounter <= 0
30 def hasShaderSupport():
31 if bool(glCreateShader):
35 class GLShader(GLReferenceCounter):
36 def __init__(self, vertexProgram, fragmentProgram):
37 super(GLShader, self).__init__()
38 self._vertexString = vertexProgram
39 self._fragmentString = fragmentProgram
41 vertexShader = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
42 fragmentShader = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
44 #shader.compileProgram tries to return the shader program as a overloaded int. But the return value of a shader does not always fit in a int (needs to be a long). So we do raw OpenGL calls.
45 # This is to ensure that this works on intel GPU's
46 # self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
47 self._program = glCreateProgram()
48 glAttachShader(self._program, vertexShader)
49 glAttachShader(self._program, fragmentShader)
50 glLinkProgram(self._program)
51 if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
52 raise RuntimeError("Link failure: %s" % (glGetProgramInfoLog(self._program)))
53 # Validation has to occur *after* linking
54 glValidateProgram(self._program)
55 if glGetProgramiv(self._program, GL_VALIDATE_STATUS) == GL_FALSE:
56 raise RuntimeError("Validation failure: %s"%(glGetProgramInfoLog(self._program)))
57 glDeleteShader(vertexShader)
58 glDeleteShader(fragmentShader)
59 except RuntimeError, e:
64 if self._program is not None:
65 shaders.glUseProgram(self._program)
68 shaders.glUseProgram(0)
71 if self._program is not None:
72 glDeleteProgram(self._program)
75 def setUniform(self, name, value):
76 if self._program is not None:
77 if type(value) is float:
78 glUniform1f(glGetUniformLocation(self._program, name), value)
79 elif type(value) is numpy.matrix:
80 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
82 print 'Unknown type for setUniform: %s' % (str(type(value)))
85 return self._program is not None
87 def getVertexShader(self):
88 return self._vertexString
90 def getFragmentShader(self):
91 return self._fragmentString
94 if self._program is not None and bool(glDeleteProgram):
95 print "Shader was not properly released!"
97 class GLFakeShader(GLReferenceCounter):
99 A Class that acts as an OpenGL shader, but in reality is not one. Used if shaders are not supported.
102 super(GLFakeShader, self).__init__()
105 glEnable(GL_LIGHTING)
107 glEnable(GL_COLOR_MATERIAL)
108 glLightfv(GL_LIGHT0, GL_DIFFUSE, [1,1,1,1])
109 glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,0])
110 glLightfv(GL_LIGHT0, GL_SPECULAR, [0,0,0,0])
113 glDisable(GL_LIGHTING)
118 def setUniform(self, name, value):
124 def getVertexShader(self):
127 def getFragmentShader(self):
130 class GLVBO(GLReferenceCounter):
132 Vertex buffer object. Used for faster rendering.
134 def __init__(self, renderType, vertexArray, normalArray = None, indicesArray = None):
135 super(GLVBO, self).__init__()
136 # TODO: Add size check to see if normal and vertex arrays have same size.
137 self._renderType = renderType
138 if not bool(glGenBuffers): # Fallback if buffers are not supported.
139 self._vertexArray = vertexArray
140 self._normalArray = normalArray
141 self._indicesArray = indicesArray
142 self._size = len(vertexArray)
144 self._hasNormals = self._normalArray is not None
145 self._hasIndices = self._indicesArray is not None
147 self._size = len(indicesArray)
150 self._size = len(vertexArray)
151 self._hasNormals = normalArray is not None
152 self._hasIndices = indicesArray is not None
153 maxVertsPerBuffer = 30000
155 maxVertsPerBuffer = self._size
156 if maxVertsPerBuffer > 0:
157 bufferCount = ((self._size-1) / maxVertsPerBuffer) + 1
158 for n in xrange(0, bufferCount):
160 'buffer': glGenBuffers(1),
161 'size': maxVertsPerBuffer
163 offset = n * maxVertsPerBuffer
164 if n == bufferCount - 1:
165 bufferInfo['size'] = ((self._size - 1) % maxVertsPerBuffer) + 1
166 glBindBuffer(GL_ARRAY_BUFFER, bufferInfo['buffer'])
168 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray[offset:offset+bufferInfo['size']], normalArray[offset:offset+bufferInfo['size']]), 1), GL_STATIC_DRAW)
170 glBufferData(GL_ARRAY_BUFFER, vertexArray[offset:offset+bufferInfo['size']], GL_STATIC_DRAW)
171 glBindBuffer(GL_ARRAY_BUFFER, 0)
172 self._buffers.append(bufferInfo)
174 self._size = len(indicesArray)
175 self._bufferIndices = glGenBuffers(1)
176 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
177 glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
180 glEnableClientState(GL_VERTEX_ARRAY)
181 if self._buffers is None:
182 glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
184 glEnableClientState(GL_NORMAL_ARRAY)
185 glNormalPointer(GL_FLOAT, 0, self._normalArray)
187 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, self._indicesArray)
189 batchSize = 996 #Warning, batchSize needs to be dividable by 4 (quads), 3 (triangles) and 2 (lines). Current value is magic.
190 extraStartPos = int(self._size / batchSize) * batchSize #leftovers.
191 extraCount = self._size - extraStartPos
192 for i in xrange(0, int(self._size / batchSize)):
193 glDrawArrays(self._renderType, i * batchSize, batchSize)
194 glDrawArrays(self._renderType, extraStartPos, extraCount)
196 for info in self._buffers:
197 glBindBuffer(GL_ARRAY_BUFFER, info['buffer'])
199 glEnableClientState(GL_NORMAL_ARRAY)
200 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
201 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
203 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
205 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
206 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
208 glDrawArrays(self._renderType, 0, info['size'])
210 glBindBuffer(GL_ARRAY_BUFFER, 0)
212 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
214 glDisableClientState(GL_VERTEX_ARRAY)
216 glDisableClientState(GL_NORMAL_ARRAY)
219 if self._buffers is not None:
220 for info in self._buffers:
221 glBindBuffer(GL_ARRAY_BUFFER, info['buffer'])
222 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
223 glBindBuffer(GL_ARRAY_BUFFER, 0)
224 glDeleteBuffers(1, [info['buffer']])
227 glBindBuffer(GL_ARRAY_BUFFER, self._bufferIndices)
228 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
229 glBindBuffer(GL_ARRAY_BUFFER, 0)
230 glDeleteBuffers(1, [self._bufferIndices])
231 self._vertexArray = None
232 self._normalArray = None
235 if self._buffers is not None and bool(glDeleteBuffers):
236 print "VBO was not properly released!"
238 def glDrawStringCenter(s):
240 Draw string on current draw pointer position
243 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
245 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
247 def glGetStringSize(s):
249 Get size in pixels of string
253 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
257 def glDrawStringLeft(s):
263 glTranslate(0, 18 * n, 0)
268 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
270 def glDrawStringRight(s):
272 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
274 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
276 def glDrawQuad(x, y, w, h):
278 glTranslatef(x, y, 0)
279 glDisable(GL_TEXTURE_2D)
288 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
289 tx = float(texID % 4) / 4
290 ty = float(int(texID / 4)) / 8
300 glTranslatef(x, y, 0)
301 glEnable(GL_TEXTURE_2D)
303 glTexCoord2f(tx+tsx, ty)
307 glTexCoord2f(tx, ty+tsy)
309 glTexCoord2f(tx+tsx, ty+tsy)
314 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
316 Same as draw texured quad, but without stretching the corners. Useful for resizable windows.
318 tx0 = float(texID % 4) / 4
319 ty0 = float(int(texID / 4)) / 8
320 tx1 = tx0 + 0.25 / 2.0
321 ty1 = ty0 + 0.125 / 2.0
326 glTranslatef(x, y, 0)
327 glEnable(GL_TEXTURE_2D)
330 glTexCoord2f(tx1, ty0)
331 glVertex2f( cornerSize, 0)
332 glTexCoord2f(tx0, ty0)
334 glTexCoord2f(tx0, ty1)
335 glVertex2f( 0, cornerSize)
336 glTexCoord2f(tx1, ty1)
337 glVertex2f( cornerSize, cornerSize)
339 glTexCoord2f(tx2, ty0)
341 glTexCoord2f(tx1, ty0)
342 glVertex2f( w - cornerSize, 0)
343 glTexCoord2f(tx1, ty1)
344 glVertex2f( w - cornerSize, cornerSize)
345 glTexCoord2f(tx2, ty1)
346 glVertex2f( w, cornerSize)
348 glTexCoord2f(tx1, ty1)
349 glVertex2f( cornerSize, h - cornerSize)
350 glTexCoord2f(tx0, ty1)
351 glVertex2f( 0, h - cornerSize)
352 glTexCoord2f(tx0, ty2)
354 glTexCoord2f(tx1, ty2)
355 glVertex2f( cornerSize, h)
357 glTexCoord2f(tx2, ty1)
358 glVertex2f( w, h - cornerSize)
359 glTexCoord2f(tx1, ty1)
360 glVertex2f( w - cornerSize, h - cornerSize)
361 glTexCoord2f(tx1, ty2)
362 glVertex2f( w - cornerSize, h)
363 glTexCoord2f(tx2, ty2)
367 glTexCoord2f(tx1, ty1)
368 glVertex2f( w-cornerSize, cornerSize)
369 glTexCoord2f(tx1, ty1)
370 glVertex2f( cornerSize, cornerSize)
371 glTexCoord2f(tx1, ty1)
372 glVertex2f( cornerSize, h-cornerSize)
373 glTexCoord2f(tx1, ty1)
374 glVertex2f( w-cornerSize, h-cornerSize)
377 glTexCoord2f(tx2, ty1)
378 glVertex2f( w, cornerSize)
379 glTexCoord2f(tx1, ty1)
380 glVertex2f( w-cornerSize, cornerSize)
381 glTexCoord2f(tx1, ty1)
382 glVertex2f( w-cornerSize, h-cornerSize)
383 glTexCoord2f(tx2, ty1)
384 glVertex2f( w, h-cornerSize)
387 glTexCoord2f(tx1, ty1)
388 glVertex2f( cornerSize, cornerSize)
389 glTexCoord2f(tx0, ty1)
390 glVertex2f( 0, cornerSize)
391 glTexCoord2f(tx0, ty1)
392 glVertex2f( 0, h-cornerSize)
393 glTexCoord2f(tx1, ty1)
394 glVertex2f( cornerSize, h-cornerSize)
397 glTexCoord2f(tx1, ty0)
398 glVertex2f( w-cornerSize, 0)
399 glTexCoord2f(tx1, ty0)
400 glVertex2f( cornerSize, 0)
401 glTexCoord2f(tx1, ty1)
402 glVertex2f( cornerSize, cornerSize)
403 glTexCoord2f(tx1, ty1)
404 glVertex2f( w-cornerSize, cornerSize)
407 glTexCoord2f(tx1, ty1)
408 glVertex2f( w-cornerSize, h-cornerSize)
409 glTexCoord2f(tx1, ty1)
410 glVertex2f( cornerSize, h-cornerSize)
411 glTexCoord2f(tx1, ty2)
412 glVertex2f( cornerSize, h)
413 glTexCoord2f(tx1, ty2)
414 glVertex2f( w-cornerSize, h)
417 glDisable(GL_TEXTURE_2D)
420 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
422 Projects window position to 3D space. (gluUnProject). Reimplentation as some drivers crash with the original.
424 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
425 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
426 finalMatrix = npModelMatrix * npProjMatrix
427 finalMatrix = numpy.linalg.inv(finalMatrix)
429 viewport = map(float, viewport)
430 vector = numpy.array([(winx - viewport[0]) / viewport[2] * 2.0 - 1.0, (winy - viewport[1]) / viewport[3] * 2.0 - 1.0, winz * 2.0 - 1.0, 1]).reshape((1,4))
431 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
432 ret = list(vector)[0:3] / vector[3]
435 def convert3x3MatrixTo4x4(matrix):
436 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
438 def loadGLTexture(filename):
439 tex = glGenTextures(1)
440 glBindTexture(GL_TEXTURE_2D, tex)
441 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
443 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
444 rgbData = img.GetData()
445 alphaData = img.GetAlphaData()
446 if alphaData is not None:
448 for i in xrange(0, len(alphaData)):
449 data += rgbData[i*3:i*3+3] + alphaData[i]
450 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
452 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
455 def DrawBox(vMin, vMax):
456 """ Draw wireframe box
458 glBegin(GL_LINE_LOOP)
459 glVertex3f(vMin[0], vMin[1], vMin[2])
460 glVertex3f(vMax[0], vMin[1], vMin[2])
461 glVertex3f(vMax[0], vMax[1], vMin[2])
462 glVertex3f(vMin[0], vMax[1], vMin[2])
465 glBegin(GL_LINE_LOOP)
466 glVertex3f(vMin[0], vMin[1], vMax[2])
467 glVertex3f(vMax[0], vMin[1], vMax[2])
468 glVertex3f(vMax[0], vMax[1], vMax[2])
469 glVertex3f(vMin[0], vMax[1], vMax[2])
472 glVertex3f(vMin[0], vMin[1], vMin[2])
473 glVertex3f(vMin[0], vMin[1], vMax[2])
474 glVertex3f(vMax[0], vMin[1], vMin[2])
475 glVertex3f(vMax[0], vMin[1], vMax[2])
476 glVertex3f(vMax[0], vMax[1], vMin[2])
477 glVertex3f(vMax[0], vMax[1], vMax[2])
478 glVertex3f(vMin[0], vMax[1], vMin[2])
479 glVertex3f(vMin[0], vMax[1], vMax[2])