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