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