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 return glCreateShader != False
39 class GLShader(GLReferenceCounter):
40 def __init__(self, vertexProgram, fragmentProgram):
41 super(GLShader, self).__init__()
42 self._vertexString = vertexProgram
43 self._fragmentString = fragmentProgram
45 self._vertexProgram = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
46 self._fragmentProgram = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
47 self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
48 except RuntimeError, e:
53 if self._program is not None:
54 shaders.glUseProgram(self._program)
57 shaders.glUseProgram(0)
60 if self._program is not None:
61 shaders.glDeleteShader(self._vertexProgram)
62 shaders.glDeleteShader(self._fragmentProgram)
63 glDeleteProgram(self._program)
66 def setUniform(self, name, value):
67 if self._program is not None:
68 if type(value) is float:
69 glUniform1f(glGetUniformLocation(self._program, name), value)
70 elif type(value) is numpy.matrix:
71 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
73 print 'Unknown type for setUniform: %s' % (str(type(value)))
76 return self._program is not None
78 def getVertexShader(self):
79 return self._vertexString
81 def getFragmentShader(self):
82 return self._fragmentString
85 if self._program is not None and bool(glDeleteProgram):
86 print "Shader was not properly released!"
88 #A Class that acts as an OpenGL shader, but in reality is not none.
89 class GLFakeShader(GLReferenceCounter):
91 super(GLFakeShader, self).__init__()
96 glEnable(GL_COLOR_MATERIAL)
97 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.3,0.3,0.3,1])
98 glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,0])
101 glDisable(GL_LIGHTING)
106 def setUniform(self, name, value):
112 def getVertexShader(self):
115 def getFragmentShader(self):
118 class GLVBO(GLReferenceCounter):
119 def __init__(self, vertexArray, normalArray = None):
120 super(GLVBO, self).__init__()
121 self._buffer = glGenBuffers(1)
122 self._size = len(vertexArray)
123 self._hasNormals = normalArray is not None
124 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
126 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
128 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
129 glBindBuffer(GL_ARRAY_BUFFER, 0)
131 def render(self, render_type = GL_TRIANGLES):
132 glEnableClientState(GL_VERTEX_ARRAY)
133 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
136 glEnableClientState(GL_NORMAL_ARRAY)
137 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
138 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
140 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
142 batchSize = 996 #Warning, batchSize needs to be dividable by 4, 3 and 2
143 extraStartPos = int(self._size / batchSize) * batchSize
144 extraCount = self._size - extraStartPos
146 for i in xrange(0, int(self._size / batchSize)):
147 glDrawArrays(render_type, i * batchSize, batchSize)
148 glDrawArrays(render_type, extraStartPos, extraCount)
149 glBindBuffer(GL_ARRAY_BUFFER, 0)
151 glDisableClientState(GL_VERTEX_ARRAY)
153 glDisableClientState(GL_NORMAL_ARRAY)
156 if self._buffer is not None:
157 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
158 glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
159 glBindBuffer(GL_ARRAY_BUFFER, 0)
160 glDeleteBuffers(1, [self._buffer])
164 if self._buffer is not None and bool(glDeleteBuffers):
165 print "VBO was not properly released!"
167 def DrawMachine(machineSize):
168 glDisable(GL_LIGHTING)
169 glDisable(GL_CULL_FACE)
171 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
175 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
176 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
181 x1 = max(min(x1, sx), 0)
182 y1 = max(min(y1, sy), 0)
183 x2 = max(min(x2, sx), 0)
184 y2 = max(min(y2, sy), 0)
185 if (x & 1) == (y & 1):
186 glColor4ub(5, 171, 231, 127)
188 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
190 glVertex3f(x1, y1, -0.02)
191 glVertex3f(x2, y1, -0.02)
192 glVertex3f(x2, y2, -0.02)
193 glVertex3f(x1, y2, -0.02)
196 glEnable(GL_CULL_FACE)
198 if profile.getPreference('machine_type') == 'ultimaker':
200 glEnable(GL_LIGHTING)
201 glTranslate(100, 200, -1)
202 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
203 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
205 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
208 if platformMesh is None:
210 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
215 DrawMesh(platformMesh)
217 glDisable(GL_LIGHTING)
218 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
220 glColor4ub(5, 171, 231, 64)
222 glVertex3f(0, 0, machineSize.z)
223 glVertex3f(0, machineSize.y, machineSize.z)
224 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
225 glVertex3f(machineSize.x, 0, machineSize.z)
228 glColor4ub(5, 171, 231, 96)
231 glVertex3f(0, 0, machineSize.z)
232 glVertex3f(machineSize.x, 0, machineSize.z)
233 glVertex3f(machineSize.x, 0, 0)
235 glVertex3f(0, machineSize.y, machineSize.z)
236 glVertex3f(0, machineSize.y, 0)
237 glVertex3f(machineSize.x, machineSize.y, 0)
238 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
241 glColor4ub(5, 171, 231, 128)
243 glVertex3f(0, 0, machineSize.z)
245 glVertex3f(0, machineSize.y, 0)
246 glVertex3f(0, machineSize.y, machineSize.z)
248 glVertex3f(machineSize.x, 0, 0)
249 glVertex3f(machineSize.x, 0, machineSize.z)
250 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
251 glVertex3f(machineSize.x, machineSize.y, 0)
256 #Draw the X/Y/Z indicator
276 glDisable(GL_DEPTH_TEST)
280 glTranslate(20, 0, 0)
281 noZ = ResetMatrixRotationAndScale()
282 glDrawStringCenter("X")
288 glTranslate(0, 20, 0)
289 glDrawStringCenter("Y")
296 glTranslate(0, 0, 20)
297 glDrawStringCenter("Z")
301 glEnable(GL_DEPTH_TEST)
303 def glDrawStringCenter(s):
305 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
307 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
309 def glGetStringSize(s):
312 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
316 def glDrawStringLeft(s):
322 glTranslate(0, 18 * n, 0)
327 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
329 def glDrawStringRight(s):
331 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
333 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
335 def glDrawQuad(x, y, w, h):
337 glTranslatef(x, y, 0)
338 glDisable(GL_TEXTURE_2D)
347 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
348 tx = float(texID % 4) / 4
349 ty = float(int(texID / 4)) / 8
359 glTranslatef(x, y, 0)
360 glEnable(GL_TEXTURE_2D)
362 glTexCoord2f(tx+tsx, ty)
366 glTexCoord2f(tx, ty+tsy)
368 glTexCoord2f(tx+tsx, ty+tsy)
373 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
374 tx0 = float(texID % 4) / 4
375 ty0 = float(int(texID / 4)) / 8
376 tx1 = tx0 + 0.25 / 2.0
377 ty1 = ty0 + 0.125 / 2.0
382 glTranslatef(x, y, 0)
383 glEnable(GL_TEXTURE_2D)
386 glTexCoord2f(tx1, ty0)
387 glVertex2f( cornerSize, 0)
388 glTexCoord2f(tx0, ty0)
390 glTexCoord2f(tx0, ty1)
391 glVertex2f( 0, cornerSize)
392 glTexCoord2f(tx1, ty1)
393 glVertex2f( cornerSize, cornerSize)
395 glTexCoord2f(tx2, ty0)
397 glTexCoord2f(tx1, ty0)
398 glVertex2f( w - cornerSize, 0)
399 glTexCoord2f(tx1, ty1)
400 glVertex2f( w - cornerSize, cornerSize)
401 glTexCoord2f(tx2, ty1)
402 glVertex2f( w, cornerSize)
404 glTexCoord2f(tx1, ty1)
405 glVertex2f( cornerSize, h - cornerSize)
406 glTexCoord2f(tx0, ty1)
407 glVertex2f( 0, h - cornerSize)
408 glTexCoord2f(tx0, ty2)
410 glTexCoord2f(tx1, ty2)
411 glVertex2f( cornerSize, h)
413 glTexCoord2f(tx2, ty1)
414 glVertex2f( w, h - cornerSize)
415 glTexCoord2f(tx1, ty1)
416 glVertex2f( w - cornerSize, h - cornerSize)
417 glTexCoord2f(tx1, ty2)
418 glVertex2f( w - cornerSize, h)
419 glTexCoord2f(tx2, ty2)
423 glTexCoord2f(tx1, ty1)
424 glVertex2f( w-cornerSize, cornerSize)
425 glTexCoord2f(tx1, ty1)
426 glVertex2f( cornerSize, cornerSize)
427 glTexCoord2f(tx1, ty1)
428 glVertex2f( cornerSize, h-cornerSize)
429 glTexCoord2f(tx1, ty1)
430 glVertex2f( w-cornerSize, h-cornerSize)
433 glTexCoord2f(tx2, ty1)
434 glVertex2f( w, cornerSize)
435 glTexCoord2f(tx1, ty1)
436 glVertex2f( w-cornerSize, cornerSize)
437 glTexCoord2f(tx1, ty1)
438 glVertex2f( w-cornerSize, h-cornerSize)
439 glTexCoord2f(tx2, ty1)
440 glVertex2f( w, h-cornerSize)
443 glTexCoord2f(tx1, ty1)
444 glVertex2f( cornerSize, cornerSize)
445 glTexCoord2f(tx0, ty1)
446 glVertex2f( 0, cornerSize)
447 glTexCoord2f(tx0, ty1)
448 glVertex2f( 0, h-cornerSize)
449 glTexCoord2f(tx1, ty1)
450 glVertex2f( cornerSize, h-cornerSize)
453 glTexCoord2f(tx1, ty0)
454 glVertex2f( w-cornerSize, 0)
455 glTexCoord2f(tx1, ty0)
456 glVertex2f( cornerSize, 0)
457 glTexCoord2f(tx1, ty1)
458 glVertex2f( cornerSize, cornerSize)
459 glTexCoord2f(tx1, ty1)
460 glVertex2f( w-cornerSize, cornerSize)
463 glTexCoord2f(tx1, ty1)
464 glVertex2f( w-cornerSize, h-cornerSize)
465 glTexCoord2f(tx1, ty1)
466 glVertex2f( cornerSize, h-cornerSize)
467 glTexCoord2f(tx1, ty2)
468 glVertex2f( cornerSize, h)
469 glTexCoord2f(tx1, ty2)
470 glVertex2f( w-cornerSize, h)
473 glDisable(GL_TEXTURE_2D)
476 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
477 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
478 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
479 finalMatrix = npModelMatrix * npProjMatrix
480 finalMatrix = numpy.linalg.inv(finalMatrix)
482 viewport = map(float, viewport)
483 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))
484 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
485 ret = list(vector)[0:3] / vector[3]
488 def convert3x3MatrixTo4x4(matrix):
489 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
491 def loadGLTexture(filename):
492 tex = glGenTextures(1)
493 glBindTexture(GL_TEXTURE_2D, tex)
494 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
496 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
497 rgbData = img.GetData()
498 alphaData = img.GetAlphaData()
499 if alphaData is not None:
501 for i in xrange(0, len(alphaData)):
502 data += rgbData[i*3:i*3+3] + alphaData[i]
503 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
505 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
508 def ResetMatrixRotationAndScale():
509 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
513 scale2D = matrix[0][0]
524 if matrix[3][2] != 0.0:
525 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
526 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
529 matrix[0][0] = scale2D
530 matrix[1][1] = scale2D
531 matrix[2][2] = scale2D
535 glLoadMatrixf(matrix)
539 def DrawBox(vMin, vMax):
540 glBegin(GL_LINE_LOOP)
541 glVertex3f(vMin[0], vMin[1], vMin[2])
542 glVertex3f(vMax[0], vMin[1], vMin[2])
543 glVertex3f(vMax[0], vMax[1], vMin[2])
544 glVertex3f(vMin[0], vMax[1], vMin[2])
547 glBegin(GL_LINE_LOOP)
548 glVertex3f(vMin[0], vMin[1], vMax[2])
549 glVertex3f(vMax[0], vMin[1], vMax[2])
550 glVertex3f(vMax[0], vMax[1], vMax[2])
551 glVertex3f(vMin[0], vMax[1], vMax[2])
554 glVertex3f(vMin[0], vMin[1], vMin[2])
555 glVertex3f(vMin[0], vMin[1], vMax[2])
556 glVertex3f(vMax[0], vMin[1], vMin[2])
557 glVertex3f(vMax[0], vMin[1], vMax[2])
558 glVertex3f(vMax[0], vMax[1], vMin[2])
559 glVertex3f(vMax[0], vMax[1], vMax[2])
560 glVertex3f(vMin[0], vMax[1], vMin[2])
561 glVertex3f(vMin[0], vMax[1], vMax[2])
565 def DrawMeshOutline(mesh):
566 glEnable(GL_CULL_FACE)
567 glEnableClientState(GL_VERTEX_ARRAY);
568 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
572 glPolygonMode(GL_BACK, GL_LINE)
573 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
574 glPolygonMode(GL_BACK, GL_FILL)
577 glDisableClientState(GL_VERTEX_ARRAY)
580 def DrawMesh(mesh, insideOut = False):
581 glEnable(GL_CULL_FACE)
582 glEnableClientState(GL_VERTEX_ARRAY)
583 glEnableClientState(GL_NORMAL_ARRAY)
584 for m in mesh._meshList:
585 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
587 glNormalPointer(GL_FLOAT, 0, m.invNormal)
589 glNormalPointer(GL_FLOAT, 0, m.normal)
591 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
592 batchSize = 999 #Warning, batchSize needs to be dividable by 3
593 extraStartPos = int(m.vertexCount / batchSize) * batchSize
594 extraCount = m.vertexCount - extraStartPos
597 for i in xrange(0, int(m.vertexCount / batchSize)):
598 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
599 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
603 glNormalPointer(GL_FLOAT, 0, m.normal)
605 glNormalPointer(GL_FLOAT, 0, m.invNormal)
606 for i in xrange(0, int(m.vertexCount / batchSize)):
607 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
608 extraStartPos = int(m.vertexCount / batchSize) * batchSize
609 extraCount = m.vertexCount - extraStartPos
610 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
613 glDisableClientState(GL_VERTEX_ARRAY)
614 glDisableClientState(GL_NORMAL_ARRAY)
617 def DrawMeshSteep(mesh, matrix, angle):
618 cosAngle = math.sin(angle / 180.0 * math.pi)
619 glDisable(GL_LIGHTING)
620 glDepthFunc(GL_EQUAL)
621 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
622 for i in xrange(0, int(mesh.vertexCount), 3):
623 if normals[i][2] < -0.999999:
624 if mesh.vertexes[i + 0][2] > 0.01:
626 glBegin(GL_TRIANGLES)
627 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
628 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
629 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
631 elif normals[i][2] < -cosAngle:
632 glColor3f(-normals[i][2], 0, 0)
633 glBegin(GL_TRIANGLES)
634 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
635 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
636 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
638 elif normals[i][2] > 0.999999:
639 if mesh.vertexes[i + 0][2] > 0.01:
641 glBegin(GL_TRIANGLES)
642 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
643 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
644 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
646 elif normals[i][2] > cosAngle:
647 glColor3f(normals[i][2], 0, 0)
648 glBegin(GL_TRIANGLES)
649 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
650 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
651 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
655 def DrawGCodeLayer(layer, drawQuick = True):
656 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
657 filamentArea = math.pi * filamentRadius * filamentRadius
658 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
661 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
662 moveColor = [0, 0, 1, 0.5]
663 retractColor = [1, 0, 0.5, 0.5]
664 supportColor = [0, 1, 1, 1]
665 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
666 innerWallColor = [0, 1, 0, 1]
667 skirtColor = [0, 0.5, 0.5, 1]
668 prevPathWasRetract = False
670 glDisable(GL_CULL_FACE)
672 if path.type == 'move':
673 if prevPathWasRetract:
680 if path.type == 'extrude':
681 if path.pathType == 'FILL':
682 c = fillColorCycle[fillCycle]
683 fillCycle = (fillCycle + 1) % len(fillColorCycle)
684 elif path.pathType == 'WALL-INNER':
687 elif path.pathType == 'SUPPORT':
689 elif path.pathType == 'SKIRT':
692 c = extrudeColor[path.extruder]
693 if path.type == 'retract':
695 if path.type == 'extrude' and not drawQuick:
698 for i in xrange(0, len(path.points) - 1):
700 v1 = path.points[i + 1]
702 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
703 dist = (v0 - v1).vsize()
704 if dist > 0 and path.layerThickness > 0:
705 extrusionMMperDist = (v1.e - v0.e) / dist
706 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
708 drawLength += (v0 - v1).vsize()
709 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
712 vv2 = v0 + normal * lineWidth
713 vv3 = v1 + normal * lineWidth
714 vv0 = v0 - normal * lineWidth
715 vv1 = v1 - normal * lineWidth
719 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
720 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
721 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
722 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
724 if prevNormal is not None:
725 n = (normal + prevNormal)
727 vv4 = v0 + n * lineWidth
728 vv5 = v0 - n * lineWidth
731 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
732 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
733 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
734 glVertex3f(v0.x, v0.y, v0.z - zOffset)
736 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
737 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
738 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
739 glVertex3f(v0.x, v0.y, v0.z - zOffset)
747 glBegin(GL_TRIANGLES)
748 for v in path.points:
749 glVertex3f(v[0], v[1], v[2])
752 if not path.type == 'move':
753 prevPathWasRetract = False
754 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
755 # prevPathWasRetract = True
756 glEnable(GL_CULL_FACE)