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