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