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 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 if type(value) is float:
66 glUniform1f(glGetUniformLocation(self._program, name), value)
67 elif type(value) is numpy.matrix:
68 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
70 print 'Unknown type for setUniform: %s' % (str(type(value)))
73 return self._program is not None
75 def getVertexShader(self):
76 return self._vertexString
78 def getFragmentShader(self):
79 return self._fragmentString
82 if self._program is not None and bool(glDeleteProgram):
83 print "Shader was not properly released!"
85 class GLVBO(GLReferenceCounter):
86 def __init__(self, vertexArray, normalArray = None):
87 super(GLVBO, self).__init__()
88 self._buffer = glGenBuffers(1)
89 self._size = len(vertexArray)
90 self._hasNormals = normalArray is not None
91 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
93 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
95 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
96 glBindBuffer(GL_ARRAY_BUFFER, 0)
98 def render(self, render_type = GL_TRIANGLES):
99 glEnableClientState(GL_VERTEX_ARRAY)
100 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
103 glEnableClientState(GL_NORMAL_ARRAY)
104 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
105 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
107 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
109 batchSize = 996 #Warning, batchSize needs to be dividable by 4, 3 and 2
110 extraStartPos = int(self._size / batchSize) * batchSize
111 extraCount = self._size - extraStartPos
113 for i in xrange(0, int(self._size / batchSize)):
114 glDrawArrays(render_type, i * batchSize, batchSize)
115 glDrawArrays(render_type, extraStartPos, extraCount)
116 glBindBuffer(GL_ARRAY_BUFFER, 0)
118 glDisableClientState(GL_VERTEX_ARRAY)
120 glDisableClientState(GL_NORMAL_ARRAY)
123 if self._buffer is not None:
124 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
125 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
126 glBindBuffer(GL_ARRAY_BUFFER, 0)
127 glDeleteBuffers(1, [self._buffer])
131 if self._buffer is not None and bool(glDeleteBuffers):
132 print "VBO was not properly released!"
134 def DrawMachine(machineSize):
135 glDisable(GL_LIGHTING)
136 glDisable(GL_CULL_FACE)
138 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
142 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
143 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
148 x1 = max(min(x1, sx), 0)
149 y1 = max(min(y1, sy), 0)
150 x2 = max(min(x2, sx), 0)
151 y2 = max(min(y2, sy), 0)
152 if (x & 1) == (y & 1):
153 glColor4ub(5, 171, 231, 127)
155 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
157 glVertex3f(x1, y1, -0.02)
158 glVertex3f(x2, y1, -0.02)
159 glVertex3f(x2, y2, -0.02)
160 glVertex3f(x1, y2, -0.02)
163 glEnable(GL_CULL_FACE)
165 if profile.getPreference('machine_type') == 'ultimaker':
167 glEnable(GL_LIGHTING)
168 glTranslate(100, 200, -1)
169 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
170 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
172 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
175 if platformMesh is None:
177 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
182 DrawMesh(platformMesh)
184 glDisable(GL_LIGHTING)
185 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
187 glColor4ub(5, 171, 231, 64)
189 glVertex3f(0, 0, machineSize.z)
190 glVertex3f(0, machineSize.y, machineSize.z)
191 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
192 glVertex3f(machineSize.x, 0, machineSize.z)
195 glColor4ub(5, 171, 231, 96)
198 glVertex3f(0, 0, machineSize.z)
199 glVertex3f(machineSize.x, 0, machineSize.z)
200 glVertex3f(machineSize.x, 0, 0)
202 glVertex3f(0, machineSize.y, machineSize.z)
203 glVertex3f(0, machineSize.y, 0)
204 glVertex3f(machineSize.x, machineSize.y, 0)
205 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
208 glColor4ub(5, 171, 231, 128)
210 glVertex3f(0, 0, machineSize.z)
212 glVertex3f(0, machineSize.y, 0)
213 glVertex3f(0, machineSize.y, machineSize.z)
215 glVertex3f(machineSize.x, 0, 0)
216 glVertex3f(machineSize.x, 0, machineSize.z)
217 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
218 glVertex3f(machineSize.x, machineSize.y, 0)
223 #Draw the X/Y/Z indicator
243 glDisable(GL_DEPTH_TEST)
247 glTranslate(20, 0, 0)
248 noZ = ResetMatrixRotationAndScale()
249 glDrawStringCenter("X")
255 glTranslate(0, 20, 0)
256 glDrawStringCenter("Y")
263 glTranslate(0, 0, 20)
264 glDrawStringCenter("Z")
268 glEnable(GL_DEPTH_TEST)
270 def glDrawStringCenter(s):
272 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
274 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
276 def glGetStringSize(s):
279 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
283 def glDrawStringLeft(s):
289 glTranslate(0, 18 * n, 0)
294 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
296 def glDrawStringRight(s):
298 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
300 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
302 def glDrawQuad(x, y, w, h):
304 glTranslatef(x, y, 0)
305 glDisable(GL_TEXTURE_2D)
314 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
315 tx = float(texID % 4) / 4
316 ty = float(int(texID / 4)) / 8
326 glTranslatef(x, y, 0)
327 glEnable(GL_TEXTURE_2D)
329 glTexCoord2f(tx+tsx, ty)
333 glTexCoord2f(tx, ty+tsy)
335 glTexCoord2f(tx+tsx, ty+tsy)
340 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
341 tx0 = float(texID % 4) / 4
342 ty0 = float(int(texID / 4)) / 8
343 tx1 = tx0 + 0.25 / 2.0
344 ty1 = ty0 + 0.125 / 2.0
349 glTranslatef(x, y, 0)
350 glEnable(GL_TEXTURE_2D)
353 glTexCoord2f(tx1, ty0)
354 glVertex2f( cornerSize, 0)
355 glTexCoord2f(tx0, ty0)
357 glTexCoord2f(tx0, ty1)
358 glVertex2f( 0, cornerSize)
359 glTexCoord2f(tx1, ty1)
360 glVertex2f( cornerSize, cornerSize)
362 glTexCoord2f(tx2, ty0)
364 glTexCoord2f(tx1, ty0)
365 glVertex2f( w - cornerSize, 0)
366 glTexCoord2f(tx1, ty1)
367 glVertex2f( w - cornerSize, cornerSize)
368 glTexCoord2f(tx2, ty1)
369 glVertex2f( w, cornerSize)
371 glTexCoord2f(tx1, ty1)
372 glVertex2f( cornerSize, h - cornerSize)
373 glTexCoord2f(tx0, ty1)
374 glVertex2f( 0, h - cornerSize)
375 glTexCoord2f(tx0, ty2)
377 glTexCoord2f(tx1, ty2)
378 glVertex2f( cornerSize, h)
380 glTexCoord2f(tx2, ty1)
381 glVertex2f( w, h - cornerSize)
382 glTexCoord2f(tx1, ty1)
383 glVertex2f( w - cornerSize, h - cornerSize)
384 glTexCoord2f(tx1, ty2)
385 glVertex2f( w - cornerSize, h)
386 glTexCoord2f(tx2, ty2)
390 glTexCoord2f(tx1, ty1)
391 glVertex2f( w-cornerSize, cornerSize)
392 glTexCoord2f(tx1, ty1)
393 glVertex2f( cornerSize, cornerSize)
394 glTexCoord2f(tx1, ty1)
395 glVertex2f( cornerSize, h-cornerSize)
396 glTexCoord2f(tx1, ty1)
397 glVertex2f( w-cornerSize, h-cornerSize)
400 glTexCoord2f(tx2, ty1)
401 glVertex2f( w, cornerSize)
402 glTexCoord2f(tx1, ty1)
403 glVertex2f( w-cornerSize, cornerSize)
404 glTexCoord2f(tx1, ty1)
405 glVertex2f( w-cornerSize, h-cornerSize)
406 glTexCoord2f(tx2, ty1)
407 glVertex2f( w, h-cornerSize)
410 glTexCoord2f(tx1, ty1)
411 glVertex2f( cornerSize, cornerSize)
412 glTexCoord2f(tx0, ty1)
413 glVertex2f( 0, cornerSize)
414 glTexCoord2f(tx0, ty1)
415 glVertex2f( 0, h-cornerSize)
416 glTexCoord2f(tx1, ty1)
417 glVertex2f( cornerSize, h-cornerSize)
420 glTexCoord2f(tx1, ty0)
421 glVertex2f( w-cornerSize, 0)
422 glTexCoord2f(tx1, ty0)
423 glVertex2f( cornerSize, 0)
424 glTexCoord2f(tx1, ty1)
425 glVertex2f( cornerSize, cornerSize)
426 glTexCoord2f(tx1, ty1)
427 glVertex2f( w-cornerSize, cornerSize)
430 glTexCoord2f(tx1, ty1)
431 glVertex2f( w-cornerSize, h-cornerSize)
432 glTexCoord2f(tx1, ty1)
433 glVertex2f( cornerSize, h-cornerSize)
434 glTexCoord2f(tx1, ty2)
435 glVertex2f( cornerSize, h)
436 glTexCoord2f(tx1, ty2)
437 glVertex2f( w-cornerSize, h)
440 glDisable(GL_TEXTURE_2D)
443 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
444 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
445 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
446 finalMatrix = npModelMatrix * npProjMatrix
447 finalMatrix = numpy.linalg.inv(finalMatrix)
449 viewport = map(float, viewport)
450 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))
451 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
452 ret = list(vector)[0:3] / vector[3]
455 def convert3x3MatrixTo4x4(matrix):
456 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
458 def loadGLTexture(filename):
459 tex = glGenTextures(1)
460 glBindTexture(GL_TEXTURE_2D, tex)
461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
463 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
464 rgbData = img.GetData()
465 alphaData = img.GetAlphaData()
466 if alphaData is not None:
468 for i in xrange(0, len(alphaData)):
469 data += rgbData[i*3:i*3+3] + alphaData[i]
470 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
472 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
475 def ResetMatrixRotationAndScale():
476 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
480 scale2D = matrix[0][0]
491 if matrix[3][2] != 0.0:
492 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
493 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
496 matrix[0][0] = scale2D
497 matrix[1][1] = scale2D
498 matrix[2][2] = scale2D
502 glLoadMatrixf(matrix)
506 def DrawBox(vMin, vMax):
507 glBegin(GL_LINE_LOOP)
508 glVertex3f(vMin[0], vMin[1], vMin[2])
509 glVertex3f(vMax[0], vMin[1], vMin[2])
510 glVertex3f(vMax[0], vMax[1], vMin[2])
511 glVertex3f(vMin[0], vMax[1], vMin[2])
514 glBegin(GL_LINE_LOOP)
515 glVertex3f(vMin[0], vMin[1], vMax[2])
516 glVertex3f(vMax[0], vMin[1], vMax[2])
517 glVertex3f(vMax[0], vMax[1], vMax[2])
518 glVertex3f(vMin[0], vMax[1], vMax[2])
521 glVertex3f(vMin[0], vMin[1], vMin[2])
522 glVertex3f(vMin[0], vMin[1], vMax[2])
523 glVertex3f(vMax[0], vMin[1], vMin[2])
524 glVertex3f(vMax[0], vMin[1], vMax[2])
525 glVertex3f(vMax[0], vMax[1], vMin[2])
526 glVertex3f(vMax[0], vMax[1], vMax[2])
527 glVertex3f(vMin[0], vMax[1], vMin[2])
528 glVertex3f(vMin[0], vMax[1], vMax[2])
532 def DrawMeshOutline(mesh):
533 glEnable(GL_CULL_FACE)
534 glEnableClientState(GL_VERTEX_ARRAY);
535 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
539 glPolygonMode(GL_BACK, GL_LINE)
540 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
541 glPolygonMode(GL_BACK, GL_FILL)
544 glDisableClientState(GL_VERTEX_ARRAY)
547 def DrawMesh(mesh, insideOut = False):
548 glEnable(GL_CULL_FACE)
549 glEnableClientState(GL_VERTEX_ARRAY)
550 glEnableClientState(GL_NORMAL_ARRAY)
551 for m in mesh._meshList:
552 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
554 glNormalPointer(GL_FLOAT, 0, m.invNormal)
556 glNormalPointer(GL_FLOAT, 0, m.normal)
558 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
559 batchSize = 999 #Warning, batchSize needs to be dividable by 3
560 extraStartPos = int(m.vertexCount / batchSize) * batchSize
561 extraCount = m.vertexCount - extraStartPos
564 for i in xrange(0, int(m.vertexCount / batchSize)):
565 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
566 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
570 glNormalPointer(GL_FLOAT, 0, m.normal)
572 glNormalPointer(GL_FLOAT, 0, m.invNormal)
573 for i in xrange(0, int(m.vertexCount / batchSize)):
574 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
575 extraStartPos = int(m.vertexCount / batchSize) * batchSize
576 extraCount = m.vertexCount - extraStartPos
577 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
580 glDisableClientState(GL_VERTEX_ARRAY)
581 glDisableClientState(GL_NORMAL_ARRAY)
584 def DrawMeshSteep(mesh, matrix, angle):
585 cosAngle = math.sin(angle / 180.0 * math.pi)
586 glDisable(GL_LIGHTING)
587 glDepthFunc(GL_EQUAL)
588 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
589 for i in xrange(0, int(mesh.vertexCount), 3):
590 if normals[i][2] < -0.999999:
591 if mesh.vertexes[i + 0][2] > 0.01:
593 glBegin(GL_TRIANGLES)
594 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
595 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
596 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
598 elif normals[i][2] < -cosAngle:
599 glColor3f(-normals[i][2], 0, 0)
600 glBegin(GL_TRIANGLES)
601 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
602 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
603 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
605 elif normals[i][2] > 0.999999:
606 if mesh.vertexes[i + 0][2] > 0.01:
608 glBegin(GL_TRIANGLES)
609 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
610 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
611 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
613 elif normals[i][2] > cosAngle:
614 glColor3f(normals[i][2], 0, 0)
615 glBegin(GL_TRIANGLES)
616 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
617 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
618 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
622 def DrawGCodeLayer(layer, drawQuick = True):
623 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
624 filamentArea = math.pi * filamentRadius * filamentRadius
625 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
628 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
629 moveColor = [0, 0, 1, 0.5]
630 retractColor = [1, 0, 0.5, 0.5]
631 supportColor = [0, 1, 1, 1]
632 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
633 innerWallColor = [0, 1, 0, 1]
634 skirtColor = [0, 0.5, 0.5, 1]
635 prevPathWasRetract = False
637 glDisable(GL_CULL_FACE)
639 if path.type == 'move':
640 if prevPathWasRetract:
647 if path.type == 'extrude':
648 if path.pathType == 'FILL':
649 c = fillColorCycle[fillCycle]
650 fillCycle = (fillCycle + 1) % len(fillColorCycle)
651 elif path.pathType == 'WALL-INNER':
654 elif path.pathType == 'SUPPORT':
656 elif path.pathType == 'SKIRT':
659 c = extrudeColor[path.extruder]
660 if path.type == 'retract':
662 if path.type == 'extrude' and not drawQuick:
665 for i in xrange(0, len(path.points) - 1):
667 v1 = path.points[i + 1]
669 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
670 dist = (v0 - v1).vsize()
671 if dist > 0 and path.layerThickness > 0:
672 extrusionMMperDist = (v1.e - v0.e) / dist
673 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
675 drawLength += (v0 - v1).vsize()
676 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
679 vv2 = v0 + normal * lineWidth
680 vv3 = v1 + normal * lineWidth
681 vv0 = v0 - normal * lineWidth
682 vv1 = v1 - normal * lineWidth
686 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
687 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
688 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
689 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
691 if prevNormal is not None:
692 n = (normal + prevNormal)
694 vv4 = v0 + n * lineWidth
695 vv5 = v0 - n * lineWidth
698 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
699 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
700 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
701 glVertex3f(v0.x, v0.y, v0.z - zOffset)
703 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
704 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
705 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
706 glVertex3f(v0.x, v0.y, v0.z - zOffset)
714 glBegin(GL_TRIANGLES)
715 for v in path.points:
716 glVertex3f(v[0], v[1], v[2])
719 if not path.type == 'move':
720 prevPathWasRetract = False
721 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
722 # prevPathWasRetract = True
723 glEnable(GL_CULL_FACE)