chiark / gitweb /
Fixed a typo. Changed the GCode rendering so it gives quick results first, and then...
[cura.git] / Cura / gui / util / opengl.py
1 # coding=utf-8
2 from __future__ import absolute_import
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 glutInit()
21
22 def InitGL(window, view3D, zoom):
23         # set viewing projection
24         glMatrixMode(GL_MODELVIEW)
25         glLoadIdentity()
26         size = window.GetSize()
27         glViewport(0, 0, size.GetWidth(), size.GetHeight())
28
29         glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
30         glLightfv(GL_LIGHT1, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
31
32         glEnable(GL_RESCALE_NORMAL)
33         glEnable(GL_LIGHTING)
34         glEnable(GL_LIGHT0)
35         glEnable(GL_DEPTH_TEST)
36         glEnable(GL_CULL_FACE)
37         glDisable(GL_BLEND)
38
39         glClearColor(1.0, 1.0, 1.0, 1.0)
40         glClearStencil(0)
41         glClearDepth(1.0)
42
43         glMatrixMode(GL_PROJECTION)
44         glLoadIdentity()
45         aspect = float(size.GetWidth()) / float(size.GetHeight())
46         if view3D:
47                 gluPerspective(45.0, aspect, 1.0, 1000.0)
48         else:
49                 glOrtho(-aspect * (zoom), aspect * (zoom), -1.0 * (zoom), 1.0 * (zoom), -1000.0, 1000.0)
50
51         glMatrixMode(GL_MODELVIEW)
52         glLoadIdentity()
53         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
54
55 platformMesh = None
56
57 def DrawMachine(machineSize):
58         glDisable(GL_LIGHTING)
59         glDisable(GL_CULL_FACE)
60         glEnable(GL_BLEND)
61         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
62
63         sx = machineSize.x
64         sy = machineSize.y
65         for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
66                 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
67                         x1 = sx/2+x * 10
68                         x2 = x1 + 10
69                         y1 = sx/2+y * 10
70                         y2 = y1 + 10
71                         x1 = max(min(x1, sx), 0)
72                         y1 = max(min(y1, sy), 0)
73                         x2 = max(min(x2, sx), 0)
74                         y2 = max(min(y2, sy), 0)
75                         if (x & 1) == (y & 1):
76                                 glColor4ub(5, 171, 231, 127)
77                         else:
78                                 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
79                         glBegin(GL_QUADS)
80                         glVertex3f(x1, y1, -0.02)
81                         glVertex3f(x2, y1, -0.02)
82                         glVertex3f(x2, y2, -0.02)
83                         glVertex3f(x1, y2, -0.02)
84                         glEnd()
85
86         glEnable(GL_CULL_FACE)
87
88         if profile.getPreference('machine_type') == 'ultimaker':
89                 glPushMatrix()
90                 glEnable(GL_LIGHTING)
91                 glTranslate(100, 200, -1)
92                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
93                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
94                 glEnable(GL_BLEND)
95                 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
96
97                 global platformMesh
98                 if platformMesh is None:
99                         try:
100                                 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
101                         except:
102                                 platformMesh = False
103
104                 if platformMesh:
105                         DrawMesh(platformMesh)
106                 glPopMatrix()
107                 glDisable(GL_LIGHTING)
108                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
109
110         glColor4ub(5, 171, 231, 64)
111         glBegin(GL_QUADS)
112         glVertex3f(0, 0, machineSize.z)
113         glVertex3f(0, machineSize.y, machineSize.z)
114         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
115         glVertex3f(machineSize.x, 0, machineSize.z)
116         glEnd()
117
118         glColor4ub(5, 171, 231, 96)
119         glBegin(GL_QUADS)
120         glVertex3f(0, 0, 0)
121         glVertex3f(0, 0, machineSize.z)
122         glVertex3f(machineSize.x, 0, machineSize.z)
123         glVertex3f(machineSize.x, 0, 0)
124
125         glVertex3f(0, machineSize.y, machineSize.z)
126         glVertex3f(0, machineSize.y, 0)
127         glVertex3f(machineSize.x, machineSize.y, 0)
128         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
129         glEnd()
130
131         glColor4ub(5, 171, 231, 128)
132         glBegin(GL_QUADS)
133         glVertex3f(0, 0, machineSize.z)
134         glVertex3f(0, 0, 0)
135         glVertex3f(0, machineSize.y, 0)
136         glVertex3f(0, machineSize.y, machineSize.z)
137
138         glVertex3f(machineSize.x, 0, 0)
139         glVertex3f(machineSize.x, 0, machineSize.z)
140         glVertex3f(machineSize.x, machineSize.y, machineSize.z)
141         glVertex3f(machineSize.x, machineSize.y, 0)
142         glEnd()
143
144         glDisable(GL_BLEND)
145
146         #Draw the X/Y/Z indicator
147         glPushMatrix()
148         glTranslate(5, 5, 2)
149         glLineWidth(2)
150         glColor3f(0.5, 0, 0)
151         glBegin(GL_LINES)
152         glVertex3f(0, 0, 0)
153         glVertex3f(20, 0, 0)
154         glEnd()
155         glColor3f(0, 0.5, 0)
156         glBegin(GL_LINES)
157         glVertex3f(0, 0, 0)
158         glVertex3f(0, 20, 0)
159         glEnd()
160         glColor3f(0, 0, 0.5)
161         glBegin(GL_LINES)
162         glVertex3f(0, 0, 0)
163         glVertex3f(0, 0, 20)
164         glEnd()
165
166         glDisable(GL_DEPTH_TEST)
167         #X
168         glColor3f(1, 0, 0)
169         glPushMatrix()
170         glTranslate(20, 0, 0)
171         noZ = ResetMatrixRotationAndScale()
172         glDrawStringCenter("X")
173         glPopMatrix()
174
175         #Y
176         glColor3f(0, 1, 0)
177         glPushMatrix()
178         glTranslate(0, 20, 0)
179         glDrawStringCenter("Y")
180         glPopMatrix()
181
182         #Z
183         if not noZ:
184                 glColor3f(0, 0, 1)
185                 glPushMatrix()
186                 glTranslate(0, 0, 20)
187                 glDrawStringCenter("Z")
188                 glPopMatrix()
189
190         glPopMatrix()
191         glEnable(GL_DEPTH_TEST)
192
193 def glDrawStringCenter(s):
194         glRasterPos2f(0, 0)
195         glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
196         for c in s:
197                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
198
199 def glGetStringSize(s):
200         width = 0
201         for c in s:
202                 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
203         height = 18
204         return width, height
205
206 def glDrawStringLeft(s):
207         glRasterPos2f(0, 0)
208         for c in s:
209                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
210
211 def glDrawStringRight(s):
212         glRasterPos2f(0, 0)
213         glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
214         for c in s:
215                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
216
217 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
218         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
219         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
220         finalMatrix = npModelMatrix * npProjMatrix
221         finalMatrix = numpy.linalg.inv(finalMatrix)
222
223         viewport = map(float, viewport)
224         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))
225         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
226         ret = list(vector)[0:3] / vector[3]
227         return ret
228
229 def convert3x3MatrixTo4x4(matrix):
230         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
231
232 def loadGLTexture(filename):
233         tex = glGenTextures(1)
234         glBindTexture(GL_TEXTURE_2D, tex)
235         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
236         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
237         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
238         rgbData = img.GetData()
239         alphaData = img.GetAlphaData()
240         if alphaData is not None:
241                 data = ''
242                 for i in xrange(0, len(alphaData)):
243                         data += rgbData[i*3:i*3+3] + alphaData[i]
244                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
245         else:
246                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
247         return tex
248
249 def ResetMatrixRotationAndScale():
250         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
251         noZ = False
252         if matrix[3][2] > 0:
253                 return False
254         scale2D = matrix[0][0]
255         matrix[0][0] = 1.0
256         matrix[1][0] = 0.0
257         matrix[2][0] = 0.0
258         matrix[0][1] = 0.0
259         matrix[1][1] = 1.0
260         matrix[2][1] = 0.0
261         matrix[0][2] = 0.0
262         matrix[1][2] = 0.0
263         matrix[2][2] = 1.0
264
265         if matrix[3][2] != 0.0:
266                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
267                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
268                 matrix[3][2] = -100
269         else:
270                 matrix[0][0] = scale2D
271                 matrix[1][1] = scale2D
272                 matrix[2][2] = scale2D
273                 matrix[3][2] = -100
274                 noZ = True
275
276         glLoadMatrixf(matrix)
277         return noZ
278
279
280 def DrawBox(vMin, vMax):
281         glBegin(GL_LINE_LOOP)
282         glVertex3f(vMin[0], vMin[1], vMin[2])
283         glVertex3f(vMax[0], vMin[1], vMin[2])
284         glVertex3f(vMax[0], vMax[1], vMin[2])
285         glVertex3f(vMin[0], vMax[1], vMin[2])
286         glEnd()
287
288         glBegin(GL_LINE_LOOP)
289         glVertex3f(vMin[0], vMin[1], vMax[2])
290         glVertex3f(vMax[0], vMin[1], vMax[2])
291         glVertex3f(vMax[0], vMax[1], vMax[2])
292         glVertex3f(vMin[0], vMax[1], vMax[2])
293         glEnd()
294         glBegin(GL_LINES)
295         glVertex3f(vMin[0], vMin[1], vMin[2])
296         glVertex3f(vMin[0], vMin[1], vMax[2])
297         glVertex3f(vMax[0], vMin[1], vMin[2])
298         glVertex3f(vMax[0], vMin[1], vMax[2])
299         glVertex3f(vMax[0], vMax[1], vMin[2])
300         glVertex3f(vMax[0], vMax[1], vMax[2])
301         glVertex3f(vMin[0], vMax[1], vMin[2])
302         glVertex3f(vMin[0], vMax[1], vMax[2])
303         glEnd()
304
305
306 def DrawMeshOutline(mesh):
307         glEnable(GL_CULL_FACE)
308         glEnableClientState(GL_VERTEX_ARRAY);
309         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
310
311         glCullFace(GL_FRONT)
312         glLineWidth(3)
313         glPolygonMode(GL_BACK, GL_LINE)
314         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
315         glPolygonMode(GL_BACK, GL_FILL)
316         glCullFace(GL_BACK)
317
318         glDisableClientState(GL_VERTEX_ARRAY)
319
320
321 def DrawMesh(mesh, insideOut = False):
322         glEnable(GL_CULL_FACE)
323         glEnableClientState(GL_VERTEX_ARRAY);
324         glEnableClientState(GL_NORMAL_ARRAY);
325         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
326         if insideOut:
327                 glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
328         else:
329                 glNormalPointer(GL_FLOAT, 0, mesh.normal)
330
331         #Odd, drawing in batchs is a LOT faster then drawing it all at once.
332         batchSize = 999    #Warning, batchSize needs to be dividable by 3
333         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
334         extraCount = mesh.vertexCount - extraStartPos
335
336         glCullFace(GL_BACK)
337         for i in xrange(0, int(mesh.vertexCount / batchSize)):
338                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
339         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
340
341         glCullFace(GL_FRONT)
342         if insideOut:
343                 glNormalPointer(GL_FLOAT, 0, mesh.normal)
344         else:
345                 glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
346         for i in xrange(0, int(mesh.vertexCount / batchSize)):
347                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
348         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
349         extraCount = mesh.vertexCount - extraStartPos
350         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
351         glCullFace(GL_BACK)
352
353         glDisableClientState(GL_VERTEX_ARRAY)
354         glDisableClientState(GL_NORMAL_ARRAY)
355
356
357 def DrawMeshSteep(mesh, matrix, angle):
358         cosAngle = math.sin(angle / 180.0 * math.pi)
359         glDisable(GL_LIGHTING)
360         glDepthFunc(GL_EQUAL)
361         normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
362         for i in xrange(0, int(mesh.vertexCount), 3):
363                 if normals[i][2] < -0.999999:
364                         if mesh.vertexes[i + 0][2] > 0.01:
365                                 glColor3f(0.5, 0, 0)
366                                 glBegin(GL_TRIANGLES)
367                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
368                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
369                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
370                                 glEnd()
371                 elif normals[i][2] < -cosAngle:
372                         glColor3f(-normals[i][2], 0, 0)
373                         glBegin(GL_TRIANGLES)
374                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
375                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
376                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
377                         glEnd()
378                 elif normals[i][2] > 0.999999:
379                         if mesh.vertexes[i + 0][2] > 0.01:
380                                 glColor3f(0.5, 0, 0)
381                                 glBegin(GL_TRIANGLES)
382                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
383                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
384                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
385                                 glEnd()
386                 elif normals[i][2] > cosAngle:
387                         glColor3f(normals[i][2], 0, 0)
388                         glBegin(GL_TRIANGLES)
389                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
390                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
391                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
392                         glEnd()
393         glDepthFunc(GL_LESS)
394
395
396 def DrawGCodeLayer(layer, drawQuick = True):
397         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
398         filamentArea = math.pi * filamentRadius * filamentRadius
399         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
400
401         fillCycle = 0
402         fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
403         moveColor = [0, 0, 1, 0.5]
404         retractColor = [1, 0, 0.5, 0.5]
405         supportColor = [0, 1, 1, 1]
406         extrudeColor = [1, 0, 0, 1]
407         innerWallColor = [0, 1, 0, 1]
408         skirtColor = [0, 0.5, 0.5, 1]
409         prevPathWasRetract = False
410
411         glDisable(GL_CULL_FACE)
412         for path in layer:
413                 if path.type == 'move':
414                         if prevPathWasRetract:
415                                 c = retractColor
416                         else:
417                                 c = moveColor
418                         if drawQuick:
419                                 continue
420                 zOffset = 0.01
421                 if path.type == 'extrude':
422                         if path.pathType == 'FILL':
423                                 c = fillColorCycle[fillCycle]
424                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
425                                 if drawQuick:
426                                         continue
427                         elif path.pathType == 'WALL-INNER':
428                                 c = innerWallColor
429                                 zOffset = 0.02
430                         elif path.pathType == 'SUPPORT':
431                                 c = supportColor
432                         elif path.pathType == 'SKIRT':
433                                 c = skirtColor
434                         else:
435                                 c = extrudeColor
436                 if path.type == 'retract':
437                         c = retractColor
438                 if path.type == 'extrude' and not drawQuick:
439                         drawLength = 0.0
440                         prevNormal = None
441                         for i in xrange(0, len(path.list) - 1):
442                                 v0 = path.list[i]
443                                 v1 = path.list[i + 1]
444
445                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
446                                 dist = (v0 - v1).vsize()
447                                 if dist > 0 and path.layerThickness > 0:
448                                         extrusionMMperDist = (v1.e - v0.e) / dist
449                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
450
451                                 drawLength += (v0 - v1).vsize()
452                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
453                                 normal.normalize()
454
455                                 vv2 = v0 + normal * lineWidth
456                                 vv3 = v1 + normal * lineWidth
457                                 vv0 = v0 - normal * lineWidth
458                                 vv1 = v1 - normal * lineWidth
459
460                                 glBegin(GL_QUADS)
461                                 glColor4fv(c)
462                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
463                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
464                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
465                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
466                                 glEnd()
467                                 if prevNormal is not None:
468                                         n = (normal + prevNormal)
469                                         n.normalize()
470                                         vv4 = v0 + n * lineWidth
471                                         vv5 = v0 - n * lineWidth
472                                         glBegin(GL_QUADS)
473                                         glColor4fv(c)
474                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
475                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
476                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
477                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
478
479                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
480                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
481                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
482                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
483                                         glEnd()
484
485                                 prevNormal = normal
486                                 prevVv1 = vv1
487                                 prevVv3 = vv3
488                 else:
489                         glBegin(GL_LINE_STRIP)
490                         glColor4fv(c)
491                         for v in path.list:
492                                 glVertex3f(v.x, v.y, v.z)
493                         glEnd()
494                 if not path.type == 'move':
495                         prevPathWasRetract = False
496                 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
497                         prevPathWasRetract = True
498         glEnable(GL_CULL_FACE)