chiark / gitweb /
Update on the OpenGL gui, now uses layout managers, and started work on a frame for...
[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):
315         glEnable(GL_CULL_FACE)
316         glEnableClientState(GL_VERTEX_ARRAY);
317         glEnableClientState(GL_NORMAL_ARRAY);
318         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
319         glNormalPointer(GL_FLOAT, 0, mesh.normal)
320
321         #Odd, drawing in batchs is a LOT faster then drawing it all at once.
322         batchSize = 999    #Warning, batchSize needs to be dividable by 3
323         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
324         extraCount = mesh.vertexCount - extraStartPos
325
326         glCullFace(GL_BACK)
327         for i in xrange(0, int(mesh.vertexCount / batchSize)):
328                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
329         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
330
331         glCullFace(GL_FRONT)
332         glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
333         for i in xrange(0, int(mesh.vertexCount / batchSize)):
334                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
335         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
336         extraCount = mesh.vertexCount - extraStartPos
337         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
338         glCullFace(GL_BACK)
339
340         glDisableClientState(GL_VERTEX_ARRAY)
341         glDisableClientState(GL_NORMAL_ARRAY)
342
343
344 def DrawMeshSteep(mesh, matrix, angle):
345         cosAngle = math.sin(angle / 180.0 * math.pi)
346         glDisable(GL_LIGHTING)
347         glDepthFunc(GL_EQUAL)
348         normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
349         for i in xrange(0, int(mesh.vertexCount), 3):
350                 if normals[i][2] < -0.999999:
351                         if mesh.vertexes[i + 0][2] > 0.01:
352                                 glColor3f(0.5, 0, 0)
353                                 glBegin(GL_TRIANGLES)
354                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
355                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
356                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
357                                 glEnd()
358                 elif normals[i][2] < -cosAngle:
359                         glColor3f(-normals[i][2], 0, 0)
360                         glBegin(GL_TRIANGLES)
361                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
362                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
363                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
364                         glEnd()
365                 elif normals[i][2] > 0.999999:
366                         if mesh.vertexes[i + 0][2] > 0.01:
367                                 glColor3f(0.5, 0, 0)
368                                 glBegin(GL_TRIANGLES)
369                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
370                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
371                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
372                                 glEnd()
373                 elif normals[i][2] > cosAngle:
374                         glColor3f(normals[i][2], 0, 0)
375                         glBegin(GL_TRIANGLES)
376                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
377                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
378                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
379                         glEnd()
380         glDepthFunc(GL_LESS)
381
382
383 def DrawGCodeLayer(layer):
384         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
385         filamentArea = math.pi * filamentRadius * filamentRadius
386         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
387
388         fillCycle = 0
389         fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
390         moveColor = [0, 0, 1, 0.5]
391         retractColor = [1, 0, 0.5, 0.5]
392         supportColor = [0, 1, 1, 1]
393         extrudeColor = [1, 0, 0, 1]
394         innerWallColor = [0, 1, 0, 1]
395         skirtColor = [0, 0.5, 0.5, 1]
396         prevPathWasRetract = False
397
398         glDisable(GL_CULL_FACE)
399         for path in layer:
400                 if path.type == 'move':
401                         if prevPathWasRetract:
402                                 c = retractColor
403                         else:
404                                 c = moveColor
405                 zOffset = 0.01
406                 if path.type == 'extrude':
407                         if path.pathType == 'FILL':
408                                 c = fillColorCycle[fillCycle]
409                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
410                         elif path.pathType == 'WALL-INNER':
411                                 c = innerWallColor
412                                 zOffset = 0.02
413                         elif path.pathType == 'SUPPORT':
414                                 c = supportColor
415                         elif path.pathType == 'SKIRT':
416                                 c = skirtColor
417                         else:
418                                 c = extrudeColor
419                 if path.type == 'retract':
420                         c = retractColor
421                 if path.type == 'extrude':
422                         drawLength = 0.0
423                         prevNormal = None
424                         for i in xrange(0, len(path.list) - 1):
425                                 v0 = path.list[i]
426                                 v1 = path.list[i + 1]
427
428                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
429                                 dist = (v0 - v1).vsize()
430                                 if dist > 0 and path.layerThickness > 0:
431                                         extrusionMMperDist = (v1.e - v0.e) / dist
432                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
433
434                                 drawLength += (v0 - v1).vsize()
435                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
436                                 normal.normalize()
437
438                                 vv2 = v0 + normal * lineWidth
439                                 vv3 = v1 + normal * lineWidth
440                                 vv0 = v0 - normal * lineWidth
441                                 vv1 = v1 - normal * lineWidth
442
443                                 glBegin(GL_QUADS)
444                                 glColor4fv(c)
445                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
446                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
447                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
448                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
449                                 glEnd()
450                                 if prevNormal is not None:
451                                         n = (normal + prevNormal)
452                                         n.normalize()
453                                         vv4 = v0 + n * lineWidth
454                                         vv5 = v0 - n * lineWidth
455                                         glBegin(GL_QUADS)
456                                         glColor4fv(c)
457                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
458                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
459                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
460                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
461
462                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
463                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
464                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
465                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
466                                         glEnd()
467
468                                 prevNormal = normal
469                                 prevVv1 = vv1
470                                 prevVv3 = vv3
471                 else:
472                         glBegin(GL_LINE_STRIP)
473                         glColor4fv(c)
474                         for v in path.list:
475                                 glVertex3f(v.x, v.y, v.z)
476                         glEnd()
477                 if not path.type == 'move':
478                         prevPathWasRetract = False
479                 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
480                         prevPathWasRetract = True
481         glEnable(GL_CULL_FACE)