1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
9 from Cura.util.resources import getPathForImage
13 #OpenGL.ERROR_CHECKING = False
14 from OpenGL.GLUT import *
15 from OpenGL.GLU import *
16 from OpenGL.GL import *
17 from OpenGL.GL import shaders
22 class GLReferenceCounter(object):
31 return self._refCounter <= 0
33 def hasShaderSupport():
34 if bool(glCreateShader):
38 class GLShader(GLReferenceCounter):
39 def __init__(self, vertexProgram, fragmentProgram):
40 super(GLShader, self).__init__()
41 self._vertexString = vertexProgram
42 self._fragmentString = fragmentProgram
44 vertexShader = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
45 fragmentShader = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
47 #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.
48 # self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
49 self._program = glCreateProgram()
50 glAttachShader(self._program, vertexShader)
51 glAttachShader(self._program, fragmentShader)
52 glLinkProgram(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 if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
58 raise RuntimeError("Link failure: %s" % (glGetProgramInfoLog(self._program)))
59 glDeleteShader(vertexShader)
60 glDeleteShader(fragmentShader)
61 except RuntimeError, e:
66 if self._program is not None:
67 shaders.glUseProgram(self._program)
70 shaders.glUseProgram(0)
73 if self._program is not None:
74 glDeleteProgram(self._program)
77 def setUniform(self, name, value):
78 if self._program is not None:
79 if type(value) is float:
80 glUniform1f(glGetUniformLocation(self._program, name), value)
81 elif type(value) is numpy.matrix:
82 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
84 print 'Unknown type for setUniform: %s' % (str(type(value)))
87 return self._program is not None
89 def getVertexShader(self):
90 return self._vertexString
92 def getFragmentShader(self):
93 return self._fragmentString
96 if self._program is not None and bool(glDeleteProgram):
97 print "Shader was not properly released!"
99 #A Class that acts as an OpenGL shader, but in reality is not none.
100 class GLFakeShader(GLReferenceCounter):
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):
131 def __init__(self, renderType, vertexArray, normalArray = None, indicesArray = None):
132 super(GLVBO, self).__init__()
133 self._renderType = renderType
134 if not bool(glGenBuffers):
135 self._vertexArray = vertexArray
136 self._normalArray = normalArray
137 self._indicesArray = indicesArray
138 self._size = len(vertexArray)
140 self._hasNormals = self._normalArray is not None
141 self._hasIndices = self._indicesArray is not None
143 self._buffer = glGenBuffers(1)
144 self._size = len(vertexArray)
145 self._hasNormals = normalArray is not None
146 self._hasIndices = indicesArray is not None
147 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
149 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
151 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
152 glBindBuffer(GL_ARRAY_BUFFER, 0)
154 self._size = len(indicesArray)
155 self._bufferIndices = glGenBuffers(1)
156 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
157 glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
160 glEnableClientState(GL_VERTEX_ARRAY)
161 if self._buffer is None:
162 glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
164 glEnableClientState(GL_NORMAL_ARRAY)
165 glNormalPointer(GL_FLOAT, 0, self._normalArray)
167 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
169 glEnableClientState(GL_NORMAL_ARRAY)
170 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
171 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
173 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
175 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
178 glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
180 batchSize = 996 #Warning, batchSize needs to be dividable by 4, 3 and 2
181 extraStartPos = int(self._size / batchSize) * batchSize
182 extraCount = self._size - extraStartPos
183 for i in xrange(0, int(self._size / batchSize)):
184 glDrawArrays(self._renderType, i * batchSize, batchSize)
185 glDrawArrays(self._renderType, extraStartPos, extraCount)
187 if self._buffer is not None:
188 glBindBuffer(GL_ARRAY_BUFFER, 0)
190 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
192 glDisableClientState(GL_VERTEX_ARRAY)
194 glDisableClientState(GL_NORMAL_ARRAY)
197 if self._buffer is not None:
198 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
199 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
200 glBindBuffer(GL_ARRAY_BUFFER, 0)
201 glDeleteBuffers(1, [self._buffer])
203 self._vertexArray = None
204 self._normalArray = None
207 if self._buffer is not None and bool(glDeleteBuffers):
208 print "VBO was not properly released!"
210 def glDrawStringCenter(s):
212 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
214 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
216 def glGetStringSize(s):
219 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
223 def glDrawStringLeft(s):
229 glTranslate(0, 18 * n, 0)
234 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
236 def glDrawStringRight(s):
238 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
240 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
242 def glDrawQuad(x, y, w, h):
244 glTranslatef(x, y, 0)
245 glDisable(GL_TEXTURE_2D)
254 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
255 tx = float(texID % 4) / 4
256 ty = float(int(texID / 4)) / 8
266 glTranslatef(x, y, 0)
267 glEnable(GL_TEXTURE_2D)
269 glTexCoord2f(tx+tsx, ty)
273 glTexCoord2f(tx, ty+tsy)
275 glTexCoord2f(tx+tsx, ty+tsy)
280 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
281 tx0 = float(texID % 4) / 4
282 ty0 = float(int(texID / 4)) / 8
283 tx1 = tx0 + 0.25 / 2.0
284 ty1 = ty0 + 0.125 / 2.0
289 glTranslatef(x, y, 0)
290 glEnable(GL_TEXTURE_2D)
293 glTexCoord2f(tx1, ty0)
294 glVertex2f( cornerSize, 0)
295 glTexCoord2f(tx0, ty0)
297 glTexCoord2f(tx0, ty1)
298 glVertex2f( 0, cornerSize)
299 glTexCoord2f(tx1, ty1)
300 glVertex2f( cornerSize, cornerSize)
302 glTexCoord2f(tx2, ty0)
304 glTexCoord2f(tx1, ty0)
305 glVertex2f( w - cornerSize, 0)
306 glTexCoord2f(tx1, ty1)
307 glVertex2f( w - cornerSize, cornerSize)
308 glTexCoord2f(tx2, ty1)
309 glVertex2f( w, cornerSize)
311 glTexCoord2f(tx1, ty1)
312 glVertex2f( cornerSize, h - cornerSize)
313 glTexCoord2f(tx0, ty1)
314 glVertex2f( 0, h - cornerSize)
315 glTexCoord2f(tx0, ty2)
317 glTexCoord2f(tx1, ty2)
318 glVertex2f( cornerSize, h)
320 glTexCoord2f(tx2, ty1)
321 glVertex2f( w, h - cornerSize)
322 glTexCoord2f(tx1, ty1)
323 glVertex2f( w - cornerSize, h - cornerSize)
324 glTexCoord2f(tx1, ty2)
325 glVertex2f( w - cornerSize, h)
326 glTexCoord2f(tx2, ty2)
330 glTexCoord2f(tx1, ty1)
331 glVertex2f( w-cornerSize, cornerSize)
332 glTexCoord2f(tx1, ty1)
333 glVertex2f( cornerSize, cornerSize)
334 glTexCoord2f(tx1, ty1)
335 glVertex2f( cornerSize, h-cornerSize)
336 glTexCoord2f(tx1, ty1)
337 glVertex2f( w-cornerSize, h-cornerSize)
340 glTexCoord2f(tx2, ty1)
341 glVertex2f( w, cornerSize)
342 glTexCoord2f(tx1, ty1)
343 glVertex2f( w-cornerSize, cornerSize)
344 glTexCoord2f(tx1, ty1)
345 glVertex2f( w-cornerSize, h-cornerSize)
346 glTexCoord2f(tx2, ty1)
347 glVertex2f( w, h-cornerSize)
350 glTexCoord2f(tx1, ty1)
351 glVertex2f( cornerSize, cornerSize)
352 glTexCoord2f(tx0, ty1)
353 glVertex2f( 0, cornerSize)
354 glTexCoord2f(tx0, ty1)
355 glVertex2f( 0, h-cornerSize)
356 glTexCoord2f(tx1, ty1)
357 glVertex2f( cornerSize, h-cornerSize)
360 glTexCoord2f(tx1, ty0)
361 glVertex2f( w-cornerSize, 0)
362 glTexCoord2f(tx1, ty0)
363 glVertex2f( cornerSize, 0)
364 glTexCoord2f(tx1, ty1)
365 glVertex2f( cornerSize, cornerSize)
366 glTexCoord2f(tx1, ty1)
367 glVertex2f( w-cornerSize, cornerSize)
370 glTexCoord2f(tx1, ty1)
371 glVertex2f( w-cornerSize, h-cornerSize)
372 glTexCoord2f(tx1, ty1)
373 glVertex2f( cornerSize, h-cornerSize)
374 glTexCoord2f(tx1, ty2)
375 glVertex2f( cornerSize, h)
376 glTexCoord2f(tx1, ty2)
377 glVertex2f( w-cornerSize, h)
380 glDisable(GL_TEXTURE_2D)
383 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
384 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
385 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
386 finalMatrix = npModelMatrix * npProjMatrix
387 finalMatrix = numpy.linalg.inv(finalMatrix)
389 viewport = map(float, viewport)
390 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))
391 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
392 ret = list(vector)[0:3] / vector[3]
395 def convert3x3MatrixTo4x4(matrix):
396 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
398 def loadGLTexture(filename):
399 tex = glGenTextures(1)
400 glBindTexture(GL_TEXTURE_2D, tex)
401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
402 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
403 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
404 rgbData = img.GetData()
405 alphaData = img.GetAlphaData()
406 if alphaData is not None:
408 for i in xrange(0, len(alphaData)):
409 data += rgbData[i*3:i*3+3] + alphaData[i]
410 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
412 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
415 def ResetMatrixRotationAndScale():
416 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
420 scale2D = matrix[0][0]
431 if matrix[3][2] != 0.0:
432 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
433 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
436 matrix[0][0] = scale2D
437 matrix[1][1] = scale2D
438 matrix[2][2] = scale2D
442 glLoadMatrixf(matrix)
446 def DrawBox(vMin, vMax):
447 glBegin(GL_LINE_LOOP)
448 glVertex3f(vMin[0], vMin[1], vMin[2])
449 glVertex3f(vMax[0], vMin[1], vMin[2])
450 glVertex3f(vMax[0], vMax[1], vMin[2])
451 glVertex3f(vMin[0], vMax[1], vMin[2])
454 glBegin(GL_LINE_LOOP)
455 glVertex3f(vMin[0], vMin[1], vMax[2])
456 glVertex3f(vMax[0], vMin[1], vMax[2])
457 glVertex3f(vMax[0], vMax[1], vMax[2])
458 glVertex3f(vMin[0], vMax[1], vMax[2])
461 glVertex3f(vMin[0], vMin[1], vMin[2])
462 glVertex3f(vMin[0], vMin[1], vMax[2])
463 glVertex3f(vMax[0], vMin[1], vMin[2])
464 glVertex3f(vMax[0], vMin[1], vMax[2])
465 glVertex3f(vMax[0], vMax[1], vMin[2])
466 glVertex3f(vMax[0], vMax[1], vMax[2])
467 glVertex3f(vMin[0], vMax[1], vMin[2])
468 glVertex3f(vMin[0], vMax[1], vMax[2])
472 def DrawMeshOutline(mesh):
473 glEnable(GL_CULL_FACE)
474 glEnableClientState(GL_VERTEX_ARRAY);
475 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
479 glPolygonMode(GL_BACK, GL_LINE)
480 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
481 glPolygonMode(GL_BACK, GL_FILL)
484 glDisableClientState(GL_VERTEX_ARRAY)
487 def DrawMesh(mesh, insideOut = False):
488 glEnable(GL_CULL_FACE)
489 glEnableClientState(GL_VERTEX_ARRAY)
490 glEnableClientState(GL_NORMAL_ARRAY)
491 for m in mesh._meshList:
492 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
494 glNormalPointer(GL_FLOAT, 0, m.invNormal)
496 glNormalPointer(GL_FLOAT, 0, m.normal)
498 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
499 batchSize = 999 #Warning, batchSize needs to be dividable by 3
500 extraStartPos = int(m.vertexCount / batchSize) * batchSize
501 extraCount = m.vertexCount - extraStartPos
504 for i in xrange(0, int(m.vertexCount / batchSize)):
505 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
506 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
510 glNormalPointer(GL_FLOAT, 0, m.normal)
512 glNormalPointer(GL_FLOAT, 0, m.invNormal)
513 for i in xrange(0, int(m.vertexCount / batchSize)):
514 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
515 extraStartPos = int(m.vertexCount / batchSize) * batchSize
516 extraCount = m.vertexCount - extraStartPos
517 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
520 glDisableClientState(GL_VERTEX_ARRAY)
521 glDisableClientState(GL_NORMAL_ARRAY)
524 def DrawMeshSteep(mesh, matrix, angle):
525 cosAngle = math.sin(angle / 180.0 * math.pi)
526 glDisable(GL_LIGHTING)
527 glDepthFunc(GL_EQUAL)
528 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
529 for i in xrange(0, int(mesh.vertexCount), 3):
530 if normals[i][2] < -0.999999:
531 if mesh.vertexes[i + 0][2] > 0.01:
533 glBegin(GL_TRIANGLES)
534 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
535 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
536 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
538 elif normals[i][2] < -cosAngle:
539 glColor3f(-normals[i][2], 0, 0)
540 glBegin(GL_TRIANGLES)
541 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
542 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
543 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
545 elif normals[i][2] > 0.999999:
546 if mesh.vertexes[i + 0][2] > 0.01:
548 glBegin(GL_TRIANGLES)
549 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
550 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
551 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
553 elif normals[i][2] > cosAngle:
554 glColor3f(normals[i][2], 0, 0)
555 glBegin(GL_TRIANGLES)
556 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
557 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
558 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])