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 # Validation has to occur *after* linking
52 glValidateProgram(self._program)
53 if glGetProgramiv(self._program, GL_VALIDATE_STATUS) == GL_FALSE:
54 raise RuntimeError("Validation failure: %s"%(glGetProgramInfoLog(self._program)))
55 if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
56 raise RuntimeError("Link 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 self._renderType = renderType
137 if not bool(glGenBuffers): # Fallback if buffers are not supported.
138 self._vertexArray = vertexArray
139 self._normalArray = normalArray
140 self._indicesArray = indicesArray
141 self._size = len(vertexArray)
143 self._hasNormals = self._normalArray is not None
144 self._hasIndices = self._indicesArray is not None
146 self._size = len(indicesArray)
148 self._buffer = glGenBuffers(1)
149 self._size = len(vertexArray)
150 self._hasNormals = normalArray is not None
151 self._hasIndices = indicesArray is not None
152 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
153 if self._hasNormals: #TODO: Add size check to see if arrays have same size.
154 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
156 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
157 glBindBuffer(GL_ARRAY_BUFFER, 0)
159 self._size = len(indicesArray)
160 self._bufferIndices = glGenBuffers(1)
161 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
162 glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
165 glEnableClientState(GL_VERTEX_ARRAY)
166 if self._buffer is None:
167 glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
169 glEnableClientState(GL_NORMAL_ARRAY)
170 glNormalPointer(GL_FLOAT, 0, self._normalArray)
172 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
174 glEnableClientState(GL_NORMAL_ARRAY)
175 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
176 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
178 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
180 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
183 if self._buffer is None:
184 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, self._indicesArray)
186 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
188 batchSize = 996 #Warning, batchSize needs to be dividable by 4 (quads), 3 (triangles) and 2 (lines). Current value is magic.
189 extraStartPos = int(self._size / batchSize) * batchSize #leftovers.
190 extraCount = self._size - extraStartPos
191 for i in xrange(0, int(self._size / batchSize)):
192 glDrawArrays(self._renderType, i * batchSize, batchSize)
193 glDrawArrays(self._renderType, extraStartPos, extraCount)
195 if self._buffer is not None:
196 glBindBuffer(GL_ARRAY_BUFFER, 0)
198 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
200 glDisableClientState(GL_VERTEX_ARRAY)
202 glDisableClientState(GL_NORMAL_ARRAY)
205 if self._buffer is not None:
206 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
207 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
208 glBindBuffer(GL_ARRAY_BUFFER, 0)
209 glDeleteBuffers(1, [self._buffer])
212 glBindBuffer(GL_ARRAY_BUFFER, self._bufferIndices)
213 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
214 glBindBuffer(GL_ARRAY_BUFFER, 0)
215 glDeleteBuffers(1, [self._bufferIndices])
216 self._vertexArray = None
217 self._normalArray = None
220 if self._buffer is not None and bool(glDeleteBuffers):
221 print "VBO was not properly released!"
223 def glDrawStringCenter(s):
225 Draw string on current draw pointer position
228 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
230 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
232 def glGetStringSize(s):
234 Get size in pixels of string
238 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
242 def glDrawStringLeft(s):
248 glTranslate(0, 18 * n, 0)
253 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
255 def glDrawStringRight(s):
257 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
259 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
261 def glDrawQuad(x, y, w, h):
263 glTranslatef(x, y, 0)
264 glDisable(GL_TEXTURE_2D)
273 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
274 tx = float(texID % 4) / 4
275 ty = float(int(texID / 4)) / 8
285 glTranslatef(x, y, 0)
286 glEnable(GL_TEXTURE_2D)
288 glTexCoord2f(tx+tsx, ty)
292 glTexCoord2f(tx, ty+tsy)
294 glTexCoord2f(tx+tsx, ty+tsy)
299 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
301 Same as draw texured quad, but without stretching the corners. Useful for resizable windows.
303 tx0 = float(texID % 4) / 4
304 ty0 = float(int(texID / 4)) / 8
305 tx1 = tx0 + 0.25 / 2.0
306 ty1 = ty0 + 0.125 / 2.0
311 glTranslatef(x, y, 0)
312 glEnable(GL_TEXTURE_2D)
315 glTexCoord2f(tx1, ty0)
316 glVertex2f( cornerSize, 0)
317 glTexCoord2f(tx0, ty0)
319 glTexCoord2f(tx0, ty1)
320 glVertex2f( 0, cornerSize)
321 glTexCoord2f(tx1, ty1)
322 glVertex2f( cornerSize, cornerSize)
324 glTexCoord2f(tx2, ty0)
326 glTexCoord2f(tx1, ty0)
327 glVertex2f( w - cornerSize, 0)
328 glTexCoord2f(tx1, ty1)
329 glVertex2f( w - cornerSize, cornerSize)
330 glTexCoord2f(tx2, ty1)
331 glVertex2f( w, cornerSize)
333 glTexCoord2f(tx1, ty1)
334 glVertex2f( cornerSize, h - cornerSize)
335 glTexCoord2f(tx0, ty1)
336 glVertex2f( 0, h - cornerSize)
337 glTexCoord2f(tx0, ty2)
339 glTexCoord2f(tx1, ty2)
340 glVertex2f( cornerSize, h)
342 glTexCoord2f(tx2, ty1)
343 glVertex2f( w, h - cornerSize)
344 glTexCoord2f(tx1, ty1)
345 glVertex2f( w - cornerSize, h - cornerSize)
346 glTexCoord2f(tx1, ty2)
347 glVertex2f( w - cornerSize, h)
348 glTexCoord2f(tx2, ty2)
352 glTexCoord2f(tx1, ty1)
353 glVertex2f( w-cornerSize, cornerSize)
354 glTexCoord2f(tx1, ty1)
355 glVertex2f( cornerSize, cornerSize)
356 glTexCoord2f(tx1, ty1)
357 glVertex2f( cornerSize, h-cornerSize)
358 glTexCoord2f(tx1, ty1)
359 glVertex2f( w-cornerSize, h-cornerSize)
362 glTexCoord2f(tx2, ty1)
363 glVertex2f( w, cornerSize)
364 glTexCoord2f(tx1, ty1)
365 glVertex2f( w-cornerSize, cornerSize)
366 glTexCoord2f(tx1, ty1)
367 glVertex2f( w-cornerSize, h-cornerSize)
368 glTexCoord2f(tx2, ty1)
369 glVertex2f( w, h-cornerSize)
372 glTexCoord2f(tx1, ty1)
373 glVertex2f( cornerSize, cornerSize)
374 glTexCoord2f(tx0, ty1)
375 glVertex2f( 0, cornerSize)
376 glTexCoord2f(tx0, ty1)
377 glVertex2f( 0, h-cornerSize)
378 glTexCoord2f(tx1, ty1)
379 glVertex2f( cornerSize, h-cornerSize)
382 glTexCoord2f(tx1, ty0)
383 glVertex2f( w-cornerSize, 0)
384 glTexCoord2f(tx1, ty0)
385 glVertex2f( cornerSize, 0)
386 glTexCoord2f(tx1, ty1)
387 glVertex2f( cornerSize, cornerSize)
388 glTexCoord2f(tx1, ty1)
389 glVertex2f( w-cornerSize, cornerSize)
392 glTexCoord2f(tx1, ty1)
393 glVertex2f( w-cornerSize, h-cornerSize)
394 glTexCoord2f(tx1, ty1)
395 glVertex2f( cornerSize, h-cornerSize)
396 glTexCoord2f(tx1, ty2)
397 glVertex2f( cornerSize, h)
398 glTexCoord2f(tx1, ty2)
399 glVertex2f( w-cornerSize, h)
402 glDisable(GL_TEXTURE_2D)
405 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
407 Projects window position to 3D space. (gluUnProject). Reimplentation as some drivers crash with the original.
409 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
410 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
411 finalMatrix = npModelMatrix * npProjMatrix
412 finalMatrix = numpy.linalg.inv(finalMatrix)
414 viewport = map(float, viewport)
415 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))
416 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
417 ret = list(vector)[0:3] / vector[3]
420 def convert3x3MatrixTo4x4(matrix):
421 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
423 def loadGLTexture(filename):
424 tex = glGenTextures(1)
425 glBindTexture(GL_TEXTURE_2D, tex)
426 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
428 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
429 rgbData = img.GetData()
430 alphaData = img.GetAlphaData()
431 if alphaData is not None:
433 for i in xrange(0, len(alphaData)):
434 data += rgbData[i*3:i*3+3] + alphaData[i]
435 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
437 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
440 def DrawBox(vMin, vMax):
441 """ Draw wireframe box
443 glBegin(GL_LINE_LOOP)
444 glVertex3f(vMin[0], vMin[1], vMin[2])
445 glVertex3f(vMax[0], vMin[1], vMin[2])
446 glVertex3f(vMax[0], vMax[1], vMin[2])
447 glVertex3f(vMin[0], vMax[1], vMin[2])
450 glBegin(GL_LINE_LOOP)
451 glVertex3f(vMin[0], vMin[1], vMax[2])
452 glVertex3f(vMax[0], vMin[1], vMax[2])
453 glVertex3f(vMax[0], vMax[1], vMax[2])
454 glVertex3f(vMin[0], vMax[1], vMax[2])
457 glVertex3f(vMin[0], vMin[1], vMin[2])
458 glVertex3f(vMin[0], vMin[1], vMax[2])
459 glVertex3f(vMax[0], vMin[1], vMin[2])
460 glVertex3f(vMax[0], vMin[1], vMax[2])
461 glVertex3f(vMax[0], vMax[1], vMin[2])
462 glVertex3f(vMax[0], vMax[1], vMax[2])
463 glVertex3f(vMin[0], vMax[1], vMin[2])
464 glVertex3f(vMin[0], vMax[1], vMax[2])