chiark / gitweb /
Add proper copyright statements.
[cura.git] / Cura / gui / util / opengl.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
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 from OpenGL.GL import shaders
21 glutInit()
22
23 platformMesh = None
24
25 class GLReferenceCounter(object):
26         def __init__(self):
27                 self._refCounter = 1
28
29         def incRef(self):
30                 self._refCounter += 1
31
32         def decRef(self):
33                 self._refCounter -= 1
34                 return self._refCounter <= 0
35
36 class GLShader(GLReferenceCounter):
37         def __init__(self, vertexProgram, fragmentProgram):
38                 super(GLShader, self).__init__()
39                 self._vertexString = vertexProgram
40                 self._fragmentString = fragmentProgram
41                 try:
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:
46                         print str(e)
47                         self._program = None
48
49         def bind(self):
50                 if self._program is not None:
51                         shaders.glUseProgram(self._program)
52
53         def unbind(self):
54                 shaders.glUseProgram(0)
55
56         def release(self):
57                 if self._program is not None:
58                         shaders.glDeleteShader(self._vertexProgram)
59                         shaders.glDeleteShader(self._fragmentProgram)
60                         glDeleteProgram(self._program)
61                         self._program = None
62
63         def setUniform(self, name, value):
64                 if self._program is not None:
65                         glUniform1f(glGetUniformLocation(self._program, name), value)
66
67         def isValid(self):
68                 return self._program is not None
69
70         def getVertexShader(self):
71                 return self._vertexString
72
73         def getFragmentShader(self):
74                 return self._fragmentString
75
76         def __del__(self):
77                 if self._program is not None and bool(glDeleteProgram):
78                         print "Shader was not properly released!"
79
80 class GLVBO(GLReferenceCounter):
81         def __init__(self, vertexArray, normalArray = None):
82                 super(GLVBO, self).__init__()
83                 self._buffer = glGenBuffers(1)
84                 self._size = len(vertexArray)
85                 self._hasNormals = normalArray is not None
86                 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
87                 if self._hasNormals:
88                         glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
89                 else:
90                         glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
91                 glBindBuffer(GL_ARRAY_BUFFER, 0)
92
93         def render(self, render_type = GL_TRIANGLES):
94                 glEnableClientState(GL_VERTEX_ARRAY)
95                 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
96
97                 if self._hasNormals:
98                         glEnableClientState(GL_NORMAL_ARRAY)
99                         glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
100                         glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
101                 else:
102                         glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
103
104                 batchSize = 996    #Warning, batchSize needs to be dividable by 4, 3 and 2
105                 extraStartPos = int(self._size / batchSize) * batchSize
106                 extraCount = self._size - extraStartPos
107
108                 for i in xrange(0, int(self._size / batchSize)):
109                         glDrawArrays(render_type, i * batchSize, batchSize)
110                 glDrawArrays(render_type, extraStartPos, extraCount)
111                 glBindBuffer(GL_ARRAY_BUFFER, 0)
112
113                 glDisableClientState(GL_VERTEX_ARRAY)
114                 if self._hasNormals:
115                         glDisableClientState(GL_NORMAL_ARRAY)
116
117         def release(self):
118                 if self._buffer is not None:
119                         glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
120                         glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
121                         glBindBuffer(GL_ARRAY_BUFFER, 0)
122                         glDeleteBuffers(1, [self._buffer])
123                         self._buffer = None
124
125         def __del__(self):
126                 if self._buffer is not None and bool(glDeleteBuffers):
127                         print "VBO was not properly released!"
128
129 def DrawMachine(machineSize):
130         glDisable(GL_LIGHTING)
131         glDisable(GL_CULL_FACE)
132         glEnable(GL_BLEND)
133         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
134
135         sx = machineSize.x
136         sy = machineSize.y
137         for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
138                 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
139                         x1 = sx/2+x * 10
140                         x2 = x1 + 10
141                         y1 = sx/2+y * 10
142                         y2 = y1 + 10
143                         x1 = max(min(x1, sx), 0)
144                         y1 = max(min(y1, sy), 0)
145                         x2 = max(min(x2, sx), 0)
146                         y2 = max(min(y2, sy), 0)
147                         if (x & 1) == (y & 1):
148                                 glColor4ub(5, 171, 231, 127)
149                         else:
150                                 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
151                         glBegin(GL_QUADS)
152                         glVertex3f(x1, y1, -0.02)
153                         glVertex3f(x2, y1, -0.02)
154                         glVertex3f(x2, y2, -0.02)
155                         glVertex3f(x1, y2, -0.02)
156                         glEnd()
157
158         glEnable(GL_CULL_FACE)
159
160         if profile.getPreference('machine_type') == 'ultimaker':
161                 glPushMatrix()
162                 glEnable(GL_LIGHTING)
163                 glTranslate(100, 200, -1)
164                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
165                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
166                 glEnable(GL_BLEND)
167                 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
168
169                 global platformMesh
170                 if platformMesh is None:
171                         try:
172                                 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
173                         except:
174                                 platformMesh = False
175
176                 if platformMesh:
177                         DrawMesh(platformMesh)
178                 glPopMatrix()
179                 glDisable(GL_LIGHTING)
180                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
181
182         glColor4ub(5, 171, 231, 64)
183         glBegin(GL_QUADS)
184         glVertex3f(0, 0, machineSize.z)
185         glVertex3f(0, machineSize.y, machineSize.z)
186         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
187         glVertex3f(machineSize.x, 0, machineSize.z)
188         glEnd()
189
190         glColor4ub(5, 171, 231, 96)
191         glBegin(GL_QUADS)
192         glVertex3f(0, 0, 0)
193         glVertex3f(0, 0, machineSize.z)
194         glVertex3f(machineSize.x, 0, machineSize.z)
195         glVertex3f(machineSize.x, 0, 0)
196
197         glVertex3f(0, machineSize.y, machineSize.z)
198         glVertex3f(0, machineSize.y, 0)
199         glVertex3f(machineSize.x, machineSize.y, 0)
200         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
201         glEnd()
202
203         glColor4ub(5, 171, 231, 128)
204         glBegin(GL_QUADS)
205         glVertex3f(0, 0, machineSize.z)
206         glVertex3f(0, 0, 0)
207         glVertex3f(0, machineSize.y, 0)
208         glVertex3f(0, machineSize.y, machineSize.z)
209
210         glVertex3f(machineSize.x, 0, 0)
211         glVertex3f(machineSize.x, 0, machineSize.z)
212         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
213         glVertex3f(machineSize.x, machineSize.y, 0)
214         glEnd()
215
216         glDisable(GL_BLEND)
217
218         #Draw the X/Y/Z indicator
219         glPushMatrix()
220         glTranslate(5, 5, 2)
221         glLineWidth(2)
222         glColor3f(0.5, 0, 0)
223         glBegin(GL_LINES)
224         glVertex3f(0, 0, 0)
225         glVertex3f(20, 0, 0)
226         glEnd()
227         glColor3f(0, 0.5, 0)
228         glBegin(GL_LINES)
229         glVertex3f(0, 0, 0)
230         glVertex3f(0, 20, 0)
231         glEnd()
232         glColor3f(0, 0, 0.5)
233         glBegin(GL_LINES)
234         glVertex3f(0, 0, 0)
235         glVertex3f(0, 0, 20)
236         glEnd()
237
238         glDisable(GL_DEPTH_TEST)
239         #X
240         glColor3f(1, 0, 0)
241         glPushMatrix()
242         glTranslate(20, 0, 0)
243         noZ = ResetMatrixRotationAndScale()
244         glDrawStringCenter("X")
245         glPopMatrix()
246
247         #Y
248         glColor3f(0, 1, 0)
249         glPushMatrix()
250         glTranslate(0, 20, 0)
251         glDrawStringCenter("Y")
252         glPopMatrix()
253
254         #Z
255         if not noZ:
256                 glColor3f(0, 0, 1)
257                 glPushMatrix()
258                 glTranslate(0, 0, 20)
259                 glDrawStringCenter("Z")
260                 glPopMatrix()
261
262         glPopMatrix()
263         glEnable(GL_DEPTH_TEST)
264
265 def glDrawStringCenter(s):
266         glRasterPos2f(0, 0)
267         glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
268         for c in s:
269                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
270
271 def glGetStringSize(s):
272         width = 0
273         for c in s:
274                 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
275         height = 18
276         return width, height
277
278 def glDrawStringLeft(s):
279         glRasterPos2f(0, 0)
280         n = 1
281         for c in s:
282                 if c == '\n':
283                         glPushMatrix()
284                         glTranslate(0, 18 * n, 0)
285                         n += 1
286                         glRasterPos2f(0, 0)
287                         glPopMatrix()
288                 else:
289                         glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
290
291 def glDrawStringRight(s):
292         glRasterPos2f(0, 0)
293         glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
294         for c in s:
295                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
296
297 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
298         tx = float(texID % 4) / 4
299         ty = float(int(texID / 4)) / 8
300         tsx = 0.25
301         tsy = 0.125
302         if mirror & 1:
303                 tx += tsx
304                 tsx = -tsx
305         if mirror & 2:
306                 ty += tsy
307                 tsy = -tsy
308         glPushMatrix()
309         glTranslatef(x, y, 0)
310         glEnable(GL_TEXTURE_2D)
311         glBegin(GL_QUADS)
312         glTexCoord2f(tx+tsx, ty)
313         glVertex2f(w, 0)
314         glTexCoord2f(tx, ty)
315         glVertex2f(0, 0)
316         glTexCoord2f(tx, ty+tsy)
317         glVertex2f(0, h)
318         glTexCoord2f(tx+tsx, ty+tsy)
319         glVertex2f(w, h)
320         glEnd()
321         glPopMatrix()
322
323 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
324         tx0 = float(texID % 4) / 4
325         ty0 = float(int(texID / 4)) / 8
326         tx1 = tx0 + 0.25 / 2.0
327         ty1 = ty0 + 0.125 / 2.0
328         tx2 = tx0 + 0.25
329         ty2 = ty0 + 0.125
330
331         glPushMatrix()
332         glTranslatef(x, y, 0)
333         glEnable(GL_TEXTURE_2D)
334         glBegin(GL_QUADS)
335         #TopLeft
336         glTexCoord2f(tx1, ty0)
337         glVertex2f( cornerSize, 0)
338         glTexCoord2f(tx0, ty0)
339         glVertex2f( 0, 0)
340         glTexCoord2f(tx0, ty1)
341         glVertex2f( 0, cornerSize)
342         glTexCoord2f(tx1, ty1)
343         glVertex2f( cornerSize, cornerSize)
344         #TopRight
345         glTexCoord2f(tx2, ty0)
346         glVertex2f( w, 0)
347         glTexCoord2f(tx1, ty0)
348         glVertex2f( w - cornerSize, 0)
349         glTexCoord2f(tx1, ty1)
350         glVertex2f( w - cornerSize, cornerSize)
351         glTexCoord2f(tx2, ty1)
352         glVertex2f( w, cornerSize)
353         #BottomLeft
354         glTexCoord2f(tx1, ty1)
355         glVertex2f( cornerSize, h - cornerSize)
356         glTexCoord2f(tx0, ty1)
357         glVertex2f( 0, h - cornerSize)
358         glTexCoord2f(tx0, ty2)
359         glVertex2f( 0, h)
360         glTexCoord2f(tx1, ty2)
361         glVertex2f( cornerSize, h)
362         #BottomRight
363         glTexCoord2f(tx2, ty1)
364         glVertex2f( w, h - cornerSize)
365         glTexCoord2f(tx1, ty1)
366         glVertex2f( w - cornerSize, h - cornerSize)
367         glTexCoord2f(tx1, ty2)
368         glVertex2f( w - cornerSize, h)
369         glTexCoord2f(tx2, ty2)
370         glVertex2f( w, h)
371
372         #Center
373         glTexCoord2f(tx1, ty1)
374         glVertex2f( w-cornerSize, cornerSize)
375         glTexCoord2f(tx1, ty1)
376         glVertex2f( cornerSize, cornerSize)
377         glTexCoord2f(tx1, ty1)
378         glVertex2f( cornerSize, h-cornerSize)
379         glTexCoord2f(tx1, ty1)
380         glVertex2f( w-cornerSize, h-cornerSize)
381
382         #Right
383         glTexCoord2f(tx2, ty1)
384         glVertex2f( w, cornerSize)
385         glTexCoord2f(tx1, ty1)
386         glVertex2f( w-cornerSize, cornerSize)
387         glTexCoord2f(tx1, ty1)
388         glVertex2f( w-cornerSize, h-cornerSize)
389         glTexCoord2f(tx2, ty1)
390         glVertex2f( w, h-cornerSize)
391
392         #Left
393         glTexCoord2f(tx1, ty1)
394         glVertex2f( cornerSize, cornerSize)
395         glTexCoord2f(tx0, ty1)
396         glVertex2f( 0, cornerSize)
397         glTexCoord2f(tx0, ty1)
398         glVertex2f( 0, h-cornerSize)
399         glTexCoord2f(tx1, ty1)
400         glVertex2f( cornerSize, h-cornerSize)
401
402         #Top
403         glTexCoord2f(tx1, ty0)
404         glVertex2f( w-cornerSize, 0)
405         glTexCoord2f(tx1, ty0)
406         glVertex2f( cornerSize, 0)
407         glTexCoord2f(tx1, ty1)
408         glVertex2f( cornerSize, cornerSize)
409         glTexCoord2f(tx1, ty1)
410         glVertex2f( w-cornerSize, cornerSize)
411
412         #Bottom
413         glTexCoord2f(tx1, ty1)
414         glVertex2f( w-cornerSize, h-cornerSize)
415         glTexCoord2f(tx1, ty1)
416         glVertex2f( cornerSize, h-cornerSize)
417         glTexCoord2f(tx1, ty2)
418         glVertex2f( cornerSize, h)
419         glTexCoord2f(tx1, ty2)
420         glVertex2f( w-cornerSize, h)
421
422         glEnd()
423         glDisable(GL_TEXTURE_2D)
424         glPopMatrix()
425
426 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
427         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
428         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
429         finalMatrix = npModelMatrix * npProjMatrix
430         finalMatrix = numpy.linalg.inv(finalMatrix)
431
432         viewport = map(float, viewport)
433         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))
434         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
435         ret = list(vector)[0:3] / vector[3]
436         return ret
437
438 def convert3x3MatrixTo4x4(matrix):
439         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
440
441 def loadGLTexture(filename):
442         tex = glGenTextures(1)
443         glBindTexture(GL_TEXTURE_2D, tex)
444         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
445         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
446         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
447         rgbData = img.GetData()
448         alphaData = img.GetAlphaData()
449         if alphaData is not None:
450                 data = ''
451                 for i in xrange(0, len(alphaData)):
452                         data += rgbData[i*3:i*3+3] + alphaData[i]
453                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
454         else:
455                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
456         return tex
457
458 def ResetMatrixRotationAndScale():
459         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
460         noZ = False
461         if matrix[3][2] > 0:
462                 return False
463         scale2D = matrix[0][0]
464         matrix[0][0] = 1.0
465         matrix[1][0] = 0.0
466         matrix[2][0] = 0.0
467         matrix[0][1] = 0.0
468         matrix[1][1] = 1.0
469         matrix[2][1] = 0.0
470         matrix[0][2] = 0.0
471         matrix[1][2] = 0.0
472         matrix[2][2] = 1.0
473
474         if matrix[3][2] != 0.0:
475                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
476                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
477                 matrix[3][2] = -100
478         else:
479                 matrix[0][0] = scale2D
480                 matrix[1][1] = scale2D
481                 matrix[2][2] = scale2D
482                 matrix[3][2] = -100
483                 noZ = True
484
485         glLoadMatrixf(matrix)
486         return noZ
487
488
489 def DrawBox(vMin, vMax):
490         glBegin(GL_LINE_LOOP)
491         glVertex3f(vMin[0], vMin[1], vMin[2])
492         glVertex3f(vMax[0], vMin[1], vMin[2])
493         glVertex3f(vMax[0], vMax[1], vMin[2])
494         glVertex3f(vMin[0], vMax[1], vMin[2])
495         glEnd()
496
497         glBegin(GL_LINE_LOOP)
498         glVertex3f(vMin[0], vMin[1], vMax[2])
499         glVertex3f(vMax[0], vMin[1], vMax[2])
500         glVertex3f(vMax[0], vMax[1], vMax[2])
501         glVertex3f(vMin[0], vMax[1], vMax[2])
502         glEnd()
503         glBegin(GL_LINES)
504         glVertex3f(vMin[0], vMin[1], vMin[2])
505         glVertex3f(vMin[0], vMin[1], vMax[2])
506         glVertex3f(vMax[0], vMin[1], vMin[2])
507         glVertex3f(vMax[0], vMin[1], vMax[2])
508         glVertex3f(vMax[0], vMax[1], vMin[2])
509         glVertex3f(vMax[0], vMax[1], vMax[2])
510         glVertex3f(vMin[0], vMax[1], vMin[2])
511         glVertex3f(vMin[0], vMax[1], vMax[2])
512         glEnd()
513
514
515 def DrawMeshOutline(mesh):
516         glEnable(GL_CULL_FACE)
517         glEnableClientState(GL_VERTEX_ARRAY);
518         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
519
520         glCullFace(GL_FRONT)
521         glLineWidth(3)
522         glPolygonMode(GL_BACK, GL_LINE)
523         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
524         glPolygonMode(GL_BACK, GL_FILL)
525         glCullFace(GL_BACK)
526
527         glDisableClientState(GL_VERTEX_ARRAY)
528
529
530 def DrawMesh(mesh, insideOut = False):
531         glEnable(GL_CULL_FACE)
532         glEnableClientState(GL_VERTEX_ARRAY)
533         glEnableClientState(GL_NORMAL_ARRAY)
534         for m in mesh._meshList:
535                 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
536                 if insideOut:
537                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
538                 else:
539                         glNormalPointer(GL_FLOAT, 0, m.normal)
540
541                 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
542                 batchSize = 999    #Warning, batchSize needs to be dividable by 3
543                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
544                 extraCount = m.vertexCount - extraStartPos
545
546                 glCullFace(GL_BACK)
547                 for i in xrange(0, int(m.vertexCount / batchSize)):
548                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
549                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
550
551                 glCullFace(GL_FRONT)
552                 if insideOut:
553                         glNormalPointer(GL_FLOAT, 0, m.normal)
554                 else:
555                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
556                 for i in xrange(0, int(m.vertexCount / batchSize)):
557                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
558                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
559                 extraCount = m.vertexCount - extraStartPos
560                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
561                 glCullFace(GL_BACK)
562
563         glDisableClientState(GL_VERTEX_ARRAY)
564         glDisableClientState(GL_NORMAL_ARRAY)
565
566
567 def DrawMeshSteep(mesh, matrix, angle):
568         cosAngle = math.sin(angle / 180.0 * math.pi)
569         glDisable(GL_LIGHTING)
570         glDepthFunc(GL_EQUAL)
571         normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
572         for i in xrange(0, int(mesh.vertexCount), 3):
573                 if normals[i][2] < -0.999999:
574                         if mesh.vertexes[i + 0][2] > 0.01:
575                                 glColor3f(0.5, 0, 0)
576                                 glBegin(GL_TRIANGLES)
577                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
578                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
579                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
580                                 glEnd()
581                 elif normals[i][2] < -cosAngle:
582                         glColor3f(-normals[i][2], 0, 0)
583                         glBegin(GL_TRIANGLES)
584                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
585                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
586                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
587                         glEnd()
588                 elif normals[i][2] > 0.999999:
589                         if mesh.vertexes[i + 0][2] > 0.01:
590                                 glColor3f(0.5, 0, 0)
591                                 glBegin(GL_TRIANGLES)
592                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
593                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
594                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
595                                 glEnd()
596                 elif normals[i][2] > cosAngle:
597                         glColor3f(normals[i][2], 0, 0)
598                         glBegin(GL_TRIANGLES)
599                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
600                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
601                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
602                         glEnd()
603         glDepthFunc(GL_LESS)
604
605 def DrawGCodeLayer(layer, drawQuick = True):
606         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
607         filamentArea = math.pi * filamentRadius * filamentRadius
608         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
609
610         fillCycle = 0
611         fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
612         moveColor = [0, 0, 1, 0.5]
613         retractColor = [1, 0, 0.5, 0.5]
614         supportColor = [0, 1, 1, 1]
615         extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
616         innerWallColor = [0, 1, 0, 1]
617         skirtColor = [0, 0.5, 0.5, 1]
618         prevPathWasRetract = False
619
620         glDisable(GL_CULL_FACE)
621         for path in layer:
622                 if path.type == 'move':
623                         if prevPathWasRetract:
624                                 c = retractColor
625                         else:
626                                 c = moveColor
627                         if drawQuick:
628                                 continue
629                 zOffset = 0.01
630                 if path.type == 'extrude':
631                         if path.pathType == 'FILL':
632                                 c = fillColorCycle[fillCycle]
633                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
634                         elif path.pathType == 'WALL-INNER':
635                                 c = innerWallColor
636                                 zOffset = 0.02
637                         elif path.pathType == 'SUPPORT':
638                                 c = supportColor
639                         elif path.pathType == 'SKIRT':
640                                 c = skirtColor
641                         else:
642                                 c = extrudeColor[path.extruder]
643                 if path.type == 'retract':
644                         c = retractColor
645                 if path.type == 'extrude' and not drawQuick:
646                         drawLength = 0.0
647                         prevNormal = None
648                         for i in xrange(0, len(path.points) - 1):
649                                 v0 = path.points[i]
650                                 v1 = path.points[i + 1]
651
652                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
653                                 dist = (v0 - v1).vsize()
654                                 if dist > 0 and path.layerThickness > 0:
655                                         extrusionMMperDist = (v1.e - v0.e) / dist
656                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
657
658                                 drawLength += (v0 - v1).vsize()
659                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
660                                 normal.normalize()
661
662                                 vv2 = v0 + normal * lineWidth
663                                 vv3 = v1 + normal * lineWidth
664                                 vv0 = v0 - normal * lineWidth
665                                 vv1 = v1 - normal * lineWidth
666
667                                 glBegin(GL_QUADS)
668                                 glColor4fv(c)
669                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
670                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
671                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
672                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
673                                 glEnd()
674                                 if prevNormal is not None:
675                                         n = (normal + prevNormal)
676                                         n.normalize()
677                                         vv4 = v0 + n * lineWidth
678                                         vv5 = v0 - n * lineWidth
679                                         glBegin(GL_QUADS)
680                                         glColor4fv(c)
681                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
682                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
683                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
684                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
685
686                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
687                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
688                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
689                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
690                                         glEnd()
691
692                                 prevNormal = normal
693                                 prevVv1 = vv1
694                                 prevVv3 = vv3
695                 else:
696                         glColor4fv(c)
697                         glBegin(GL_TRIANGLES)
698                         for v in path.points:
699                                 glVertex3f(v[0], v[1], v[2])
700                         glEnd()
701
702                 if not path.type == 'move':
703                         prevPathWasRetract = False
704                 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
705                 #       prevPathWasRetract = True
706         glEnable(GL_CULL_FACE)