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