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