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 GLShader(object):
26 def __init__(self, vertexProgram, fragmentProgram):
27 self._vertexString = vertexProgram
28 self._fragmentString = fragmentProgram
30 self._vertexProgram = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
31 self._fragmentProgram = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
32 self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
33 except RuntimeError, e:
38 if self._program is not None:
39 shaders.glUseProgram(self._program)
42 shaders.glUseProgram(0)
45 if self._program is not None:
46 shaders.glDeleteShader(self._vertexProgram)
47 shaders.glDeleteShader(self._fragmentProgram)
48 glDeleteProgram(self._program)
51 def setUniform(self, name, value):
52 if self._program is not None:
53 glUniform1f(glGetUniformLocation(self._program, name), value)
56 return self._program is not None
58 def getVertexShader(self):
59 return self._vertexString
61 def getFragmentShader(self):
62 return self._fragmentString
65 if self._program is not None and bool(glDeleteProgram):
66 print "Shader was not properly released!"
69 def __init__(self, vertexArray, normalArray):
70 self._buffer = glGenBuffers(1)
71 self._size = len(vertexArray)
72 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
73 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
74 glBindBuffer(GL_ARRAY_BUFFER, 0)
76 def render(self, render_type = GL_TRIANGLES):
77 glEnableClientState(GL_VERTEX_ARRAY)
78 glEnableClientState(GL_NORMAL_ARRAY)
79 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
80 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
81 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
83 batchSize = 999 #Warning, batchSize needs to be dividable by 3
84 extraStartPos = int(self._size / batchSize) * batchSize
85 extraCount = self._size - extraStartPos
87 for i in xrange(0, int(self._size / batchSize)):
88 glDrawArrays(render_type, i * batchSize, batchSize)
89 glDrawArrays(render_type, extraStartPos, extraCount)
90 glBindBuffer(GL_ARRAY_BUFFER, 0)
91 glDisableClientState(GL_VERTEX_ARRAY)
92 glDisableClientState(GL_NORMAL_ARRAY)
95 if self._buffer is not None:
96 glDeleteBuffers(1, [self._buffer])
100 if self._buffer is not None and bool(glDeleteBuffers):
101 print "VBO was not properly released!"
103 def DrawMachine(machineSize):
104 glDisable(GL_LIGHTING)
105 glDisable(GL_CULL_FACE)
107 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
111 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
112 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
117 x1 = max(min(x1, sx), 0)
118 y1 = max(min(y1, sy), 0)
119 x2 = max(min(x2, sx), 0)
120 y2 = max(min(y2, sy), 0)
121 if (x & 1) == (y & 1):
122 glColor4ub(5, 171, 231, 127)
124 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
126 glVertex3f(x1, y1, -0.02)
127 glVertex3f(x2, y1, -0.02)
128 glVertex3f(x2, y2, -0.02)
129 glVertex3f(x1, y2, -0.02)
132 glEnable(GL_CULL_FACE)
134 if profile.getPreference('machine_type') == 'ultimaker':
136 glEnable(GL_LIGHTING)
137 glTranslate(100, 200, -1)
138 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
139 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
141 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
144 if platformMesh is None:
146 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
151 DrawMesh(platformMesh)
153 glDisable(GL_LIGHTING)
154 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
156 glColor4ub(5, 171, 231, 64)
158 glVertex3f(0, 0, machineSize.z)
159 glVertex3f(0, machineSize.y, machineSize.z)
160 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
161 glVertex3f(machineSize.x, 0, machineSize.z)
164 glColor4ub(5, 171, 231, 96)
167 glVertex3f(0, 0, machineSize.z)
168 glVertex3f(machineSize.x, 0, machineSize.z)
169 glVertex3f(machineSize.x, 0, 0)
171 glVertex3f(0, machineSize.y, machineSize.z)
172 glVertex3f(0, machineSize.y, 0)
173 glVertex3f(machineSize.x, machineSize.y, 0)
174 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
177 glColor4ub(5, 171, 231, 128)
179 glVertex3f(0, 0, machineSize.z)
181 glVertex3f(0, machineSize.y, 0)
182 glVertex3f(0, machineSize.y, machineSize.z)
184 glVertex3f(machineSize.x, 0, 0)
185 glVertex3f(machineSize.x, 0, machineSize.z)
186 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
187 glVertex3f(machineSize.x, machineSize.y, 0)
192 #Draw the X/Y/Z indicator
212 glDisable(GL_DEPTH_TEST)
216 glTranslate(20, 0, 0)
217 noZ = ResetMatrixRotationAndScale()
218 glDrawStringCenter("X")
224 glTranslate(0, 20, 0)
225 glDrawStringCenter("Y")
232 glTranslate(0, 0, 20)
233 glDrawStringCenter("Z")
237 glEnable(GL_DEPTH_TEST)
239 def glDrawStringCenter(s):
241 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
243 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
245 def glGetStringSize(s):
248 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
252 def glDrawStringLeft(s):
255 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
257 def glDrawStringRight(s):
259 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
261 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
263 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
264 tx = float(texID % 4) / 4
265 ty = float(int(texID / 4)) / 8
275 glTranslatef(x, y, 0)
276 glEnable(GL_TEXTURE_2D)
278 glTexCoord2f(tx+tsx, ty)
282 glTexCoord2f(tx, ty+tsy)
284 glTexCoord2f(tx+tsx, ty+tsy)
289 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
290 tx0 = float(texID % 4) / 4
291 ty0 = float(int(texID / 4)) / 8
292 tx1 = tx0 + 0.25 / 2.0
293 ty1 = ty0 + 0.125 / 2.0
298 glTranslatef(x, y, 0)
299 glEnable(GL_TEXTURE_2D)
302 glTexCoord2f(tx1, ty0)
303 glVertex2f( cornerSize, 0)
304 glTexCoord2f(tx0, ty0)
306 glTexCoord2f(tx0, ty1)
307 glVertex2f( 0, cornerSize)
308 glTexCoord2f(tx1, ty1)
309 glVertex2f( cornerSize, cornerSize)
311 glTexCoord2f(tx2, ty0)
313 glTexCoord2f(tx1, ty0)
314 glVertex2f( w - cornerSize, 0)
315 glTexCoord2f(tx1, ty1)
316 glVertex2f( w - cornerSize, cornerSize)
317 glTexCoord2f(tx2, ty1)
318 glVertex2f( w, cornerSize)
320 glTexCoord2f(tx1, ty1)
321 glVertex2f( cornerSize, h - cornerSize)
322 glTexCoord2f(tx0, ty1)
323 glVertex2f( 0, h - cornerSize)
324 glTexCoord2f(tx0, ty2)
326 glTexCoord2f(tx1, ty2)
327 glVertex2f( cornerSize, h)
329 glTexCoord2f(tx2, ty1)
330 glVertex2f( w, h - cornerSize)
331 glTexCoord2f(tx1, ty1)
332 glVertex2f( w - cornerSize, h - cornerSize)
333 glTexCoord2f(tx1, ty2)
334 glVertex2f( w - cornerSize, h)
335 glTexCoord2f(tx2, ty2)
339 glTexCoord2f(tx1, ty1)
340 glVertex2f( w-cornerSize, cornerSize)
341 glTexCoord2f(tx1, ty1)
342 glVertex2f( cornerSize, cornerSize)
343 glTexCoord2f(tx1, ty1)
344 glVertex2f( cornerSize, h-cornerSize)
345 glTexCoord2f(tx1, ty1)
346 glVertex2f( w-cornerSize, h-cornerSize)
349 glTexCoord2f(tx2, ty1)
350 glVertex2f( w, cornerSize)
351 glTexCoord2f(tx1, ty1)
352 glVertex2f( w-cornerSize, cornerSize)
353 glTexCoord2f(tx1, ty1)
354 glVertex2f( w-cornerSize, h-cornerSize)
355 glTexCoord2f(tx2, ty1)
356 glVertex2f( w, h-cornerSize)
359 glTexCoord2f(tx1, ty1)
360 glVertex2f( cornerSize, cornerSize)
361 glTexCoord2f(tx0, ty1)
362 glVertex2f( 0, cornerSize)
363 glTexCoord2f(tx0, ty1)
364 glVertex2f( 0, h-cornerSize)
365 glTexCoord2f(tx1, ty1)
366 glVertex2f( cornerSize, h-cornerSize)
369 glTexCoord2f(tx1, ty0)
370 glVertex2f( w-cornerSize, 0)
371 glTexCoord2f(tx1, ty0)
372 glVertex2f( cornerSize, 0)
373 glTexCoord2f(tx1, ty1)
374 glVertex2f( cornerSize, cornerSize)
375 glTexCoord2f(tx1, ty1)
376 glVertex2f( w-cornerSize, cornerSize)
379 glTexCoord2f(tx1, ty1)
380 glVertex2f( w-cornerSize, h-cornerSize)
381 glTexCoord2f(tx1, ty1)
382 glVertex2f( cornerSize, h-cornerSize)
383 glTexCoord2f(tx1, ty2)
384 glVertex2f( cornerSize, h)
385 glTexCoord2f(tx1, ty2)
386 glVertex2f( w-cornerSize, h)
389 glDisable(GL_TEXTURE_2D)
392 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
393 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
394 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
395 finalMatrix = npModelMatrix * npProjMatrix
396 finalMatrix = numpy.linalg.inv(finalMatrix)
398 viewport = map(float, viewport)
399 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))
400 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
401 ret = list(vector)[0:3] / vector[3]
404 def convert3x3MatrixTo4x4(matrix):
405 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
407 def loadGLTexture(filename):
408 tex = glGenTextures(1)
409 glBindTexture(GL_TEXTURE_2D, tex)
410 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
411 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
412 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
413 rgbData = img.GetData()
414 alphaData = img.GetAlphaData()
415 if alphaData is not None:
417 for i in xrange(0, len(alphaData)):
418 data += rgbData[i*3:i*3+3] + alphaData[i]
419 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
421 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
424 def ResetMatrixRotationAndScale():
425 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
429 scale2D = matrix[0][0]
440 if matrix[3][2] != 0.0:
441 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
442 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
445 matrix[0][0] = scale2D
446 matrix[1][1] = scale2D
447 matrix[2][2] = scale2D
451 glLoadMatrixf(matrix)
455 def DrawBox(vMin, vMax):
456 glBegin(GL_LINE_LOOP)
457 glVertex3f(vMin[0], vMin[1], vMin[2])
458 glVertex3f(vMax[0], vMin[1], vMin[2])
459 glVertex3f(vMax[0], vMax[1], vMin[2])
460 glVertex3f(vMin[0], vMax[1], vMin[2])
463 glBegin(GL_LINE_LOOP)
464 glVertex3f(vMin[0], vMin[1], vMax[2])
465 glVertex3f(vMax[0], vMin[1], vMax[2])
466 glVertex3f(vMax[0], vMax[1], vMax[2])
467 glVertex3f(vMin[0], vMax[1], vMax[2])
470 glVertex3f(vMin[0], vMin[1], vMin[2])
471 glVertex3f(vMin[0], vMin[1], vMax[2])
472 glVertex3f(vMax[0], vMin[1], vMin[2])
473 glVertex3f(vMax[0], vMin[1], vMax[2])
474 glVertex3f(vMax[0], vMax[1], vMin[2])
475 glVertex3f(vMax[0], vMax[1], vMax[2])
476 glVertex3f(vMin[0], vMax[1], vMin[2])
477 glVertex3f(vMin[0], vMax[1], vMax[2])
481 def DrawMeshOutline(mesh):
482 glEnable(GL_CULL_FACE)
483 glEnableClientState(GL_VERTEX_ARRAY);
484 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
488 glPolygonMode(GL_BACK, GL_LINE)
489 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
490 glPolygonMode(GL_BACK, GL_FILL)
493 glDisableClientState(GL_VERTEX_ARRAY)
496 def DrawMesh(mesh, insideOut = False):
497 glEnable(GL_CULL_FACE)
498 glEnableClientState(GL_VERTEX_ARRAY)
499 glEnableClientState(GL_NORMAL_ARRAY)
500 for m in mesh._meshList:
501 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
503 glNormalPointer(GL_FLOAT, 0, m.invNormal)
505 glNormalPointer(GL_FLOAT, 0, m.normal)
507 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
508 batchSize = 999 #Warning, batchSize needs to be dividable by 3
509 extraStartPos = int(m.vertexCount / batchSize) * batchSize
510 extraCount = m.vertexCount - extraStartPos
513 for i in xrange(0, int(m.vertexCount / batchSize)):
514 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
515 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
519 glNormalPointer(GL_FLOAT, 0, m.normal)
521 glNormalPointer(GL_FLOAT, 0, m.invNormal)
522 for i in xrange(0, int(m.vertexCount / batchSize)):
523 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
524 extraStartPos = int(m.vertexCount / batchSize) * batchSize
525 extraCount = m.vertexCount - extraStartPos
526 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
529 glDisableClientState(GL_VERTEX_ARRAY)
530 glDisableClientState(GL_NORMAL_ARRAY)
533 def DrawMeshSteep(mesh, matrix, angle):
534 cosAngle = math.sin(angle / 180.0 * math.pi)
535 glDisable(GL_LIGHTING)
536 glDepthFunc(GL_EQUAL)
537 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
538 for i in xrange(0, int(mesh.vertexCount), 3):
539 if normals[i][2] < -0.999999:
540 if mesh.vertexes[i + 0][2] > 0.01:
542 glBegin(GL_TRIANGLES)
543 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
544 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
545 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
547 elif normals[i][2] < -cosAngle:
548 glColor3f(-normals[i][2], 0, 0)
549 glBegin(GL_TRIANGLES)
550 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
551 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
552 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
554 elif normals[i][2] > 0.999999:
555 if mesh.vertexes[i + 0][2] > 0.01:
557 glBegin(GL_TRIANGLES)
558 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
559 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
560 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
562 elif normals[i][2] > cosAngle:
563 glColor3f(normals[i][2], 0, 0)
564 glBegin(GL_TRIANGLES)
565 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
566 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
567 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
572 def DrawGCodeLayer(layer, drawQuick = True):
573 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
574 filamentArea = math.pi * filamentRadius * filamentRadius
575 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
578 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
579 moveColor = [0, 0, 1, 0.5]
580 retractColor = [1, 0, 0.5, 0.5]
581 supportColor = [0, 1, 1, 1]
582 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
583 innerWallColor = [0, 1, 0, 1]
584 skirtColor = [0, 0.5, 0.5, 1]
585 prevPathWasRetract = False
587 glDisable(GL_CULL_FACE)
589 if path.type == 'move':
590 if prevPathWasRetract:
597 if path.type == 'extrude':
598 if path.pathType == 'FILL':
599 c = fillColorCycle[fillCycle]
600 fillCycle = (fillCycle + 1) % len(fillColorCycle)
603 elif path.pathType == 'WALL-INNER':
606 elif path.pathType == 'SUPPORT':
608 elif path.pathType == 'SKIRT':
611 c = extrudeColor[path.extruder]
612 if path.type == 'retract':
614 if path.type == 'extrude' and not drawQuick:
617 for i in xrange(0, len(path.list) - 1):
619 v1 = path.list[i + 1]
621 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
622 dist = (v0 - v1).vsize()
623 if dist > 0 and path.layerThickness > 0:
624 extrusionMMperDist = (v1.e - v0.e) / dist
625 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
627 drawLength += (v0 - v1).vsize()
628 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
631 vv2 = v0 + normal * lineWidth
632 vv3 = v1 + normal * lineWidth
633 vv0 = v0 - normal * lineWidth
634 vv1 = v1 - normal * lineWidth
638 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
639 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
640 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
641 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
643 if prevNormal is not None:
644 n = (normal + prevNormal)
646 vv4 = v0 + n * lineWidth
647 vv5 = v0 - n * lineWidth
650 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
651 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
652 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
653 glVertex3f(v0.x, v0.y, v0.z - zOffset)
655 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
656 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
657 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
658 glVertex3f(v0.x, v0.y, v0.z - zOffset)
665 glBegin(GL_LINE_STRIP)
668 glVertex3f(v.x, v.y, v.z)
670 if not path.type == 'move':
671 prevPathWasRetract = False
672 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
673 prevPathWasRetract = True
674 glEnable(GL_CULL_FACE)