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