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