chiark / gitweb /
Merge branch 'SteamEngine' of github.com:daid/Cura 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 = 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 = 1002    #Warning, batchSize needs to be dividable by 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         for c in s:
278                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
279
280 def glDrawStringRight(s):
281         glRasterPos2f(0, 0)
282         glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
283         for c in s:
284                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
285
286 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
287         tx = float(texID % 4) / 4
288         ty = float(int(texID / 4)) / 8
289         tsx = 0.25
290         tsy = 0.125
291         if mirror & 1:
292                 tx += tsx
293                 tsx = -tsx
294         if mirror & 2:
295                 ty += tsy
296                 tsy = -tsy
297         glPushMatrix()
298         glTranslatef(x, y, 0)
299         glEnable(GL_TEXTURE_2D)
300         glBegin(GL_QUADS)
301         glTexCoord2f(tx+tsx, ty)
302         glVertex2f(w, 0)
303         glTexCoord2f(tx, ty)
304         glVertex2f(0, 0)
305         glTexCoord2f(tx, ty+tsy)
306         glVertex2f(0, h)
307         glTexCoord2f(tx+tsx, ty+tsy)
308         glVertex2f(w, h)
309         glEnd()
310         glPopMatrix()
311
312 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
313         tx0 = float(texID % 4) / 4
314         ty0 = float(int(texID / 4)) / 8
315         tx1 = tx0 + 0.25 / 2.0
316         ty1 = ty0 + 0.125 / 2.0
317         tx2 = tx0 + 0.25
318         ty2 = ty0 + 0.125
319
320         glPushMatrix()
321         glTranslatef(x, y, 0)
322         glEnable(GL_TEXTURE_2D)
323         glBegin(GL_QUADS)
324         #TopLeft
325         glTexCoord2f(tx1, ty0)
326         glVertex2f( cornerSize, 0)
327         glTexCoord2f(tx0, ty0)
328         glVertex2f( 0, 0)
329         glTexCoord2f(tx0, ty1)
330         glVertex2f( 0, cornerSize)
331         glTexCoord2f(tx1, ty1)
332         glVertex2f( cornerSize, cornerSize)
333         #TopRight
334         glTexCoord2f(tx2, ty0)
335         glVertex2f( w, 0)
336         glTexCoord2f(tx1, ty0)
337         glVertex2f( w - cornerSize, 0)
338         glTexCoord2f(tx1, ty1)
339         glVertex2f( w - cornerSize, cornerSize)
340         glTexCoord2f(tx2, ty1)
341         glVertex2f( w, cornerSize)
342         #BottomLeft
343         glTexCoord2f(tx1, ty1)
344         glVertex2f( cornerSize, h - cornerSize)
345         glTexCoord2f(tx0, ty1)
346         glVertex2f( 0, h - cornerSize)
347         glTexCoord2f(tx0, ty2)
348         glVertex2f( 0, h)
349         glTexCoord2f(tx1, ty2)
350         glVertex2f( cornerSize, h)
351         #BottomRight
352         glTexCoord2f(tx2, ty1)
353         glVertex2f( w, h - cornerSize)
354         glTexCoord2f(tx1, ty1)
355         glVertex2f( w - cornerSize, h - cornerSize)
356         glTexCoord2f(tx1, ty2)
357         glVertex2f( w - cornerSize, h)
358         glTexCoord2f(tx2, ty2)
359         glVertex2f( w, h)
360
361         #Center
362         glTexCoord2f(tx1, ty1)
363         glVertex2f( w-cornerSize, cornerSize)
364         glTexCoord2f(tx1, ty1)
365         glVertex2f( cornerSize, cornerSize)
366         glTexCoord2f(tx1, ty1)
367         glVertex2f( cornerSize, h-cornerSize)
368         glTexCoord2f(tx1, ty1)
369         glVertex2f( w-cornerSize, h-cornerSize)
370
371         #Right
372         glTexCoord2f(tx2, ty1)
373         glVertex2f( w, cornerSize)
374         glTexCoord2f(tx1, ty1)
375         glVertex2f( w-cornerSize, cornerSize)
376         glTexCoord2f(tx1, ty1)
377         glVertex2f( w-cornerSize, h-cornerSize)
378         glTexCoord2f(tx2, ty1)
379         glVertex2f( w, h-cornerSize)
380
381         #Left
382         glTexCoord2f(tx1, ty1)
383         glVertex2f( cornerSize, cornerSize)
384         glTexCoord2f(tx0, ty1)
385         glVertex2f( 0, cornerSize)
386         glTexCoord2f(tx0, ty1)
387         glVertex2f( 0, h-cornerSize)
388         glTexCoord2f(tx1, ty1)
389         glVertex2f( cornerSize, h-cornerSize)
390
391         #Top
392         glTexCoord2f(tx1, ty0)
393         glVertex2f( w-cornerSize, 0)
394         glTexCoord2f(tx1, ty0)
395         glVertex2f( cornerSize, 0)
396         glTexCoord2f(tx1, ty1)
397         glVertex2f( cornerSize, cornerSize)
398         glTexCoord2f(tx1, ty1)
399         glVertex2f( w-cornerSize, cornerSize)
400
401         #Bottom
402         glTexCoord2f(tx1, ty1)
403         glVertex2f( w-cornerSize, h-cornerSize)
404         glTexCoord2f(tx1, ty1)
405         glVertex2f( cornerSize, h-cornerSize)
406         glTexCoord2f(tx1, ty2)
407         glVertex2f( cornerSize, h)
408         glTexCoord2f(tx1, ty2)
409         glVertex2f( w-cornerSize, h)
410
411         glEnd()
412         glDisable(GL_TEXTURE_2D)
413         glPopMatrix()
414
415 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
416         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
417         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
418         finalMatrix = npModelMatrix * npProjMatrix
419         finalMatrix = numpy.linalg.inv(finalMatrix)
420
421         viewport = map(float, viewport)
422         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))
423         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
424         ret = list(vector)[0:3] / vector[3]
425         return ret
426
427 def convert3x3MatrixTo4x4(matrix):
428         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
429
430 def loadGLTexture(filename):
431         tex = glGenTextures(1)
432         glBindTexture(GL_TEXTURE_2D, tex)
433         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
434         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
435         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
436         rgbData = img.GetData()
437         alphaData = img.GetAlphaData()
438         if alphaData is not None:
439                 data = ''
440                 for i in xrange(0, len(alphaData)):
441                         data += rgbData[i*3:i*3+3] + alphaData[i]
442                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
443         else:
444                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
445         return tex
446
447 def ResetMatrixRotationAndScale():
448         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
449         noZ = False
450         if matrix[3][2] > 0:
451                 return False
452         scale2D = matrix[0][0]
453         matrix[0][0] = 1.0
454         matrix[1][0] = 0.0
455         matrix[2][0] = 0.0
456         matrix[0][1] = 0.0
457         matrix[1][1] = 1.0
458         matrix[2][1] = 0.0
459         matrix[0][2] = 0.0
460         matrix[1][2] = 0.0
461         matrix[2][2] = 1.0
462
463         if matrix[3][2] != 0.0:
464                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
465                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
466                 matrix[3][2] = -100
467         else:
468                 matrix[0][0] = scale2D
469                 matrix[1][1] = scale2D
470                 matrix[2][2] = scale2D
471                 matrix[3][2] = -100
472                 noZ = True
473
474         glLoadMatrixf(matrix)
475         return noZ
476
477
478 def DrawBox(vMin, vMax):
479         glBegin(GL_LINE_LOOP)
480         glVertex3f(vMin[0], vMin[1], vMin[2])
481         glVertex3f(vMax[0], vMin[1], vMin[2])
482         glVertex3f(vMax[0], vMax[1], vMin[2])
483         glVertex3f(vMin[0], vMax[1], vMin[2])
484         glEnd()
485
486         glBegin(GL_LINE_LOOP)
487         glVertex3f(vMin[0], vMin[1], vMax[2])
488         glVertex3f(vMax[0], vMin[1], vMax[2])
489         glVertex3f(vMax[0], vMax[1], vMax[2])
490         glVertex3f(vMin[0], vMax[1], vMax[2])
491         glEnd()
492         glBegin(GL_LINES)
493         glVertex3f(vMin[0], vMin[1], vMin[2])
494         glVertex3f(vMin[0], vMin[1], vMax[2])
495         glVertex3f(vMax[0], vMin[1], vMin[2])
496         glVertex3f(vMax[0], vMin[1], vMax[2])
497         glVertex3f(vMax[0], vMax[1], vMin[2])
498         glVertex3f(vMax[0], vMax[1], vMax[2])
499         glVertex3f(vMin[0], vMax[1], vMin[2])
500         glVertex3f(vMin[0], vMax[1], vMax[2])
501         glEnd()
502
503
504 def DrawMeshOutline(mesh):
505         glEnable(GL_CULL_FACE)
506         glEnableClientState(GL_VERTEX_ARRAY);
507         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
508
509         glCullFace(GL_FRONT)
510         glLineWidth(3)
511         glPolygonMode(GL_BACK, GL_LINE)
512         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
513         glPolygonMode(GL_BACK, GL_FILL)
514         glCullFace(GL_BACK)
515
516         glDisableClientState(GL_VERTEX_ARRAY)
517
518
519 def DrawMesh(mesh, insideOut = False):
520         glEnable(GL_CULL_FACE)
521         glEnableClientState(GL_VERTEX_ARRAY)
522         glEnableClientState(GL_NORMAL_ARRAY)
523         for m in mesh._meshList:
524                 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
525                 if insideOut:
526                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
527                 else:
528                         glNormalPointer(GL_FLOAT, 0, m.normal)
529
530                 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
531                 batchSize = 999    #Warning, batchSize needs to be dividable by 3
532                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
533                 extraCount = m.vertexCount - extraStartPos
534
535                 glCullFace(GL_BACK)
536                 for i in xrange(0, int(m.vertexCount / batchSize)):
537                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
538                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
539
540                 glCullFace(GL_FRONT)
541                 if insideOut:
542                         glNormalPointer(GL_FLOAT, 0, m.normal)
543                 else:
544                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
545                 for i in xrange(0, int(m.vertexCount / batchSize)):
546                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
547                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
548                 extraCount = m.vertexCount - extraStartPos
549                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
550                 glCullFace(GL_BACK)
551
552         glDisableClientState(GL_VERTEX_ARRAY)
553         glDisableClientState(GL_NORMAL_ARRAY)
554
555
556 def DrawMeshSteep(mesh, matrix, angle):
557         cosAngle = math.sin(angle / 180.0 * math.pi)
558         glDisable(GL_LIGHTING)
559         glDepthFunc(GL_EQUAL)
560         normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
561         for i in xrange(0, int(mesh.vertexCount), 3):
562                 if normals[i][2] < -0.999999:
563                         if mesh.vertexes[i + 0][2] > 0.01:
564                                 glColor3f(0.5, 0, 0)
565                                 glBegin(GL_TRIANGLES)
566                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
567                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
568                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
569                                 glEnd()
570                 elif normals[i][2] < -cosAngle:
571                         glColor3f(-normals[i][2], 0, 0)
572                         glBegin(GL_TRIANGLES)
573                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
574                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
575                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
576                         glEnd()
577                 elif normals[i][2] > 0.999999:
578                         if mesh.vertexes[i + 0][2] > 0.01:
579                                 glColor3f(0.5, 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 + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
583                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
584                                 glEnd()
585                 elif normals[i][2] > cosAngle:
586                         glColor3f(normals[i][2], 0, 0)
587                         glBegin(GL_TRIANGLES)
588                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
589                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
590                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
591                         glEnd()
592         glDepthFunc(GL_LESS)
593
594 def DrawGCodeLayer(layer, drawQuick = True):
595         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
596         filamentArea = math.pi * filamentRadius * filamentRadius
597         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
598
599         fillCycle = 0
600         fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
601         moveColor = [0, 0, 1, 0.5]
602         retractColor = [1, 0, 0.5, 0.5]
603         supportColor = [0, 1, 1, 1]
604         extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
605         innerWallColor = [0, 1, 0, 1]
606         skirtColor = [0, 0.5, 0.5, 1]
607         prevPathWasRetract = False
608
609         glDisable(GL_CULL_FACE)
610         for path in layer:
611                 if path.type == 'move':
612                         if prevPathWasRetract:
613                                 c = retractColor
614                         else:
615                                 c = moveColor
616                         if drawQuick:
617                                 continue
618                 zOffset = 0.01
619                 if path.type == 'extrude':
620                         if path.pathType == 'FILL':
621                                 c = fillColorCycle[fillCycle]
622                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
623                         elif path.pathType == 'WALL-INNER':
624                                 c = innerWallColor
625                                 zOffset = 0.02
626                         elif path.pathType == 'SUPPORT':
627                                 c = supportColor
628                         elif path.pathType == 'SKIRT':
629                                 c = skirtColor
630                         else:
631                                 c = extrudeColor[path.extruder]
632                 if path.type == 'retract':
633                         c = retractColor
634                 if path.type == 'extrude' and not drawQuick:
635                         drawLength = 0.0
636                         prevNormal = None
637                         for i in xrange(0, len(path.points) - 1):
638                                 v0 = path.points[i]
639                                 v1 = path.points[i + 1]
640
641                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
642                                 dist = (v0 - v1).vsize()
643                                 if dist > 0 and path.layerThickness > 0:
644                                         extrusionMMperDist = (v1.e - v0.e) / dist
645                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
646
647                                 drawLength += (v0 - v1).vsize()
648                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
649                                 normal.normalize()
650
651                                 vv2 = v0 + normal * lineWidth
652                                 vv3 = v1 + normal * lineWidth
653                                 vv0 = v0 - normal * lineWidth
654                                 vv1 = v1 - normal * lineWidth
655
656                                 glBegin(GL_QUADS)
657                                 glColor4fv(c)
658                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
659                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
660                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
661                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
662                                 glEnd()
663                                 if prevNormal is not None:
664                                         n = (normal + prevNormal)
665                                         n.normalize()
666                                         vv4 = v0 + n * lineWidth
667                                         vv5 = v0 - n * lineWidth
668                                         glBegin(GL_QUADS)
669                                         glColor4fv(c)
670                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
671                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
672                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
673                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
674
675                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
676                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
677                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
678                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
679                                         glEnd()
680
681                                 prevNormal = normal
682                                 prevVv1 = vv1
683                                 prevVv3 = vv3
684                 else:
685                         glColor4fv(c)
686                         glBegin(GL_TRIANGLES)
687                         for v in path.points:
688                                 glVertex3f(v[0], v[1], v[2])
689                         glEnd()
690
691                 if not path.type == 'move':
692                         prevPathWasRetract = False
693                 #if path.type == 'retract' and path.points[0].almostEqual(path.points[-1]):
694                 #       prevPathWasRetract = True
695         glEnable(GL_CULL_FACE)