chiark / gitweb /
Initial changes to get some project planner stuff working again.
[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         width = 0
195         for c in s:
196                 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
197         glBitmap(0,0,0,0, -width/2, 0, None)
198         for c in s:
199                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
200
201 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
202         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
203         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
204         finalMatrix = npModelMatrix * npProjMatrix
205         finalMatrix = numpy.linalg.inv(finalMatrix)
206
207         viewport = map(float, viewport)
208         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))
209         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
210         ret = list(vector)[0:3] / vector[3]
211         return ret
212
213 def convert3x3MatrixTo4x4(matrix):
214         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
215
216 def loadGLTexture(filename):
217         tex = glGenTextures(1)
218         glBindTexture(GL_TEXTURE_2D, tex)
219         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
220         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
221         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
222         rgbData = img.GetData()
223         alphaData = img.GetAlphaData()
224         if alphaData is not None:
225                 data = ''
226                 for i in xrange(0, len(alphaData)):
227                         data += rgbData[i*3:i*3+3] + alphaData[i]
228                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
229         else:
230                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
231         return tex
232
233 def ResetMatrixRotationAndScale():
234         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
235         noZ = False
236         if matrix[3][2] > 0:
237                 return False
238         scale2D = matrix[0][0]
239         matrix[0][0] = 1.0
240         matrix[1][0] = 0.0
241         matrix[2][0] = 0.0
242         matrix[0][1] = 0.0
243         matrix[1][1] = 1.0
244         matrix[2][1] = 0.0
245         matrix[0][2] = 0.0
246         matrix[1][2] = 0.0
247         matrix[2][2] = 1.0
248
249         if matrix[3][2] != 0.0:
250                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
251                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
252                 matrix[3][2] = -100
253         else:
254                 matrix[0][0] = scale2D
255                 matrix[1][1] = scale2D
256                 matrix[2][2] = scale2D
257                 matrix[3][2] = -100
258                 noZ = True
259
260         glLoadMatrixf(matrix)
261         return noZ
262
263
264 def DrawBox(vMin, vMax):
265         glBegin(GL_LINE_LOOP)
266         glVertex3f(vMin[0], vMin[1], vMin[2])
267         glVertex3f(vMax[0], vMin[1], vMin[2])
268         glVertex3f(vMax[0], vMax[1], vMin[2])
269         glVertex3f(vMin[0], vMax[1], vMin[2])
270         glEnd()
271
272         glBegin(GL_LINE_LOOP)
273         glVertex3f(vMin[0], vMin[1], vMax[2])
274         glVertex3f(vMax[0], vMin[1], vMax[2])
275         glVertex3f(vMax[0], vMax[1], vMax[2])
276         glVertex3f(vMin[0], vMax[1], vMax[2])
277         glEnd()
278         glBegin(GL_LINES)
279         glVertex3f(vMin[0], vMin[1], vMin[2])
280         glVertex3f(vMin[0], vMin[1], vMax[2])
281         glVertex3f(vMax[0], vMin[1], vMin[2])
282         glVertex3f(vMax[0], vMin[1], vMax[2])
283         glVertex3f(vMax[0], vMax[1], vMin[2])
284         glVertex3f(vMax[0], vMax[1], vMax[2])
285         glVertex3f(vMin[0], vMax[1], vMin[2])
286         glVertex3f(vMin[0], vMax[1], vMax[2])
287         glEnd()
288
289
290 def DrawMeshOutline(mesh):
291         glEnable(GL_CULL_FACE)
292         glEnableClientState(GL_VERTEX_ARRAY);
293         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
294
295         glCullFace(GL_FRONT)
296         glLineWidth(3)
297         glPolygonMode(GL_BACK, GL_LINE)
298         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
299         glPolygonMode(GL_BACK, GL_FILL)
300         glCullFace(GL_BACK)
301
302         glDisableClientState(GL_VERTEX_ARRAY)
303
304
305 def DrawMesh(mesh):
306         glEnable(GL_CULL_FACE)
307         glEnableClientState(GL_VERTEX_ARRAY);
308         glEnableClientState(GL_NORMAL_ARRAY);
309         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
310         glNormalPointer(GL_FLOAT, 0, mesh.normal)
311
312         #Odd, drawing in batchs is a LOT faster then drawing it all at once.
313         batchSize = 999    #Warning, batchSize needs to be dividable by 3
314         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
315         extraCount = mesh.vertexCount - extraStartPos
316
317         glCullFace(GL_BACK)
318         for i in xrange(0, int(mesh.vertexCount / batchSize)):
319                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
320         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
321
322         glCullFace(GL_FRONT)
323         glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
324         for i in xrange(0, int(mesh.vertexCount / batchSize)):
325                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
326         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
327         extraCount = mesh.vertexCount - extraStartPos
328         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
329         glCullFace(GL_BACK)
330
331         glDisableClientState(GL_VERTEX_ARRAY)
332         glDisableClientState(GL_NORMAL_ARRAY);
333
334
335 def DrawMeshSteep(mesh, angle):
336         cosAngle = math.sin(angle / 180.0 * math.pi)
337         glDisable(GL_LIGHTING)
338         glDepthFunc(GL_EQUAL)
339         for i in xrange(0, int(mesh.vertexCount), 3):
340                 if mesh.normal[i][2] < -0.999999:
341                         if mesh.vertexes[i + 0][2] > 0.01:
342                                 glColor3f(0.5, 0, 0)
343                                 glBegin(GL_TRIANGLES)
344                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
345                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
346                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
347                                 glEnd()
348                 elif mesh.normal[i][2] < -cosAngle:
349                         glColor3f(-mesh.normal[i][2], 0, 0)
350                         glBegin(GL_TRIANGLES)
351                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
352                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
353                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
354                         glEnd()
355                 elif mesh.normal[i][2] > 0.999999:
356                         if mesh.vertexes[i + 0][2] > 0.01:
357                                 glColor3f(0.5, 0, 0)
358                                 glBegin(GL_TRIANGLES)
359                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
360                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
361                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
362                                 glEnd()
363                 elif mesh.normal[i][2] > cosAngle:
364                         glColor3f(mesh.normal[i][2], 0, 0)
365                         glBegin(GL_TRIANGLES)
366                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
367                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
368                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
369                         glEnd()
370         glDepthFunc(GL_LESS)
371
372
373 def DrawGCodeLayer(layer):
374         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
375         filamentArea = math.pi * filamentRadius * filamentRadius
376         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
377
378         fillCycle = 0
379         fillColorCycle = [[0.5, 0.5, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]]
380         moveColor = [0, 0, 1]
381         retractColor = [1, 0, 0.5]
382         supportColor = [0, 1, 1]
383         extrudeColor = [1, 0, 0]
384         innerWallColor = [0, 1, 0]
385         skirtColor = [0, 0.5, 0.5]
386         prevPathWasRetract = False
387
388         glDisable(GL_CULL_FACE)
389         for path in layer:
390                 if path.type == 'move':
391                         if prevPathWasRetract:
392                                 c = retractColor
393                         else:
394                                 c = moveColor
395                 zOffset = 0.01
396                 if path.type == 'extrude':
397                         if path.pathType == 'FILL':
398                                 c = fillColorCycle[fillCycle]
399                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
400                         elif path.pathType == 'WALL-INNER':
401                                 c = innerWallColor
402                                 zOffset = 0.02
403                         elif path.pathType == 'SUPPORT':
404                                 c = supportColor
405                         elif path.pathType == 'SKIRT':
406                                 c = skirtColor
407                         else:
408                                 c = extrudeColor
409                 if path.type == 'retract':
410                         c = [0, 1, 1]
411                 if path.type == 'extrude':
412                         drawLength = 0.0
413                         prevNormal = None
414                         for i in xrange(0, len(path.list) - 1):
415                                 v0 = path.list[i]
416                                 v1 = path.list[i + 1]
417
418                                 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
419                                 dist = (v0 - v1).vsize()
420                                 if dist > 0 and path.layerThickness > 0:
421                                         extrusionMMperDist = (v1.e - v0.e) / dist
422                                         lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
423
424                                 drawLength += (v0 - v1).vsize()
425                                 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
426                                 normal.normalize()
427
428                                 vv2 = v0 + normal * lineWidth
429                                 vv3 = v1 + normal * lineWidth
430                                 vv0 = v0 - normal * lineWidth
431                                 vv1 = v1 - normal * lineWidth
432
433                                 glBegin(GL_QUADS)
434                                 glColor3fv(c)
435                                 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
436                                 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
437                                 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
438                                 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
439                                 glEnd()
440                                 if prevNormal is not None:
441                                         n = (normal + prevNormal)
442                                         n.normalize()
443                                         vv4 = v0 + n * lineWidth
444                                         vv5 = v0 - n * lineWidth
445                                         glBegin(GL_QUADS)
446                                         glColor3fv(c)
447                                         glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
448                                         glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
449                                         glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
450                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
451
452                                         glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
453                                         glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
454                                         glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
455                                         glVertex3f(v0.x, v0.y, v0.z - zOffset)
456                                         glEnd()
457
458                                 prevNormal = normal
459                                 prevVv1 = vv1
460                                 prevVv3 = vv3
461                 else:
462                         glBegin(GL_LINE_STRIP)
463                         glColor3fv(c)
464                         for v in path.list:
465                                 glVertex3f(v.x, v.y, v.z)
466                         glEnd()
467                 if not path.type == 'move':
468                         prevPathWasRetract = False
469                 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
470                         prevPathWasRetract = True
471         glEnable(GL_CULL_FACE)