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