1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
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 def hasShaderSupport():
37 if bool(glCreateShader):
41 class GLShader(GLReferenceCounter):
42 def __init__(self, vertexProgram, fragmentProgram):
43 super(GLShader, self).__init__()
44 self._vertexString = vertexProgram
45 self._fragmentString = fragmentProgram
47 vertexShader = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
48 fragmentShader = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
50 #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.
51 # self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
52 self._program = glCreateProgram()
53 glAttachShader(self._program, vertexShader)
54 glAttachShader(self._program, fragmentShader)
55 glLinkProgram(self._program)
56 # Validation has to occur *after* linking
57 glValidateProgram(self._program)
58 if glGetProgramiv(self._program, GL_VALIDATE_STATUS) == GL_FALSE:
59 raise RuntimeError("Validation failure: %s"%(glGetProgramInfoLog(self._program)))
60 if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
61 raise RuntimeError("Link failure: %s" % (glGetProgramInfoLog(self._program)))
62 glDeleteShader(vertexShader)
63 glDeleteShader(fragmentShader)
64 except RuntimeError, e:
69 if self._program is not None:
70 shaders.glUseProgram(self._program)
73 shaders.glUseProgram(0)
76 if self._program is not None:
77 glDeleteProgram(self._program)
80 def setUniform(self, name, value):
81 if self._program is not None:
82 if type(value) is float:
83 glUniform1f(glGetUniformLocation(self._program, name), value)
84 elif type(value) is numpy.matrix:
85 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
87 print 'Unknown type for setUniform: %s' % (str(type(value)))
90 return self._program is not None
92 def getVertexShader(self):
93 return self._vertexString
95 def getFragmentShader(self):
96 return self._fragmentString
99 if self._program is not None and bool(glDeleteProgram):
100 print "Shader was not properly released!"
102 #A Class that acts as an OpenGL shader, but in reality is not none.
103 class GLFakeShader(GLReferenceCounter):
105 super(GLFakeShader, self).__init__()
108 glEnable(GL_LIGHTING)
110 glEnable(GL_COLOR_MATERIAL)
111 glLightfv(GL_LIGHT0, GL_DIFFUSE, [1,1,1,1])
112 glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,0])
113 glLightfv(GL_LIGHT0, GL_SPECULAR, [0,0,0,0])
116 glDisable(GL_LIGHTING)
121 def setUniform(self, name, value):
127 def getVertexShader(self):
130 def getFragmentShader(self):
133 class GLVBO(GLReferenceCounter):
134 def __init__(self, vertexArray, normalArray = None):
135 super(GLVBO, self).__init__()
136 if not bool(glGenBuffers):
137 self._vertexArray = vertexArray
138 self._normalArray = normalArray
139 self._size = len(vertexArray)
141 self._hasNormals = self._normalArray is not None
143 self._buffer = glGenBuffers(1)
144 self._size = len(vertexArray)
145 self._hasNormals = normalArray 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 def render(self, render_type = GL_TRIANGLES):
154 glEnableClientState(GL_VERTEX_ARRAY)
155 if self._buffer is None:
156 glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
158 glEnableClientState(GL_NORMAL_ARRAY)
159 glNormalPointer(GL_FLOAT, 0, self._normalArray)
161 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
163 glEnableClientState(GL_NORMAL_ARRAY)
164 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
165 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
167 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
169 batchSize = 996 #Warning, batchSize needs to be dividable by 4, 3 and 2
170 extraStartPos = int(self._size / batchSize) * batchSize
171 extraCount = self._size - extraStartPos
173 for i in xrange(0, int(self._size / batchSize)):
174 glDrawArrays(render_type, i * batchSize, batchSize)
175 glDrawArrays(render_type, extraStartPos, extraCount)
176 if self._buffer is not None:
177 glBindBuffer(GL_ARRAY_BUFFER, 0)
179 glDisableClientState(GL_VERTEX_ARRAY)
181 glDisableClientState(GL_NORMAL_ARRAY)
184 if self._buffer is not None:
185 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
186 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
187 glBindBuffer(GL_ARRAY_BUFFER, 0)
188 glDeleteBuffers(1, [self._buffer])
190 self._vertexArray = None
191 self._normalArray = None
194 if self._buffer is not None and bool(glDeleteBuffers):
195 print "VBO was not properly released!"
197 def DrawMachine(machineSize):
198 glDisable(GL_LIGHTING)
199 glDisable(GL_CULL_FACE)
201 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
205 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
206 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
211 x1 = max(min(x1, sx), 0)
212 y1 = max(min(y1, sy), 0)
213 x2 = max(min(x2, sx), 0)
214 y2 = max(min(y2, sy), 0)
215 if (x & 1) == (y & 1):
216 glColor4ub(5, 171, 231, 127)
218 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
220 glVertex3f(x1, y1, -0.02)
221 glVertex3f(x2, y1, -0.02)
222 glVertex3f(x2, y2, -0.02)
223 glVertex3f(x1, y2, -0.02)
226 glEnable(GL_CULL_FACE)
228 if profile.getPreference('machine_type') == 'ultimaker':
230 glEnable(GL_LIGHTING)
231 glTranslate(100, 200, -1)
232 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
233 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
235 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
238 if platformMesh is None:
240 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
245 DrawMesh(platformMesh)
247 glDisable(GL_LIGHTING)
248 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
250 glColor4ub(5, 171, 231, 64)
252 glVertex3f(0, 0, machineSize.z)
253 glVertex3f(0, machineSize.y, machineSize.z)
254 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
255 glVertex3f(machineSize.x, 0, machineSize.z)
258 glColor4ub(5, 171, 231, 96)
261 glVertex3f(0, 0, machineSize.z)
262 glVertex3f(machineSize.x, 0, machineSize.z)
263 glVertex3f(machineSize.x, 0, 0)
265 glVertex3f(0, machineSize.y, machineSize.z)
266 glVertex3f(0, machineSize.y, 0)
267 glVertex3f(machineSize.x, machineSize.y, 0)
268 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
271 glColor4ub(5, 171, 231, 128)
273 glVertex3f(0, 0, machineSize.z)
275 glVertex3f(0, machineSize.y, 0)
276 glVertex3f(0, machineSize.y, machineSize.z)
278 glVertex3f(machineSize.x, 0, 0)
279 glVertex3f(machineSize.x, 0, machineSize.z)
280 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
281 glVertex3f(machineSize.x, machineSize.y, 0)
286 #Draw the X/Y/Z indicator
306 glDisable(GL_DEPTH_TEST)
310 glTranslate(20, 0, 0)
311 noZ = ResetMatrixRotationAndScale()
312 glDrawStringCenter("X")
318 glTranslate(0, 20, 0)
319 glDrawStringCenter("Y")
326 glTranslate(0, 0, 20)
327 glDrawStringCenter("Z")
331 glEnable(GL_DEPTH_TEST)
333 def glDrawStringCenter(s):
335 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
337 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
339 def glGetStringSize(s):
342 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
346 def glDrawStringLeft(s):
352 glTranslate(0, 18 * n, 0)
357 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
359 def glDrawStringRight(s):
361 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
363 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
365 def glDrawQuad(x, y, w, h):
367 glTranslatef(x, y, 0)
368 glDisable(GL_TEXTURE_2D)
377 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
378 tx = float(texID % 4) / 4
379 ty = float(int(texID / 4)) / 8
389 glTranslatef(x, y, 0)
390 glEnable(GL_TEXTURE_2D)
392 glTexCoord2f(tx+tsx, ty)
396 glTexCoord2f(tx, ty+tsy)
398 glTexCoord2f(tx+tsx, ty+tsy)
403 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
404 tx0 = float(texID % 4) / 4
405 ty0 = float(int(texID / 4)) / 8
406 tx1 = tx0 + 0.25 / 2.0
407 ty1 = ty0 + 0.125 / 2.0
412 glTranslatef(x, y, 0)
413 glEnable(GL_TEXTURE_2D)
416 glTexCoord2f(tx1, ty0)
417 glVertex2f( cornerSize, 0)
418 glTexCoord2f(tx0, ty0)
420 glTexCoord2f(tx0, ty1)
421 glVertex2f( 0, cornerSize)
422 glTexCoord2f(tx1, ty1)
423 glVertex2f( cornerSize, cornerSize)
425 glTexCoord2f(tx2, ty0)
427 glTexCoord2f(tx1, ty0)
428 glVertex2f( w - cornerSize, 0)
429 glTexCoord2f(tx1, ty1)
430 glVertex2f( w - cornerSize, cornerSize)
431 glTexCoord2f(tx2, ty1)
432 glVertex2f( w, cornerSize)
434 glTexCoord2f(tx1, ty1)
435 glVertex2f( cornerSize, h - cornerSize)
436 glTexCoord2f(tx0, ty1)
437 glVertex2f( 0, h - cornerSize)
438 glTexCoord2f(tx0, ty2)
440 glTexCoord2f(tx1, ty2)
441 glVertex2f( cornerSize, h)
443 glTexCoord2f(tx2, ty1)
444 glVertex2f( w, h - cornerSize)
445 glTexCoord2f(tx1, ty1)
446 glVertex2f( w - cornerSize, h - cornerSize)
447 glTexCoord2f(tx1, ty2)
448 glVertex2f( w - cornerSize, h)
449 glTexCoord2f(tx2, ty2)
453 glTexCoord2f(tx1, ty1)
454 glVertex2f( w-cornerSize, cornerSize)
455 glTexCoord2f(tx1, ty1)
456 glVertex2f( cornerSize, cornerSize)
457 glTexCoord2f(tx1, ty1)
458 glVertex2f( cornerSize, h-cornerSize)
459 glTexCoord2f(tx1, ty1)
460 glVertex2f( w-cornerSize, h-cornerSize)
463 glTexCoord2f(tx2, ty1)
464 glVertex2f( w, cornerSize)
465 glTexCoord2f(tx1, ty1)
466 glVertex2f( w-cornerSize, cornerSize)
467 glTexCoord2f(tx1, ty1)
468 glVertex2f( w-cornerSize, h-cornerSize)
469 glTexCoord2f(tx2, ty1)
470 glVertex2f( w, h-cornerSize)
473 glTexCoord2f(tx1, ty1)
474 glVertex2f( cornerSize, cornerSize)
475 glTexCoord2f(tx0, ty1)
476 glVertex2f( 0, cornerSize)
477 glTexCoord2f(tx0, ty1)
478 glVertex2f( 0, h-cornerSize)
479 glTexCoord2f(tx1, ty1)
480 glVertex2f( cornerSize, h-cornerSize)
483 glTexCoord2f(tx1, ty0)
484 glVertex2f( w-cornerSize, 0)
485 glTexCoord2f(tx1, ty0)
486 glVertex2f( cornerSize, 0)
487 glTexCoord2f(tx1, ty1)
488 glVertex2f( cornerSize, cornerSize)
489 glTexCoord2f(tx1, ty1)
490 glVertex2f( w-cornerSize, cornerSize)
493 glTexCoord2f(tx1, ty1)
494 glVertex2f( w-cornerSize, h-cornerSize)
495 glTexCoord2f(tx1, ty1)
496 glVertex2f( cornerSize, h-cornerSize)
497 glTexCoord2f(tx1, ty2)
498 glVertex2f( cornerSize, h)
499 glTexCoord2f(tx1, ty2)
500 glVertex2f( w-cornerSize, h)
503 glDisable(GL_TEXTURE_2D)
506 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
507 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
508 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
509 finalMatrix = npModelMatrix * npProjMatrix
510 finalMatrix = numpy.linalg.inv(finalMatrix)
512 viewport = map(float, viewport)
513 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))
514 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
515 ret = list(vector)[0:3] / vector[3]
518 def convert3x3MatrixTo4x4(matrix):
519 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
521 def loadGLTexture(filename):
522 tex = glGenTextures(1)
523 glBindTexture(GL_TEXTURE_2D, tex)
524 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
526 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
527 rgbData = img.GetData()
528 alphaData = img.GetAlphaData()
529 if alphaData is not None:
531 for i in xrange(0, len(alphaData)):
532 data += rgbData[i*3:i*3+3] + alphaData[i]
533 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
535 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
538 def ResetMatrixRotationAndScale():
539 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
543 scale2D = matrix[0][0]
554 if matrix[3][2] != 0.0:
555 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
556 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
559 matrix[0][0] = scale2D
560 matrix[1][1] = scale2D
561 matrix[2][2] = scale2D
565 glLoadMatrixf(matrix)
569 def DrawBox(vMin, vMax):
570 glBegin(GL_LINE_LOOP)
571 glVertex3f(vMin[0], vMin[1], vMin[2])
572 glVertex3f(vMax[0], vMin[1], vMin[2])
573 glVertex3f(vMax[0], vMax[1], vMin[2])
574 glVertex3f(vMin[0], vMax[1], vMin[2])
577 glBegin(GL_LINE_LOOP)
578 glVertex3f(vMin[0], vMin[1], vMax[2])
579 glVertex3f(vMax[0], vMin[1], vMax[2])
580 glVertex3f(vMax[0], vMax[1], vMax[2])
581 glVertex3f(vMin[0], vMax[1], vMax[2])
584 glVertex3f(vMin[0], vMin[1], vMin[2])
585 glVertex3f(vMin[0], vMin[1], vMax[2])
586 glVertex3f(vMax[0], vMin[1], vMin[2])
587 glVertex3f(vMax[0], vMin[1], vMax[2])
588 glVertex3f(vMax[0], vMax[1], vMin[2])
589 glVertex3f(vMax[0], vMax[1], vMax[2])
590 glVertex3f(vMin[0], vMax[1], vMin[2])
591 glVertex3f(vMin[0], vMax[1], vMax[2])
595 def DrawMeshOutline(mesh):
596 glEnable(GL_CULL_FACE)
597 glEnableClientState(GL_VERTEX_ARRAY);
598 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
602 glPolygonMode(GL_BACK, GL_LINE)
603 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
604 glPolygonMode(GL_BACK, GL_FILL)
607 glDisableClientState(GL_VERTEX_ARRAY)
610 def DrawMesh(mesh, insideOut = False):
611 glEnable(GL_CULL_FACE)
612 glEnableClientState(GL_VERTEX_ARRAY)
613 glEnableClientState(GL_NORMAL_ARRAY)
614 for m in mesh._meshList:
615 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
617 glNormalPointer(GL_FLOAT, 0, m.invNormal)
619 glNormalPointer(GL_FLOAT, 0, m.normal)
621 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
622 batchSize = 999 #Warning, batchSize needs to be dividable by 3
623 extraStartPos = int(m.vertexCount / batchSize) * batchSize
624 extraCount = m.vertexCount - extraStartPos
627 for i in xrange(0, int(m.vertexCount / batchSize)):
628 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
629 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
633 glNormalPointer(GL_FLOAT, 0, m.normal)
635 glNormalPointer(GL_FLOAT, 0, m.invNormal)
636 for i in xrange(0, int(m.vertexCount / batchSize)):
637 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
638 extraStartPos = int(m.vertexCount / batchSize) * batchSize
639 extraCount = m.vertexCount - extraStartPos
640 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
643 glDisableClientState(GL_VERTEX_ARRAY)
644 glDisableClientState(GL_NORMAL_ARRAY)
647 def DrawMeshSteep(mesh, matrix, angle):
648 cosAngle = math.sin(angle / 180.0 * math.pi)
649 glDisable(GL_LIGHTING)
650 glDepthFunc(GL_EQUAL)
651 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
652 for i in xrange(0, int(mesh.vertexCount), 3):
653 if normals[i][2] < -0.999999:
654 if mesh.vertexes[i + 0][2] > 0.01:
656 glBegin(GL_TRIANGLES)
657 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
658 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
659 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
661 elif normals[i][2] < -cosAngle:
662 glColor3f(-normals[i][2], 0, 0)
663 glBegin(GL_TRIANGLES)
664 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
665 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
666 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
668 elif normals[i][2] > 0.999999:
669 if mesh.vertexes[i + 0][2] > 0.01:
671 glBegin(GL_TRIANGLES)
672 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
673 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
674 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
676 elif normals[i][2] > cosAngle:
677 glColor3f(normals[i][2], 0, 0)
678 glBegin(GL_TRIANGLES)
679 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
680 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
681 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
685 def DrawGCodeLayer(layer, drawQuick = True):
686 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
687 filamentArea = math.pi * filamentRadius * filamentRadius
688 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
691 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
692 moveColor = [0, 0, 1, 0.5]
693 retractColor = [1, 0, 0.5, 0.5]
694 supportColor = [0, 1, 1, 1]
695 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
696 innerWallColor = [0, 1, 0, 1]
697 skirtColor = [0, 0.5, 0.5, 1]
698 prevPathWasRetract = False
700 glDisable(GL_CULL_FACE)
702 if path.type == 'move':
703 if prevPathWasRetract:
710 if path.type == 'extrude':
711 if path.pathType == 'FILL':
712 c = fillColorCycle[fillCycle]
713 fillCycle = (fillCycle + 1) % len(fillColorCycle)
714 elif path.pathType == 'WALL-INNER':
717 elif path.pathType == 'SUPPORT':
719 elif path.pathType == 'SKIRT':
722 c = extrudeColor[path.extruder]
723 if path.type == 'retract':
725 if path.type == 'extrude' and not drawQuick:
728 for i in xrange(0, len(path.points) - 1):
730 v1 = path.points[i + 1]
732 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
733 dist = (v0 - v1).vsize()
734 if dist > 0 and path.layerThickness > 0:
735 extrusionMMperDist = (v1.e - v0.e) / dist
736 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
738 drawLength += (v0 - v1).vsize()
739 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
742 vv2 = v0 + normal * lineWidth
743 vv3 = v1 + normal * lineWidth
744 vv0 = v0 - normal * lineWidth
745 vv1 = v1 - normal * lineWidth
749 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
750 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
751 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
752 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
754 if prevNormal is not None:
755 n = (normal + prevNormal)
757 vv4 = v0 + n * lineWidth
758 vv5 = v0 - n * lineWidth
761 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
762 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
763 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
764 glVertex3f(v0.x, v0.y, v0.z - zOffset)
766 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
767 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
768 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
769 glVertex3f(v0.x, v0.y, v0.z - zOffset)
777 glBegin(GL_TRIANGLES)
778 for v in path.points:
779 glVertex3f(v[0], v[1], v[2])
782 if not path.type == 'move':
783 prevPathWasRetract = False
784 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
785 # prevPathWasRetract = True
786 glEnable(GL_CULL_FACE)