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
21 class GLReferenceCounter(object):
30 return self._refCounter <= 0
32 def hasShaderSupport():
33 if bool(glCreateShader):
37 class GLShader(GLReferenceCounter):
38 def __init__(self, vertexProgram, fragmentProgram):
39 super(GLShader, self).__init__()
40 self._vertexString = vertexProgram
41 self._fragmentString = fragmentProgram
43 vertexShader = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
44 fragmentShader = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
46 #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.
47 # self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
48 self._program = glCreateProgram()
49 glAttachShader(self._program, vertexShader)
50 glAttachShader(self._program, fragmentShader)
51 glLinkProgram(self._program)
52 # Validation has to occur *after* linking
53 glValidateProgram(self._program)
54 if glGetProgramiv(self._program, GL_VALIDATE_STATUS) == GL_FALSE:
55 raise RuntimeError("Validation failure: %s"%(glGetProgramInfoLog(self._program)))
56 if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
57 raise RuntimeError("Link failure: %s" % (glGetProgramInfoLog(self._program)))
58 glDeleteShader(vertexShader)
59 glDeleteShader(fragmentShader)
60 except RuntimeError, e:
65 if self._program is not None:
66 shaders.glUseProgram(self._program)
69 shaders.glUseProgram(0)
72 if self._program is not None:
73 glDeleteProgram(self._program)
76 def setUniform(self, name, value):
77 if self._program is not None:
78 if type(value) is float:
79 glUniform1f(glGetUniformLocation(self._program, name), value)
80 elif type(value) is numpy.matrix:
81 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
83 print 'Unknown type for setUniform: %s' % (str(type(value)))
86 return self._program is not None
88 def getVertexShader(self):
89 return self._vertexString
91 def getFragmentShader(self):
92 return self._fragmentString
95 if self._program is not None and bool(glDeleteProgram):
96 print "Shader was not properly released!"
98 #A Class that acts as an OpenGL shader, but in reality is not none.
99 class GLFakeShader(GLReferenceCounter):
101 super(GLFakeShader, self).__init__()
104 glEnable(GL_LIGHTING)
106 glEnable(GL_COLOR_MATERIAL)
107 glLightfv(GL_LIGHT0, GL_DIFFUSE, [1,1,1,1])
108 glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,0])
109 glLightfv(GL_LIGHT0, GL_SPECULAR, [0,0,0,0])
112 glDisable(GL_LIGHTING)
117 def setUniform(self, name, value):
123 def getVertexShader(self):
126 def getFragmentShader(self):
129 class GLVBO(GLReferenceCounter):
130 def __init__(self, renderType, vertexArray, normalArray = None, indicesArray = None):
131 super(GLVBO, self).__init__()
132 self._renderType = renderType
133 if not bool(glGenBuffers):
134 self._vertexArray = vertexArray
135 self._normalArray = normalArray
136 self._indicesArray = indicesArray
137 self._size = len(vertexArray)
139 self._hasNormals = self._normalArray is not None
140 self._hasIndices = self._indicesArray is not None
142 self._buffer = glGenBuffers(1)
143 self._size = len(vertexArray)
144 self._hasNormals = normalArray is not None
145 self._hasIndices = indicesArray is not None
146 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
148 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
150 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
151 glBindBuffer(GL_ARRAY_BUFFER, 0)
153 self._size = len(indicesArray)
154 self._bufferIndices = glGenBuffers(1)
155 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
156 glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
159 glEnableClientState(GL_VERTEX_ARRAY)
160 if self._buffer is None:
161 glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
163 glEnableClientState(GL_NORMAL_ARRAY)
164 glNormalPointer(GL_FLOAT, 0, self._normalArray)
166 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
168 glEnableClientState(GL_NORMAL_ARRAY)
169 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
170 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
172 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
174 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
177 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
179 batchSize = 996 #Warning, batchSize needs to be dividable by 4, 3 and 2
180 extraStartPos = int(self._size / batchSize) * batchSize
181 extraCount = self._size - extraStartPos
182 for i in xrange(0, int(self._size / batchSize)):
183 glDrawArrays(self._renderType, i * batchSize, batchSize)
184 glDrawArrays(self._renderType, extraStartPos, extraCount)
186 if self._buffer is not None:
187 glBindBuffer(GL_ARRAY_BUFFER, 0)
189 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
191 glDisableClientState(GL_VERTEX_ARRAY)
193 glDisableClientState(GL_NORMAL_ARRAY)
196 if self._buffer is not None:
197 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
198 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
199 glBindBuffer(GL_ARRAY_BUFFER, 0)
200 glDeleteBuffers(1, [self._buffer])
202 self._vertexArray = None
203 self._normalArray = None
206 if self._buffer is not None and bool(glDeleteBuffers):
207 print "VBO was not properly released!"
209 def glDrawStringCenter(s):
211 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
213 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
215 def glGetStringSize(s):
218 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
222 def glDrawStringLeft(s):
228 glTranslate(0, 18 * n, 0)
233 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
235 def glDrawStringRight(s):
237 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
239 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
241 def glDrawQuad(x, y, w, h):
243 glTranslatef(x, y, 0)
244 glDisable(GL_TEXTURE_2D)
253 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
254 tx = float(texID % 4) / 4
255 ty = float(int(texID / 4)) / 8
265 glTranslatef(x, y, 0)
266 glEnable(GL_TEXTURE_2D)
268 glTexCoord2f(tx+tsx, ty)
272 glTexCoord2f(tx, ty+tsy)
274 glTexCoord2f(tx+tsx, ty+tsy)
279 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
280 tx0 = float(texID % 4) / 4
281 ty0 = float(int(texID / 4)) / 8
282 tx1 = tx0 + 0.25 / 2.0
283 ty1 = ty0 + 0.125 / 2.0
288 glTranslatef(x, y, 0)
289 glEnable(GL_TEXTURE_2D)
292 glTexCoord2f(tx1, ty0)
293 glVertex2f( cornerSize, 0)
294 glTexCoord2f(tx0, ty0)
296 glTexCoord2f(tx0, ty1)
297 glVertex2f( 0, cornerSize)
298 glTexCoord2f(tx1, ty1)
299 glVertex2f( cornerSize, cornerSize)
301 glTexCoord2f(tx2, ty0)
303 glTexCoord2f(tx1, ty0)
304 glVertex2f( w - cornerSize, 0)
305 glTexCoord2f(tx1, ty1)
306 glVertex2f( w - cornerSize, cornerSize)
307 glTexCoord2f(tx2, ty1)
308 glVertex2f( w, cornerSize)
310 glTexCoord2f(tx1, ty1)
311 glVertex2f( cornerSize, h - cornerSize)
312 glTexCoord2f(tx0, ty1)
313 glVertex2f( 0, h - cornerSize)
314 glTexCoord2f(tx0, ty2)
316 glTexCoord2f(tx1, ty2)
317 glVertex2f( cornerSize, h)
319 glTexCoord2f(tx2, ty1)
320 glVertex2f( w, h - cornerSize)
321 glTexCoord2f(tx1, ty1)
322 glVertex2f( w - cornerSize, h - cornerSize)
323 glTexCoord2f(tx1, ty2)
324 glVertex2f( w - cornerSize, h)
325 glTexCoord2f(tx2, ty2)
329 glTexCoord2f(tx1, ty1)
330 glVertex2f( w-cornerSize, cornerSize)
331 glTexCoord2f(tx1, ty1)
332 glVertex2f( cornerSize, cornerSize)
333 glTexCoord2f(tx1, ty1)
334 glVertex2f( cornerSize, h-cornerSize)
335 glTexCoord2f(tx1, ty1)
336 glVertex2f( w-cornerSize, h-cornerSize)
339 glTexCoord2f(tx2, ty1)
340 glVertex2f( w, cornerSize)
341 glTexCoord2f(tx1, ty1)
342 glVertex2f( w-cornerSize, cornerSize)
343 glTexCoord2f(tx1, ty1)
344 glVertex2f( w-cornerSize, h-cornerSize)
345 glTexCoord2f(tx2, ty1)
346 glVertex2f( w, h-cornerSize)
349 glTexCoord2f(tx1, ty1)
350 glVertex2f( cornerSize, cornerSize)
351 glTexCoord2f(tx0, ty1)
352 glVertex2f( 0, cornerSize)
353 glTexCoord2f(tx0, ty1)
354 glVertex2f( 0, h-cornerSize)
355 glTexCoord2f(tx1, ty1)
356 glVertex2f( cornerSize, h-cornerSize)
359 glTexCoord2f(tx1, ty0)
360 glVertex2f( w-cornerSize, 0)
361 glTexCoord2f(tx1, ty0)
362 glVertex2f( cornerSize, 0)
363 glTexCoord2f(tx1, ty1)
364 glVertex2f( cornerSize, cornerSize)
365 glTexCoord2f(tx1, ty1)
366 glVertex2f( w-cornerSize, cornerSize)
369 glTexCoord2f(tx1, ty1)
370 glVertex2f( w-cornerSize, h-cornerSize)
371 glTexCoord2f(tx1, ty1)
372 glVertex2f( cornerSize, h-cornerSize)
373 glTexCoord2f(tx1, ty2)
374 glVertex2f( cornerSize, h)
375 glTexCoord2f(tx1, ty2)
376 glVertex2f( w-cornerSize, h)
379 glDisable(GL_TEXTURE_2D)
382 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
383 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
384 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
385 finalMatrix = npModelMatrix * npProjMatrix
386 finalMatrix = numpy.linalg.inv(finalMatrix)
388 viewport = map(float, viewport)
389 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))
390 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
391 ret = list(vector)[0:3] / vector[3]
394 def convert3x3MatrixTo4x4(matrix):
395 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
397 def loadGLTexture(filename):
398 tex = glGenTextures(1)
399 glBindTexture(GL_TEXTURE_2D, tex)
400 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
402 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
403 rgbData = img.GetData()
404 alphaData = img.GetAlphaData()
405 if alphaData is not None:
407 for i in xrange(0, len(alphaData)):
408 data += rgbData[i*3:i*3+3] + alphaData[i]
409 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
411 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
414 def ResetMatrixRotationAndScale():
415 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
419 scale2D = matrix[0][0]
430 if matrix[3][2] != 0.0:
431 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
432 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
435 matrix[0][0] = scale2D
436 matrix[1][1] = scale2D
437 matrix[2][2] = scale2D
441 glLoadMatrixf(matrix)
445 def DrawBox(vMin, vMax):
446 glBegin(GL_LINE_LOOP)
447 glVertex3f(vMin[0], vMin[1], vMin[2])
448 glVertex3f(vMax[0], vMin[1], vMin[2])
449 glVertex3f(vMax[0], vMax[1], vMin[2])
450 glVertex3f(vMin[0], vMax[1], vMin[2])
453 glBegin(GL_LINE_LOOP)
454 glVertex3f(vMin[0], vMin[1], vMax[2])
455 glVertex3f(vMax[0], vMin[1], vMax[2])
456 glVertex3f(vMax[0], vMax[1], vMax[2])
457 glVertex3f(vMin[0], vMax[1], vMax[2])
460 glVertex3f(vMin[0], vMin[1], vMin[2])
461 glVertex3f(vMin[0], vMin[1], vMax[2])
462 glVertex3f(vMax[0], vMin[1], vMin[2])
463 glVertex3f(vMax[0], vMin[1], vMax[2])
464 glVertex3f(vMax[0], vMax[1], vMin[2])
465 glVertex3f(vMax[0], vMax[1], vMax[2])
466 glVertex3f(vMin[0], vMax[1], vMin[2])
467 glVertex3f(vMin[0], vMax[1], vMax[2])
471 def DrawMeshOutline(mesh):
472 glEnable(GL_CULL_FACE)
473 glEnableClientState(GL_VERTEX_ARRAY);
474 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
478 glPolygonMode(GL_BACK, GL_LINE)
479 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
480 glPolygonMode(GL_BACK, GL_FILL)
483 glDisableClientState(GL_VERTEX_ARRAY)
486 def DrawMesh(mesh, insideOut = False):
487 glEnable(GL_CULL_FACE)
488 glEnableClientState(GL_VERTEX_ARRAY)
489 glEnableClientState(GL_NORMAL_ARRAY)
490 for m in mesh._meshList:
491 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
493 glNormalPointer(GL_FLOAT, 0, m.invNormal)
495 glNormalPointer(GL_FLOAT, 0, m.normal)
497 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
498 batchSize = 999 #Warning, batchSize needs to be dividable by 3
499 extraStartPos = int(m.vertexCount / batchSize) * batchSize
500 extraCount = m.vertexCount - extraStartPos
503 for i in xrange(0, int(m.vertexCount / batchSize)):
504 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
505 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
509 glNormalPointer(GL_FLOAT, 0, m.normal)
511 glNormalPointer(GL_FLOAT, 0, m.invNormal)
512 for i in xrange(0, int(m.vertexCount / batchSize)):
513 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
514 extraStartPos = int(m.vertexCount / batchSize) * batchSize
515 extraCount = m.vertexCount - extraStartPos
516 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
519 glDisableClientState(GL_VERTEX_ARRAY)
520 glDisableClientState(GL_NORMAL_ARRAY)
523 def DrawMeshSteep(mesh, matrix, angle):
524 cosAngle = math.sin(angle / 180.0 * math.pi)
525 glDisable(GL_LIGHTING)
526 glDepthFunc(GL_EQUAL)
527 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
528 for i in xrange(0, int(mesh.vertexCount), 3):
529 if normals[i][2] < -0.999999:
530 if mesh.vertexes[i + 0][2] > 0.01:
532 glBegin(GL_TRIANGLES)
533 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
534 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
535 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
537 elif normals[i][2] < -cosAngle:
538 glColor3f(-normals[i][2], 0, 0)
539 glBegin(GL_TRIANGLES)
540 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
541 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
542 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
544 elif normals[i][2] > 0.999999:
545 if mesh.vertexes[i + 0][2] > 0.01:
547 glBegin(GL_TRIANGLES)
548 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
549 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
550 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
552 elif normals[i][2] > cosAngle:
553 glColor3f(normals[i][2], 0, 0)
554 glBegin(GL_TRIANGLES)
555 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
556 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
557 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])