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