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):
82 super(GLVBO, self).__init__()
83 self._buffer = glGenBuffers(1)
84 self._size = len(vertexArray)
85 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
86 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
87 glBindBuffer(GL_ARRAY_BUFFER, 0)
89 def render(self, render_type = GL_TRIANGLES):
90 glEnableClientState(GL_VERTEX_ARRAY)
91 glEnableClientState(GL_NORMAL_ARRAY)
92 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
93 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
94 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
96 batchSize = 999 #Warning, batchSize needs to be dividable by 3
97 extraStartPos = int(self._size / batchSize) * batchSize
98 extraCount = self._size - extraStartPos
100 for i in xrange(0, int(self._size / batchSize)):
101 glDrawArrays(render_type, i * batchSize, batchSize)
102 glDrawArrays(render_type, extraStartPos, extraCount)
103 glBindBuffer(GL_ARRAY_BUFFER, 0)
104 glDisableClientState(GL_VERTEX_ARRAY)
105 glDisableClientState(GL_NORMAL_ARRAY)
108 if self._buffer is not None:
109 glDeleteBuffers(1, [self._buffer])
113 if self._buffer is not None and bool(glDeleteBuffers):
114 print "VBO was not properly released!"
116 def DrawMachine(machineSize):
117 glDisable(GL_LIGHTING)
118 glDisable(GL_CULL_FACE)
120 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
124 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
125 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
130 x1 = max(min(x1, sx), 0)
131 y1 = max(min(y1, sy), 0)
132 x2 = max(min(x2, sx), 0)
133 y2 = max(min(y2, sy), 0)
134 if (x & 1) == (y & 1):
135 glColor4ub(5, 171, 231, 127)
137 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
139 glVertex3f(x1, y1, -0.02)
140 glVertex3f(x2, y1, -0.02)
141 glVertex3f(x2, y2, -0.02)
142 glVertex3f(x1, y2, -0.02)
145 glEnable(GL_CULL_FACE)
147 if profile.getPreference('machine_type') == 'ultimaker':
149 glEnable(GL_LIGHTING)
150 glTranslate(100, 200, -1)
151 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
152 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
154 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
157 if platformMesh is None:
159 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
164 DrawMesh(platformMesh)
166 glDisable(GL_LIGHTING)
167 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
169 glColor4ub(5, 171, 231, 64)
171 glVertex3f(0, 0, machineSize.z)
172 glVertex3f(0, machineSize.y, machineSize.z)
173 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
174 glVertex3f(machineSize.x, 0, machineSize.z)
177 glColor4ub(5, 171, 231, 96)
180 glVertex3f(0, 0, machineSize.z)
181 glVertex3f(machineSize.x, 0, machineSize.z)
182 glVertex3f(machineSize.x, 0, 0)
184 glVertex3f(0, machineSize.y, machineSize.z)
185 glVertex3f(0, machineSize.y, 0)
186 glVertex3f(machineSize.x, machineSize.y, 0)
187 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
190 glColor4ub(5, 171, 231, 128)
192 glVertex3f(0, 0, machineSize.z)
194 glVertex3f(0, machineSize.y, 0)
195 glVertex3f(0, machineSize.y, machineSize.z)
197 glVertex3f(machineSize.x, 0, 0)
198 glVertex3f(machineSize.x, 0, machineSize.z)
199 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
200 glVertex3f(machineSize.x, machineSize.y, 0)
205 #Draw the X/Y/Z indicator
225 glDisable(GL_DEPTH_TEST)
229 glTranslate(20, 0, 0)
230 noZ = ResetMatrixRotationAndScale()
231 glDrawStringCenter("X")
237 glTranslate(0, 20, 0)
238 glDrawStringCenter("Y")
245 glTranslate(0, 0, 20)
246 glDrawStringCenter("Z")
250 glEnable(GL_DEPTH_TEST)
252 def glDrawStringCenter(s):
254 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
256 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
258 def glGetStringSize(s):
261 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
265 def glDrawStringLeft(s):
268 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
270 def glDrawStringRight(s):
272 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
274 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
276 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
277 tx = float(texID % 4) / 4
278 ty = float(int(texID / 4)) / 8
288 glTranslatef(x, y, 0)
289 glEnable(GL_TEXTURE_2D)
291 glTexCoord2f(tx+tsx, ty)
295 glTexCoord2f(tx, ty+tsy)
297 glTexCoord2f(tx+tsx, ty+tsy)
302 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
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):
406 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
407 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
408 finalMatrix = npModelMatrix * npProjMatrix
409 finalMatrix = numpy.linalg.inv(finalMatrix)
411 viewport = map(float, viewport)
412 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))
413 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
414 ret = list(vector)[0:3] / vector[3]
417 def convert3x3MatrixTo4x4(matrix):
418 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
420 def loadGLTexture(filename):
421 tex = glGenTextures(1)
422 glBindTexture(GL_TEXTURE_2D, tex)
423 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
424 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
425 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
426 rgbData = img.GetData()
427 alphaData = img.GetAlphaData()
428 if alphaData is not None:
430 for i in xrange(0, len(alphaData)):
431 data += rgbData[i*3:i*3+3] + alphaData[i]
432 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
434 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
437 def ResetMatrixRotationAndScale():
438 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
442 scale2D = matrix[0][0]
453 if matrix[3][2] != 0.0:
454 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
455 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
458 matrix[0][0] = scale2D
459 matrix[1][1] = scale2D
460 matrix[2][2] = scale2D
464 glLoadMatrixf(matrix)
468 def DrawBox(vMin, vMax):
469 glBegin(GL_LINE_LOOP)
470 glVertex3f(vMin[0], vMin[1], vMin[2])
471 glVertex3f(vMax[0], vMin[1], vMin[2])
472 glVertex3f(vMax[0], vMax[1], vMin[2])
473 glVertex3f(vMin[0], vMax[1], vMin[2])
476 glBegin(GL_LINE_LOOP)
477 glVertex3f(vMin[0], vMin[1], vMax[2])
478 glVertex3f(vMax[0], vMin[1], vMax[2])
479 glVertex3f(vMax[0], vMax[1], vMax[2])
480 glVertex3f(vMin[0], vMax[1], vMax[2])
483 glVertex3f(vMin[0], vMin[1], vMin[2])
484 glVertex3f(vMin[0], vMin[1], vMax[2])
485 glVertex3f(vMax[0], vMin[1], vMin[2])
486 glVertex3f(vMax[0], vMin[1], vMax[2])
487 glVertex3f(vMax[0], vMax[1], vMin[2])
488 glVertex3f(vMax[0], vMax[1], vMax[2])
489 glVertex3f(vMin[0], vMax[1], vMin[2])
490 glVertex3f(vMin[0], vMax[1], vMax[2])
494 def DrawMeshOutline(mesh):
495 glEnable(GL_CULL_FACE)
496 glEnableClientState(GL_VERTEX_ARRAY);
497 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
501 glPolygonMode(GL_BACK, GL_LINE)
502 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
503 glPolygonMode(GL_BACK, GL_FILL)
506 glDisableClientState(GL_VERTEX_ARRAY)
509 def DrawMesh(mesh, insideOut = False):
510 glEnable(GL_CULL_FACE)
511 glEnableClientState(GL_VERTEX_ARRAY)
512 glEnableClientState(GL_NORMAL_ARRAY)
513 for m in mesh._meshList:
514 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
516 glNormalPointer(GL_FLOAT, 0, m.invNormal)
518 glNormalPointer(GL_FLOAT, 0, m.normal)
520 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
521 batchSize = 999 #Warning, batchSize needs to be dividable by 3
522 extraStartPos = int(m.vertexCount / batchSize) * batchSize
523 extraCount = m.vertexCount - extraStartPos
526 for i in xrange(0, int(m.vertexCount / batchSize)):
527 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
528 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
532 glNormalPointer(GL_FLOAT, 0, m.normal)
534 glNormalPointer(GL_FLOAT, 0, m.invNormal)
535 for i in xrange(0, int(m.vertexCount / batchSize)):
536 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
537 extraStartPos = int(m.vertexCount / batchSize) * batchSize
538 extraCount = m.vertexCount - extraStartPos
539 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
542 glDisableClientState(GL_VERTEX_ARRAY)
543 glDisableClientState(GL_NORMAL_ARRAY)
546 def DrawMeshSteep(mesh, matrix, angle):
547 cosAngle = math.sin(angle / 180.0 * math.pi)
548 glDisable(GL_LIGHTING)
549 glDepthFunc(GL_EQUAL)
550 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
551 for i in xrange(0, int(mesh.vertexCount), 3):
552 if normals[i][2] < -0.999999:
553 if mesh.vertexes[i + 0][2] > 0.01:
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 + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
558 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
560 elif normals[i][2] < -cosAngle:
561 glColor3f(-normals[i][2], 0, 0)
562 glBegin(GL_TRIANGLES)
563 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
564 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
565 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
567 elif normals[i][2] > 0.999999:
568 if mesh.vertexes[i + 0][2] > 0.01:
570 glBegin(GL_TRIANGLES)
571 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
572 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
573 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
575 elif normals[i][2] > cosAngle:
576 glColor3f(normals[i][2], 0, 0)
577 glBegin(GL_TRIANGLES)
578 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
579 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
580 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
584 def DrawGCodeLayer(layer, drawQuick = True):
585 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
586 filamentArea = math.pi * filamentRadius * filamentRadius
587 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
590 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
591 moveColor = [0, 0, 1, 0.5]
592 retractColor = [1, 0, 0.5, 0.5]
593 supportColor = [0, 1, 1, 1]
594 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
595 innerWallColor = [0, 1, 0, 1]
596 skirtColor = [0, 0.5, 0.5, 1]
597 prevPathWasRetract = False
599 glDisable(GL_CULL_FACE)
601 if path.type == 'move':
602 if prevPathWasRetract:
609 if path.type == 'extrude':
610 if path.pathType == 'FILL':
611 c = fillColorCycle[fillCycle]
612 fillCycle = (fillCycle + 1) % len(fillColorCycle)
613 elif path.pathType == 'WALL-INNER':
616 elif path.pathType == 'SUPPORT':
618 elif path.pathType == 'SKIRT':
621 c = extrudeColor[path.extruder]
622 if path.type == 'retract':
624 if path.type == 'extrude' and not drawQuick:
627 for i in xrange(0, len(path.points) - 1):
629 v1 = path.points[i + 1]
631 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
632 dist = (v0 - v1).vsize()
633 if dist > 0 and path.layerThickness > 0:
634 extrusionMMperDist = (v1.e - v0.e) / dist
635 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
637 drawLength += (v0 - v1).vsize()
638 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
641 vv2 = v0 + normal * lineWidth
642 vv3 = v1 + normal * lineWidth
643 vv0 = v0 - normal * lineWidth
644 vv1 = v1 - normal * lineWidth
648 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
649 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
650 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
651 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
653 if prevNormal is not None:
654 n = (normal + prevNormal)
656 vv4 = v0 + n * lineWidth
657 vv5 = v0 - n * lineWidth
660 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
661 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
662 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
663 glVertex3f(v0.x, v0.y, v0.z - zOffset)
665 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
666 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
667 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
668 glVertex3f(v0.x, v0.y, v0.z - zOffset)
675 glBegin(GL_LINE_STRIP)
677 for v in path.points:
678 glVertex3f(v[0], v[1], v[2])
680 if not path.type == 'move':
681 prevPathWasRetract = False
682 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
683 # prevPathWasRetract = True
684 glEnable(GL_CULL_FACE)