2 from __future__ import absolute_import
9 from Cura.util import meshLoader
10 from Cura.util import util3d
11 from Cura.util import profile
12 from Cura.util.resources import getPathForMesh, getPathForImage
16 OpenGL.ERROR_CHECKING = False
17 from OpenGL.GLUT import *
18 from OpenGL.GLU import *
19 from OpenGL.GL import *
20 from OpenGL.GL import shaders
25 class GLReferenceCounter(object):
34 return self._refCounter <= 0
36 class GLShader(GLReferenceCounter):
37 def __init__(self, vertexProgram, fragmentProgram):
38 super(GLShader, self).__init__()
39 self._vertexString = vertexProgram
40 self._fragmentString = fragmentProgram
42 self._vertexProgram = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
43 self._fragmentProgram = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
44 self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
45 except RuntimeError, e:
50 if self._program is not None:
51 shaders.glUseProgram(self._program)
54 shaders.glUseProgram(0)
57 if self._program is not None:
58 shaders.glDeleteShader(self._vertexProgram)
59 shaders.glDeleteShader(self._fragmentProgram)
60 glDeleteProgram(self._program)
63 def setUniform(self, name, value):
64 if self._program is not None:
65 glUniform1f(glGetUniformLocation(self._program, name), value)
68 return self._program is not None
70 def getVertexShader(self):
71 return self._vertexString
73 def getFragmentShader(self):
74 return self._fragmentString
77 if self._program is not None and bool(glDeleteProgram):
78 print "Shader was not properly released!"
80 class GLVBO(GLReferenceCounter):
81 def __init__(self, vertexArray, normalArray = None):
82 super(GLVBO, self).__init__()
83 self._buffer = glGenBuffers(1)
84 self._size = len(vertexArray)
85 self._hasNormals = normalArray is not None
86 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
88 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
90 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
91 glBindBuffer(GL_ARRAY_BUFFER, 0)
93 def render(self, render_type = GL_TRIANGLES):
94 glEnableClientState(GL_VERTEX_ARRAY)
95 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
98 glEnableClientState(GL_NORMAL_ARRAY)
99 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
100 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
102 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
104 batchSize = 1002 #Warning, batchSize needs to be dividable by 3 and 2
105 extraStartPos = int(self._size / batchSize) * batchSize
106 extraCount = self._size - extraStartPos
108 for i in xrange(0, int(self._size / batchSize)):
109 glDrawArrays(render_type, i * batchSize, batchSize)
110 glDrawArrays(render_type, extraStartPos, extraCount)
111 glBindBuffer(GL_ARRAY_BUFFER, 0)
113 glDisableClientState(GL_VERTEX_ARRAY)
115 glDisableClientState(GL_NORMAL_ARRAY)
118 if self._buffer is not None:
119 glDeleteBuffers(1, [self._buffer])
123 if self._buffer is not None and bool(glDeleteBuffers):
124 print "VBO was not properly released!"
126 def DrawMachine(machineSize):
127 glDisable(GL_LIGHTING)
128 glDisable(GL_CULL_FACE)
130 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
134 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
135 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
140 x1 = max(min(x1, sx), 0)
141 y1 = max(min(y1, sy), 0)
142 x2 = max(min(x2, sx), 0)
143 y2 = max(min(y2, sy), 0)
144 if (x & 1) == (y & 1):
145 glColor4ub(5, 171, 231, 127)
147 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
149 glVertex3f(x1, y1, -0.02)
150 glVertex3f(x2, y1, -0.02)
151 glVertex3f(x2, y2, -0.02)
152 glVertex3f(x1, y2, -0.02)
155 glEnable(GL_CULL_FACE)
157 if profile.getPreference('machine_type') == 'ultimaker':
159 glEnable(GL_LIGHTING)
160 glTranslate(100, 200, -1)
161 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
162 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
164 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
167 if platformMesh is None:
169 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
174 DrawMesh(platformMesh)
176 glDisable(GL_LIGHTING)
177 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
179 glColor4ub(5, 171, 231, 64)
181 glVertex3f(0, 0, machineSize.z)
182 glVertex3f(0, machineSize.y, machineSize.z)
183 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
184 glVertex3f(machineSize.x, 0, machineSize.z)
187 glColor4ub(5, 171, 231, 96)
190 glVertex3f(0, 0, machineSize.z)
191 glVertex3f(machineSize.x, 0, machineSize.z)
192 glVertex3f(machineSize.x, 0, 0)
194 glVertex3f(0, machineSize.y, machineSize.z)
195 glVertex3f(0, machineSize.y, 0)
196 glVertex3f(machineSize.x, machineSize.y, 0)
197 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
200 glColor4ub(5, 171, 231, 128)
202 glVertex3f(0, 0, machineSize.z)
204 glVertex3f(0, machineSize.y, 0)
205 glVertex3f(0, machineSize.y, machineSize.z)
207 glVertex3f(machineSize.x, 0, 0)
208 glVertex3f(machineSize.x, 0, machineSize.z)
209 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
210 glVertex3f(machineSize.x, machineSize.y, 0)
215 #Draw the X/Y/Z indicator
235 glDisable(GL_DEPTH_TEST)
239 glTranslate(20, 0, 0)
240 noZ = ResetMatrixRotationAndScale()
241 glDrawStringCenter("X")
247 glTranslate(0, 20, 0)
248 glDrawStringCenter("Y")
255 glTranslate(0, 0, 20)
256 glDrawStringCenter("Z")
260 glEnable(GL_DEPTH_TEST)
262 def glDrawStringCenter(s):
264 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
266 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
268 def glGetStringSize(s):
271 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
275 def glDrawStringLeft(s):
278 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
280 def glDrawStringRight(s):
282 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
284 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
286 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
287 tx = float(texID % 4) / 4
288 ty = float(int(texID / 4)) / 8
298 glTranslatef(x, y, 0)
299 glEnable(GL_TEXTURE_2D)
301 glTexCoord2f(tx+tsx, ty)
305 glTexCoord2f(tx, ty+tsy)
307 glTexCoord2f(tx+tsx, ty+tsy)
312 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
313 tx0 = float(texID % 4) / 4
314 ty0 = float(int(texID / 4)) / 8
315 tx1 = tx0 + 0.25 / 2.0
316 ty1 = ty0 + 0.125 / 2.0
321 glTranslatef(x, y, 0)
322 glEnable(GL_TEXTURE_2D)
325 glTexCoord2f(tx1, ty0)
326 glVertex2f( cornerSize, 0)
327 glTexCoord2f(tx0, ty0)
329 glTexCoord2f(tx0, ty1)
330 glVertex2f( 0, cornerSize)
331 glTexCoord2f(tx1, ty1)
332 glVertex2f( cornerSize, cornerSize)
334 glTexCoord2f(tx2, ty0)
336 glTexCoord2f(tx1, ty0)
337 glVertex2f( w - cornerSize, 0)
338 glTexCoord2f(tx1, ty1)
339 glVertex2f( w - cornerSize, cornerSize)
340 glTexCoord2f(tx2, ty1)
341 glVertex2f( w, cornerSize)
343 glTexCoord2f(tx1, ty1)
344 glVertex2f( cornerSize, h - cornerSize)
345 glTexCoord2f(tx0, ty1)
346 glVertex2f( 0, h - cornerSize)
347 glTexCoord2f(tx0, ty2)
349 glTexCoord2f(tx1, ty2)
350 glVertex2f( cornerSize, h)
352 glTexCoord2f(tx2, ty1)
353 glVertex2f( w, h - cornerSize)
354 glTexCoord2f(tx1, ty1)
355 glVertex2f( w - cornerSize, h - cornerSize)
356 glTexCoord2f(tx1, ty2)
357 glVertex2f( w - cornerSize, h)
358 glTexCoord2f(tx2, ty2)
362 glTexCoord2f(tx1, ty1)
363 glVertex2f( w-cornerSize, cornerSize)
364 glTexCoord2f(tx1, ty1)
365 glVertex2f( cornerSize, cornerSize)
366 glTexCoord2f(tx1, ty1)
367 glVertex2f( cornerSize, h-cornerSize)
368 glTexCoord2f(tx1, ty1)
369 glVertex2f( w-cornerSize, h-cornerSize)
372 glTexCoord2f(tx2, ty1)
373 glVertex2f( w, cornerSize)
374 glTexCoord2f(tx1, ty1)
375 glVertex2f( w-cornerSize, cornerSize)
376 glTexCoord2f(tx1, ty1)
377 glVertex2f( w-cornerSize, h-cornerSize)
378 glTexCoord2f(tx2, ty1)
379 glVertex2f( w, h-cornerSize)
382 glTexCoord2f(tx1, ty1)
383 glVertex2f( cornerSize, cornerSize)
384 glTexCoord2f(tx0, ty1)
385 glVertex2f( 0, cornerSize)
386 glTexCoord2f(tx0, ty1)
387 glVertex2f( 0, h-cornerSize)
388 glTexCoord2f(tx1, ty1)
389 glVertex2f( cornerSize, h-cornerSize)
392 glTexCoord2f(tx1, ty0)
393 glVertex2f( w-cornerSize, 0)
394 glTexCoord2f(tx1, ty0)
395 glVertex2f( cornerSize, 0)
396 glTexCoord2f(tx1, ty1)
397 glVertex2f( cornerSize, cornerSize)
398 glTexCoord2f(tx1, ty1)
399 glVertex2f( w-cornerSize, cornerSize)
402 glTexCoord2f(tx1, ty1)
403 glVertex2f( w-cornerSize, h-cornerSize)
404 glTexCoord2f(tx1, ty1)
405 glVertex2f( cornerSize, h-cornerSize)
406 glTexCoord2f(tx1, ty2)
407 glVertex2f( cornerSize, h)
408 glTexCoord2f(tx1, ty2)
409 glVertex2f( w-cornerSize, h)
412 glDisable(GL_TEXTURE_2D)
415 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
416 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
417 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
418 finalMatrix = npModelMatrix * npProjMatrix
419 finalMatrix = numpy.linalg.inv(finalMatrix)
421 viewport = map(float, viewport)
422 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))
423 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
424 ret = list(vector)[0:3] / vector[3]
427 def convert3x3MatrixTo4x4(matrix):
428 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
430 def loadGLTexture(filename):
431 tex = glGenTextures(1)
432 glBindTexture(GL_TEXTURE_2D, tex)
433 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
434 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
435 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
436 rgbData = img.GetData()
437 alphaData = img.GetAlphaData()
438 if alphaData is not None:
440 for i in xrange(0, len(alphaData)):
441 data += rgbData[i*3:i*3+3] + alphaData[i]
442 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
444 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
447 def ResetMatrixRotationAndScale():
448 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
452 scale2D = matrix[0][0]
463 if matrix[3][2] != 0.0:
464 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
465 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
468 matrix[0][0] = scale2D
469 matrix[1][1] = scale2D
470 matrix[2][2] = scale2D
474 glLoadMatrixf(matrix)
478 def DrawBox(vMin, vMax):
479 glBegin(GL_LINE_LOOP)
480 glVertex3f(vMin[0], vMin[1], vMin[2])
481 glVertex3f(vMax[0], vMin[1], vMin[2])
482 glVertex3f(vMax[0], vMax[1], vMin[2])
483 glVertex3f(vMin[0], vMax[1], vMin[2])
486 glBegin(GL_LINE_LOOP)
487 glVertex3f(vMin[0], vMin[1], vMax[2])
488 glVertex3f(vMax[0], vMin[1], vMax[2])
489 glVertex3f(vMax[0], vMax[1], vMax[2])
490 glVertex3f(vMin[0], vMax[1], vMax[2])
493 glVertex3f(vMin[0], vMin[1], vMin[2])
494 glVertex3f(vMin[0], vMin[1], vMax[2])
495 glVertex3f(vMax[0], vMin[1], vMin[2])
496 glVertex3f(vMax[0], vMin[1], vMax[2])
497 glVertex3f(vMax[0], vMax[1], vMin[2])
498 glVertex3f(vMax[0], vMax[1], vMax[2])
499 glVertex3f(vMin[0], vMax[1], vMin[2])
500 glVertex3f(vMin[0], vMax[1], vMax[2])
504 def DrawMeshOutline(mesh):
505 glEnable(GL_CULL_FACE)
506 glEnableClientState(GL_VERTEX_ARRAY);
507 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
511 glPolygonMode(GL_BACK, GL_LINE)
512 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
513 glPolygonMode(GL_BACK, GL_FILL)
516 glDisableClientState(GL_VERTEX_ARRAY)
519 def DrawMesh(mesh, insideOut = False):
520 glEnable(GL_CULL_FACE)
521 glEnableClientState(GL_VERTEX_ARRAY)
522 glEnableClientState(GL_NORMAL_ARRAY)
523 for m in mesh._meshList:
524 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
526 glNormalPointer(GL_FLOAT, 0, m.invNormal)
528 glNormalPointer(GL_FLOAT, 0, m.normal)
530 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
531 batchSize = 999 #Warning, batchSize needs to be dividable by 3
532 extraStartPos = int(m.vertexCount / batchSize) * batchSize
533 extraCount = m.vertexCount - extraStartPos
536 for i in xrange(0, int(m.vertexCount / batchSize)):
537 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
538 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
542 glNormalPointer(GL_FLOAT, 0, m.normal)
544 glNormalPointer(GL_FLOAT, 0, m.invNormal)
545 for i in xrange(0, int(m.vertexCount / batchSize)):
546 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
547 extraStartPos = int(m.vertexCount / batchSize) * batchSize
548 extraCount = m.vertexCount - extraStartPos
549 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
552 glDisableClientState(GL_VERTEX_ARRAY)
553 glDisableClientState(GL_NORMAL_ARRAY)
556 def DrawMeshSteep(mesh, matrix, angle):
557 cosAngle = math.sin(angle / 180.0 * math.pi)
558 glDisable(GL_LIGHTING)
559 glDepthFunc(GL_EQUAL)
560 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
561 for i in xrange(0, int(mesh.vertexCount), 3):
562 if normals[i][2] < -0.999999:
563 if mesh.vertexes[i + 0][2] > 0.01:
565 glBegin(GL_TRIANGLES)
566 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
567 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
568 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
570 elif normals[i][2] < -cosAngle:
571 glColor3f(-normals[i][2], 0, 0)
572 glBegin(GL_TRIANGLES)
573 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
574 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
575 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
577 elif normals[i][2] > 0.999999:
578 if mesh.vertexes[i + 0][2] > 0.01:
580 glBegin(GL_TRIANGLES)
581 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
582 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
583 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
585 elif normals[i][2] > cosAngle:
586 glColor3f(normals[i][2], 0, 0)
587 glBegin(GL_TRIANGLES)
588 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
589 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
590 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
594 def DrawGCodeLayer(layer, drawQuick = True):
595 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
596 filamentArea = math.pi * filamentRadius * filamentRadius
597 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
600 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
601 moveColor = [0, 0, 1, 0.5]
602 retractColor = [1, 0, 0.5, 0.5]
603 supportColor = [0, 1, 1, 1]
604 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
605 innerWallColor = [0, 1, 0, 1]
606 skirtColor = [0, 0.5, 0.5, 1]
607 prevPathWasRetract = False
609 glDisable(GL_CULL_FACE)
611 if path.type == 'move':
612 if prevPathWasRetract:
619 if path.type == 'extrude':
620 if path.pathType == 'FILL':
621 c = fillColorCycle[fillCycle]
622 fillCycle = (fillCycle + 1) % len(fillColorCycle)
623 elif path.pathType == 'WALL-INNER':
626 elif path.pathType == 'SUPPORT':
628 elif path.pathType == 'SKIRT':
631 c = extrudeColor[path.extruder]
632 if path.type == 'retract':
634 if path.type == 'extrude' and not drawQuick:
637 for i in xrange(0, len(path.points) - 1):
639 v1 = path.points[i + 1]
641 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
642 dist = (v0 - v1).vsize()
643 if dist > 0 and path.layerThickness > 0:
644 extrusionMMperDist = (v1.e - v0.e) / dist
645 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
647 drawLength += (v0 - v1).vsize()
648 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
651 vv2 = v0 + normal * lineWidth
652 vv3 = v1 + normal * lineWidth
653 vv0 = v0 - normal * lineWidth
654 vv1 = v1 - normal * lineWidth
658 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
659 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
660 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
661 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
663 if prevNormal is not None:
664 n = (normal + prevNormal)
666 vv4 = v0 + n * lineWidth
667 vv5 = v0 - n * lineWidth
670 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
671 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
672 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
673 glVertex3f(v0.x, v0.y, v0.z - zOffset)
675 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
676 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
677 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
678 glVertex3f(v0.x, v0.y, v0.z - zOffset)
686 glBegin(GL_TRIANGLES)
687 for v in path.points:
688 glVertex3f(v[0], v[1], v[2])
691 if not path.type == 'move':
692 prevPathWasRetract = False
693 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
694 # prevPathWasRetract = True
695 glEnable(GL_CULL_FACE)