chiark / gitweb /
Merge pull request #342 from smorloc/master
[cura.git] / Cura / gui / util / opengl.py
1 # coding=utf-8
2 from __future__ import absolute_import
3
4 import math
5 import numpy
6 import wx
7
8 from Cura.util import meshLoader
9 from Cura.util import util3d
10 from Cura.util import profile
11 from Cura.util.resources import getPathForMesh, getPathForImage
12
13 try:
14         import OpenGL
15
16         OpenGL.ERROR_CHECKING = False
17         from OpenGL.GLUT import *
18         from OpenGL.GLU import *
19         from OpenGL.GL import *
20         glutInit()
21
22         hasOpenGLlibs = True
23 except:
24         print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
25         hasOpenGLlibs = False
26
27 def InitGL(window, view3D, zoom):
28         # set viewing projection
29         glMatrixMode(GL_MODELVIEW)
30         glLoadIdentity()
31         size = window.GetSize()
32         glViewport(0, 0, size.GetWidth(), size.GetHeight())
33
34         glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
35         glLightfv(GL_LIGHT1, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
36
37         glEnable(GL_RESCALE_NORMAL)
38         glEnable(GL_LIGHTING)
39         glEnable(GL_LIGHT0)
40         glEnable(GL_DEPTH_TEST)
41         glEnable(GL_CULL_FACE)
42         glDisable(GL_BLEND)
43
44         glClearColor(1.0, 1.0, 1.0, 1.0)
45         glClearStencil(0)
46         glClearDepth(1.0)
47
48         glMatrixMode(GL_PROJECTION)
49         glLoadIdentity()
50         aspect = float(size.GetWidth()) / float(size.GetHeight())
51         if view3D:
52                 gluPerspective(45.0, aspect, 1.0, 1000.0)
53         else:
54                 glOrtho(-aspect * (zoom), aspect * (zoom), -1.0 * (zoom), 1.0 * (zoom), -1000.0, 1000.0)
55
56         glMatrixMode(GL_MODELVIEW)
57         glLoadIdentity()
58         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
59
60 platformMesh = None
61
62 def DrawMachine(machineSize):
63         if profile.getPreference('machine_type') == 'ultimaker':
64                 glPushMatrix()
65                 glEnable(GL_LIGHTING)
66                 glTranslate(100, 200, -5)
67                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
68                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
69                 glEnable(GL_BLEND)
70                 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
71
72                 global platformMesh
73                 if platformMesh is None:
74                         try:
75                                 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
76                         except:
77                                 platformMesh = False
78
79                 if platformMesh:
80                         DrawMesh(platformMesh)
81                 glPopMatrix()
82
83         glDisable(GL_LIGHTING)
84         if False:
85                 glColor3f(0.7, 0.7, 0.7)
86                 glLineWidth(2)
87                 glBegin(GL_LINES)
88                 for i in xrange(0, int(machineSize.x), 10):
89                         glVertex3f(i, 0, 0)
90                         glVertex3f(i, machineSize.y, 0)
91                 for i in xrange(0, int(machineSize.y), 10):
92                         glVertex3f(0, i, 0)
93                         glVertex3f(machineSize.x, i, 0)
94                 glEnd()
95
96                 glEnable(GL_LINE_SMOOTH)
97                 glEnable(GL_BLEND)
98                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
99                 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
100
101                 glColor3f(0.0, 0.0, 0.0)
102                 glLineWidth(4)
103                 glBegin(GL_LINE_LOOP)
104                 glVertex3f(0, 0, 0)
105                 glVertex3f(machineSize.x, 0, 0)
106                 glVertex3f(machineSize.x, machineSize.y, 0)
107                 glVertex3f(0, machineSize.y, 0)
108                 glEnd()
109
110                 glLineWidth(2)
111                 glBegin(GL_LINE_LOOP)
112                 glVertex3f(0, 0, machineSize.z)
113                 glVertex3f(machineSize.x, 0, machineSize.z)
114                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
115                 glVertex3f(0, machineSize.y, machineSize.z)
116                 glEnd()
117                 glBegin(GL_LINES)
118                 glVertex3f(0, 0, 0)
119                 glVertex3f(0, 0, machineSize.z)
120                 glVertex3f(machineSize.x, 0, 0)
121                 glVertex3f(machineSize.x, 0, machineSize.z)
122                 glVertex3f(machineSize.x, machineSize.y, 0)
123                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
124                 glVertex3f(0, machineSize.y, 0)
125                 glVertex3f(0, machineSize.y, machineSize.z)
126                 glEnd()
127         else:
128                 glDisable(GL_CULL_FACE)
129                 glEnable(GL_BLEND)
130                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
131
132                 sx = machineSize.x
133                 sy = machineSize.y
134                 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
135                         for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
136                                 x1 = sx/2+x * 10
137                                 x2 = x1 + 10
138                                 y1 = sx/2+y * 10
139                                 y2 = y1 + 10
140                                 x1 = max(min(x1, sx), 0)
141                                 y1 = max(min(y1, sy), 0)
142                                 x2 = max(min(x2, sx), 0)
143                                 y2 = max(min(y2, sy), 0)
144                                 if (x & 1) == (y & 1):
145                                         glColor4ub(5, 171, 231, 127)
146                                 else:
147                                         glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
148                                 glBegin(GL_QUADS)
149                                 glVertex3f(x1, y1, -0.01)
150                                 glVertex3f(x2, y1, -0.01)
151                                 glVertex3f(x2, y2, -0.01)
152                                 glVertex3f(x1, y2, -0.01)
153                                 glEnd()
154
155                 glEnable(GL_CULL_FACE)
156
157                 glColor4ub(5, 171, 231, 64)
158                 glBegin(GL_QUADS)
159                 glVertex3f(0, 0, machineSize.z)
160                 glVertex3f(0, machineSize.y, machineSize.z)
161                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
162                 glVertex3f(machineSize.x, 0, machineSize.z)
163                 glEnd()
164
165                 glColor4ub(5, 171, 231, 96)
166                 glBegin(GL_QUADS)
167                 glVertex3f(0, 0, 0)
168                 glVertex3f(0, 0, machineSize.z)
169                 glVertex3f(machineSize.x, 0, machineSize.z)
170                 glVertex3f(machineSize.x, 0, 0)
171
172                 glVertex3f(0, machineSize.y, machineSize.z)
173                 glVertex3f(0, machineSize.y, 0)
174                 glVertex3f(machineSize.x, machineSize.y, 0)
175                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
176                 glEnd()
177
178                 glColor4ub(5, 171, 231, 128)
179                 glBegin(GL_QUADS)
180                 glVertex3f(0, 0, machineSize.z)
181                 glVertex3f(0, 0, 0)
182                 glVertex3f(0, machineSize.y, 0)
183                 glVertex3f(0, machineSize.y, machineSize.z)
184
185                 glVertex3f(machineSize.x, 0, 0)
186                 glVertex3f(machineSize.x, 0, machineSize.z)
187                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
188                 glVertex3f(machineSize.x, machineSize.y, 0)
189                 glEnd()
190
191                 glDisable(GL_BLEND)
192
193         glPushMatrix()
194         glTranslate(5, 5, 2)
195         glLineWidth(2)
196         glColor3f(0.5, 0, 0)
197         glBegin(GL_LINES)
198         glVertex3f(0, 0, 0)
199         glVertex3f(20, 0, 0)
200         glEnd()
201         glColor3f(0, 0.5, 0)
202         glBegin(GL_LINES)
203         glVertex3f(0, 0, 0)
204         glVertex3f(0, 20, 0)
205         glEnd()
206         glColor3f(0, 0, 0.5)
207         glBegin(GL_LINES)
208         glVertex3f(0, 0, 0)
209         glVertex3f(0, 0, 20)
210         glEnd()
211
212         glDisable(GL_DEPTH_TEST)
213         #X
214         glColor3f(1, 0, 0)
215         glPushMatrix()
216         glTranslate(20, 0, 0)
217         noZ = ResetMatrixRotationAndScale()
218         glDrawStringCenter("X")
219         glPopMatrix()
220
221         #Y
222         glColor3f(0, 1, 0)
223         glPushMatrix()
224         glTranslate(0, 20, 0)
225         glDrawStringCenter("Y")
226         glPopMatrix()
227
228         #Z
229         if not noZ:
230                 glColor3f(0, 0, 1)
231                 glPushMatrix()
232                 glTranslate(0, 0, 20)
233                 glDrawStringCenter("Z")
234                 glPopMatrix()
235
236         glPopMatrix()
237         glEnable(GL_DEPTH_TEST)
238
239 def glDrawStringCenter(s):
240         glRasterPos2f(0, 0)
241         width = 0
242         for c in s:
243                 width += glutBitmapWidth(GLUT_BITMAP_HELVETICA_18, ord(c))
244         glBitmap(0,0,0,0, -width/2, 0, None)
245         for c in s:
246                 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(c))
247
248 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
249         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
250         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
251         finalMatrix = npModelMatrix * npProjMatrix
252         finalMatrix = numpy.linalg.inv(finalMatrix)
253
254         viewport = map(float, viewport)
255         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))
256         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
257         ret = list(vector)[0:3] / vector[3]
258         return ret
259
260 def convert3x3MatrixTo4x4(matrix):
261         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
262
263 def loadGLTexture(filename):
264         tex = glGenTextures(1)
265         glBindTexture(GL_TEXTURE_2D, tex)
266         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
267         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
268         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
269         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
270         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
271         rgbData = img.GetData()
272         alphaData = img.GetAlphaData()
273         if alphaData != None:
274                 data = ''
275                 for i in xrange(0, len(alphaData)):
276                         data += rgbData[i*3:i*3+3] + alphaData[i]
277                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
278         else:
279                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
280         return tex
281
282 def ResetMatrixRotationAndScale():
283         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
284         noZ = False
285         if matrix[3][2] > 0:
286                 return False
287         scale2D = matrix[0][0]
288         matrix[0][0] = 1.0
289         matrix[1][0] = 0.0
290         matrix[2][0] = 0.0
291         matrix[0][1] = 0.0
292         matrix[1][1] = 1.0
293         matrix[2][1] = 0.0
294         matrix[0][2] = 0.0
295         matrix[1][2] = 0.0
296         matrix[2][2] = 1.0
297
298         if matrix[3][2] != 0.0:
299                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
300                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
301                 matrix[3][2] = -100
302         else:
303                 matrix[0][0] = scale2D
304                 matrix[1][1] = scale2D
305                 matrix[2][2] = scale2D
306                 matrix[3][2] = -100
307                 noZ = True
308
309         glLoadMatrixf(matrix)
310         return noZ
311
312
313 def DrawBox(vMin, vMax):
314         glBegin(GL_LINE_LOOP)
315         glVertex3f(vMin[0], vMin[1], vMin[2])
316         glVertex3f(vMax[0], vMin[1], vMin[2])
317         glVertex3f(vMax[0], vMax[1], vMin[2])
318         glVertex3f(vMin[0], vMax[1], vMin[2])
319         glEnd()
320
321         glBegin(GL_LINE_LOOP)
322         glVertex3f(vMin[0], vMin[1], vMax[2])
323         glVertex3f(vMax[0], vMin[1], vMax[2])
324         glVertex3f(vMax[0], vMax[1], vMax[2])
325         glVertex3f(vMin[0], vMax[1], vMax[2])
326         glEnd()
327         glBegin(GL_LINES)
328         glVertex3f(vMin[0], vMin[1], vMin[2])
329         glVertex3f(vMin[0], vMin[1], vMax[2])
330         glVertex3f(vMax[0], vMin[1], vMin[2])
331         glVertex3f(vMax[0], vMin[1], vMax[2])
332         glVertex3f(vMax[0], vMax[1], vMin[2])
333         glVertex3f(vMax[0], vMax[1], vMax[2])
334         glVertex3f(vMin[0], vMax[1], vMin[2])
335         glVertex3f(vMin[0], vMax[1], vMax[2])
336         glEnd()
337
338
339 def DrawMeshOutline(mesh):
340         glEnable(GL_CULL_FACE)
341         glEnableClientState(GL_VERTEX_ARRAY);
342         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
343
344         glCullFace(GL_FRONT)
345         glLineWidth(3)
346         glPolygonMode(GL_BACK, GL_LINE)
347         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
348         glPolygonMode(GL_BACK, GL_FILL)
349         glCullFace(GL_BACK)
350
351         glDisableClientState(GL_VERTEX_ARRAY)
352
353
354 def DrawMesh(mesh):
355         glEnable(GL_CULL_FACE)
356         glEnableClientState(GL_VERTEX_ARRAY);
357         glEnableClientState(GL_NORMAL_ARRAY);
358         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
359         glNormalPointer(GL_FLOAT, 0, mesh.normal)
360
361         #Odd, drawing in batchs is a LOT faster then drawing it all at once.
362         batchSize = 999    #Warning, batchSize needs to be dividable by 3
363         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
364         extraCount = mesh.vertexCount - extraStartPos
365
366         glCullFace(GL_BACK)
367         for i in xrange(0, int(mesh.vertexCount / batchSize)):
368                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
369         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
370
371         glCullFace(GL_FRONT)
372         glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
373         for i in xrange(0, int(mesh.vertexCount / batchSize)):
374                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
375         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
376         extraCount = mesh.vertexCount - extraStartPos
377         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
378         glCullFace(GL_BACK)
379
380         glDisableClientState(GL_VERTEX_ARRAY)
381         glDisableClientState(GL_NORMAL_ARRAY);
382
383
384 def DrawMeshSteep(mesh, angle):
385         cosAngle = math.sin(angle / 180.0 * math.pi)
386         glDisable(GL_LIGHTING)
387         glDepthFunc(GL_EQUAL)
388         for i in xrange(0, int(mesh.vertexCount), 3):
389                 if mesh.normal[i][2] < -0.999999:
390                         if mesh.vertexes[i + 0][2] > 0.01:
391                                 glColor3f(0.5, 0, 0)
392                                 glBegin(GL_TRIANGLES)
393                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
394                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
395                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
396                                 glEnd()
397                 elif mesh.normal[i][2] < -cosAngle:
398                         glColor3f(-mesh.normal[i][2], 0, 0)
399                         glBegin(GL_TRIANGLES)
400                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
401                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
402                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
403                         glEnd()
404                 elif mesh.normal[i][2] > 0.999999:
405                         if mesh.vertexes[i + 0][2] > 0.01:
406                                 glColor3f(0.5, 0, 0)
407                                 glBegin(GL_TRIANGLES)
408                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
409                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
410                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
411                                 glEnd()
412                 elif mesh.normal[i][2] > cosAngle:
413                         glColor3f(mesh.normal[i][2], 0, 0)
414                         glBegin(GL_TRIANGLES)
415                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
416                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
417                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
418                         glEnd()
419         glDepthFunc(GL_LESS)
420
421
422 def DrawGCodeLayer(layer):
423         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
424         filamentArea = math.pi * filamentRadius * filamentRadius
425         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
426
427         fillCycle = 0
428         fillColorCycle = [[0.5, 0.5, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]]
429         moveColor = [0, 0, 1]
430         retractColor = [1, 0, 0.5]
431         supportColor = [0, 1, 1]
432         extrudeColor = [1, 0, 0]
433         innerWallColor = [0, 1, 0]
434         skirtColor = [0, 0.5, 0.5]
435         prevPathWasRetract = False
436
437         glDisable(GL_CULL_FACE)
438         for path in layer:
439                 if path.type == 'move':
440                         if prevPathWasRetract:
441                                 c = retractColor
442                         else:
443                                 c = moveColor
444                 zOffset = 0.01
445                 if path.type == 'extrude':
446                         if path.pathType == 'FILL':
447                                 c = fillColorCycle[fillCycle]
448                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
449                         elif path.pathType == 'WALL-INNER':
450                                 c = innerWallColor
451                                 zOffset = 0.02
452                         elif path.pathType == 'SUPPORT':
453                                 c = supportColor
454                         elif path.pathType == 'SKIRT':
455                                 c = skirtColor
456                         else:
457                                 c = extrudeColor
458                 if path.type == 'retract':
459                         c = [0, 1, 1]
460                 if path.type == 'extrude':
461                         drawLength = 0.0
462                         prevNormal = None
463                         for i in xrange(0, len(path.list) - 1):
464                                 v0 = path.list[i]
465                                 v1 = path.list[i + 1]
466
467                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
468                                 dist = (v0 - v1).vsize()
469                                 if dist > 0 and path.layerThickness > 0:
470                                         extrusionMMperDist = (v1.e - v0.e) / dist
471                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
472
473                                 drawLength += (v0 - v1).vsize()
474                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
475                                 normal.normalize()
476
477                                 vv2 = v0 + normal * lineWidth
478                                 vv3 = v1 + normal * lineWidth
479                                 vv0 = v0 - normal * lineWidth
480                                 vv1 = v1 - normal * lineWidth
481
482                                 glBegin(GL_QUADS)
483                                 glColor3fv(c)
484                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
485                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
486                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
487                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
488                                 glEnd()
489                                 if prevNormal is not None:
490                                         n = (normal + prevNormal)
491                                         n.normalize()
492                                         vv4 = v0 + n * lineWidth
493                                         vv5 = v0 - n * lineWidth
494                                         glBegin(GL_QUADS)
495                                         glColor3fv(c)
496                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
497                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
498                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
499                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
500
501                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
502                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
503                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
504                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
505                                         glEnd()
506
507                                 prevNormal = normal
508                                 prevVv1 = vv1
509                                 prevVv3 = vv3
510                 else:
511                         glBegin(GL_LINE_STRIP)
512                         glColor3fv(c)
513                         for v in path.list:
514                                 glVertex3f(v.x, v.y, v.z)
515                         glEnd()
516                 if not path.type == 'move':
517                         prevPathWasRetract = False
518                 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
519                         prevPathWasRetract = True
520         glEnable(GL_CULL_FACE)