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