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