chiark / gitweb /
Replacement for gluUnproject, which seems to be causing problems with some intel...
[cura.git] / Cura / gui / util / opengl.py
1 # coding=utf-8
2 from __future__ import absolute_import
3
4 import math
5
6 from Cura.util import meshLoader
7 from Cura.util import util3d
8 from Cura.util import profile
9 from Cura.util.resources import getPathForMesh
10
11 try:
12         import OpenGL
13
14         OpenGL.ERROR_CHECKING = False
15         from OpenGL.GLUT import *
16         from OpenGL.GLU import *
17         from OpenGL.GL import *
18         glutInit()
19
20         hasOpenGLlibs = True
21 except:
22         print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
23         hasOpenGLlibs = False
24
25 import numpy
26
27 def InitGL(window, view3D, zoom):
28         # set viewing projection
29         glMatrixMode(GL_MODELVIEW)
30         glLoadIdentity()
31         size = window.GetSize()
32         glViewport(0, 0, size.GetWidth(), size.GetHeight())
33
34         glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
35         glLightfv(GL_LIGHT1, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
36
37         glEnable(GL_RESCALE_NORMAL)
38         glEnable(GL_LIGHTING)
39         glEnable(GL_LIGHT0)
40         glEnable(GL_DEPTH_TEST)
41         glEnable(GL_CULL_FACE)
42         glDisable(GL_BLEND)
43
44         glClearColor(1.0, 1.0, 1.0, 1.0)
45         glClearStencil(0)
46         glClearDepth(1.0)
47
48         glMatrixMode(GL_PROJECTION)
49         glLoadIdentity()
50         aspect = float(size.GetWidth()) / float(size.GetHeight())
51         if view3D:
52                 gluPerspective(45.0, aspect, 1.0, 1000.0)
53         else:
54                 glOrtho(-aspect * (zoom), aspect * (zoom), -1.0 * (zoom), 1.0 * (zoom), -1000.0, 1000.0)
55
56         glMatrixMode(GL_MODELVIEW)
57         glLoadIdentity()
58         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
59
60 platformMesh = None
61
62 def DrawMachine(machineSize):
63         if profile.getPreference('machine_type') == 'ultimaker':
64                 glPushMatrix()
65                 glEnable(GL_LIGHTING)
66                 glTranslate(100, 200, -5)
67                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
68                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
69                 glEnable(GL_BLEND)
70                 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
71
72                 global platformMesh
73                 if platformMesh is None:
74                         try:
75                                 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
76                         except:
77                                 platformMesh = False
78
79                 if platformMesh:
80                         DrawMesh(platformMesh)
81                 glPopMatrix()
82
83         glDisable(GL_LIGHTING)
84         if False:
85                 glColor3f(0.7, 0.7, 0.7)
86                 glLineWidth(2)
87                 glBegin(GL_LINES)
88                 for i in xrange(0, int(machineSize.x), 10):
89                         glVertex3f(i, 0, 0)
90                         glVertex3f(i, machineSize.y, 0)
91                 for i in xrange(0, int(machineSize.y), 10):
92                         glVertex3f(0, i, 0)
93                         glVertex3f(machineSize.x, i, 0)
94                 glEnd()
95
96                 glEnable(GL_LINE_SMOOTH)
97                 glEnable(GL_BLEND)
98                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
99                 glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
100
101                 glColor3f(0.0, 0.0, 0.0)
102                 glLineWidth(4)
103                 glBegin(GL_LINE_LOOP)
104                 glVertex3f(0, 0, 0)
105                 glVertex3f(machineSize.x, 0, 0)
106                 glVertex3f(machineSize.x, machineSize.y, 0)
107                 glVertex3f(0, machineSize.y, 0)
108                 glEnd()
109
110                 glLineWidth(2)
111                 glBegin(GL_LINE_LOOP)
112                 glVertex3f(0, 0, machineSize.z)
113                 glVertex3f(machineSize.x, 0, machineSize.z)
114                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
115                 glVertex3f(0, machineSize.y, machineSize.z)
116                 glEnd()
117                 glBegin(GL_LINES)
118                 glVertex3f(0, 0, 0)
119                 glVertex3f(0, 0, machineSize.z)
120                 glVertex3f(machineSize.x, 0, 0)
121                 glVertex3f(machineSize.x, 0, machineSize.z)
122                 glVertex3f(machineSize.x, machineSize.y, 0)
123                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
124                 glVertex3f(0, machineSize.y, 0)
125                 glVertex3f(0, machineSize.y, machineSize.z)
126                 glEnd()
127         else:
128                 glDisable(GL_CULL_FACE)
129                 glEnable(GL_BLEND)
130                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
131
132                 sx = machineSize.x
133                 sy = machineSize.y
134                 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
135                         for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
136                                 x1 = sx/2+x * 10
137                                 x2 = x1 + 10
138                                 y1 = sx/2+y * 10
139                                 y2 = y1 + 10
140                                 x1 = max(min(x1, sx), 0)
141                                 y1 = max(min(y1, sy), 0)
142                                 x2 = max(min(x2, sx), 0)
143                                 y2 = max(min(y2, sy), 0)
144                                 if (x & 1) == (y & 1):
145                                         glColor4ub(5, 171, 231, 127)
146                                 else:
147                                         glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
148                                 glBegin(GL_QUADS)
149                                 glVertex3f(x1, y1, -0.01)
150                                 glVertex3f(x2, y1, -0.01)
151                                 glVertex3f(x2, y2, -0.01)
152                                 glVertex3f(x1, y2, -0.01)
153                                 glEnd()
154
155                 glEnable(GL_CULL_FACE)
156
157                 glColor4ub(5, 171, 231, 64)
158                 glBegin(GL_QUADS)
159                 glVertex3f(0, 0, machineSize.z)
160                 glVertex3f(0, machineSize.y, machineSize.z)
161                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
162                 glVertex3f(machineSize.x, 0, machineSize.z)
163                 glEnd()
164
165                 glColor4ub(5, 171, 231, 96)
166                 glBegin(GL_QUADS)
167                 glVertex3f(0, 0, 0)
168                 glVertex3f(0, 0, machineSize.z)
169                 glVertex3f(machineSize.x, 0, machineSize.z)
170                 glVertex3f(machineSize.x, 0, 0)
171
172                 glVertex3f(0, machineSize.y, machineSize.z)
173                 glVertex3f(0, machineSize.y, 0)
174                 glVertex3f(machineSize.x, machineSize.y, 0)
175                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
176                 glEnd()
177
178                 glColor4ub(5, 171, 231, 128)
179                 glBegin(GL_QUADS)
180                 glVertex3f(0, 0, machineSize.z)
181                 glVertex3f(0, 0, 0)
182                 glVertex3f(0, machineSize.y, 0)
183                 glVertex3f(0, machineSize.y, machineSize.z)
184
185                 glVertex3f(machineSize.x, 0, 0)
186                 glVertex3f(machineSize.x, 0, machineSize.z)
187                 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
188                 glVertex3f(machineSize.x, machineSize.y, 0)
189                 glEnd()
190
191                 glDisable(GL_BLEND)
192
193         glPushMatrix()
194         glTranslate(5, 5, 2)
195         glLineWidth(2)
196         glColor3f(0.5, 0, 0)
197         glBegin(GL_LINES)
198         glVertex3f(0, 0, 0)
199         glVertex3f(20, 0, 0)
200         glEnd()
201         glColor3f(0, 0.5, 0)
202         glBegin(GL_LINES)
203         glVertex3f(0, 0, 0)
204         glVertex3f(0, 20, 0)
205         glEnd()
206         glColor3f(0, 0, 0.5)
207         glBegin(GL_LINES)
208         glVertex3f(0, 0, 0)
209         glVertex3f(0, 0, 20)
210         glEnd()
211
212         glDisable(GL_DEPTH_TEST)
213         #X
214         glColor3f(1, 0, 0)
215         glPushMatrix()
216         glTranslate(20, 0, 0)
217         noZ = ResetMatrixRotationAndScale()
218         glDrawStringCenter("X")
219         glPopMatrix()
220
221         #Y
222         glColor3f(0, 1, 0)
223         glPushMatrix()
224         glTranslate(0, 20, 0)
225         glDrawStringCenter("Y")
226         glPopMatrix()
227
228         #Z
229         if not noZ:
230                 glColor3f(0, 0, 1)
231                 glPushMatrix()
232                 glTranslate(0, 0, 20)
233                 glDrawStringCenter("Z")
234                 glPopMatrix()
235
236         glPopMatrix()
237         glEnable(GL_DEPTH_TEST)
238
239 def glDrawStringCenter(s):
240         glRasterPos2f(0, 0)
241         width = 0
242         for c in s:
243                 width += glutBitmapWidth(GLUT_BITMAP_HELVETICA_18, ord(c))
244         glBitmap(0,0,0,0, -width/2, 0, None)
245         for c in s:
246                 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(c))
247
248 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
249         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
250         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
251         finalMatrix = npModelMatrix * npProjMatrix
252         finalMatrix = numpy.linalg.inv(finalMatrix)
253
254         viewport = map(float, viewport)
255         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))
256         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
257         ret = list(vector)[0:3] / vector[3]
258         return ret
259
260 def ResetMatrixRotationAndScale():
261         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
262         noZ = False
263         if matrix[3][2] > 0:
264                 return False
265         scale2D = matrix[0][0]
266         matrix[0][0] = 1.0
267         matrix[1][0] = 0.0
268         matrix[2][0] = 0.0
269         matrix[0][1] = 0.0
270         matrix[1][1] = 1.0
271         matrix[2][1] = 0.0
272         matrix[0][2] = 0.0
273         matrix[1][2] = 0.0
274         matrix[2][2] = 1.0
275
276         if matrix[3][2] != 0.0:
277                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
278                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
279                 matrix[3][2] = -100
280         else:
281                 matrix[0][0] = scale2D
282                 matrix[1][1] = scale2D
283                 matrix[2][2] = scale2D
284                 matrix[3][2] = -100
285                 noZ = True
286
287         glLoadMatrixf(matrix)
288         return noZ
289
290
291 def DrawBox(vMin, vMax):
292         glBegin(GL_LINE_LOOP)
293         glVertex3f(vMin[0], vMin[1], vMin[2])
294         glVertex3f(vMax[0], vMin[1], vMin[2])
295         glVertex3f(vMax[0], vMax[1], vMin[2])
296         glVertex3f(vMin[0], vMax[1], vMin[2])
297         glEnd()
298
299         glBegin(GL_LINE_LOOP)
300         glVertex3f(vMin[0], vMin[1], vMax[2])
301         glVertex3f(vMax[0], vMin[1], vMax[2])
302         glVertex3f(vMax[0], vMax[1], vMax[2])
303         glVertex3f(vMin[0], vMax[1], vMax[2])
304         glEnd()
305         glBegin(GL_LINES)
306         glVertex3f(vMin[0], vMin[1], vMin[2])
307         glVertex3f(vMin[0], vMin[1], vMax[2])
308         glVertex3f(vMax[0], vMin[1], vMin[2])
309         glVertex3f(vMax[0], vMin[1], vMax[2])
310         glVertex3f(vMax[0], vMax[1], vMin[2])
311         glVertex3f(vMax[0], vMax[1], vMax[2])
312         glVertex3f(vMin[0], vMax[1], vMin[2])
313         glVertex3f(vMin[0], vMax[1], vMax[2])
314         glEnd()
315
316
317 def DrawMeshOutline(mesh):
318         glEnable(GL_CULL_FACE)
319         glEnableClientState(GL_VERTEX_ARRAY);
320         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
321
322         glCullFace(GL_FRONT)
323         glLineWidth(3)
324         glPolygonMode(GL_BACK, GL_LINE)
325         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
326         glPolygonMode(GL_BACK, GL_FILL)
327         glCullFace(GL_BACK)
328
329         glDisableClientState(GL_VERTEX_ARRAY)
330
331
332 def DrawMesh(mesh):
333         glEnable(GL_CULL_FACE)
334         glEnableClientState(GL_VERTEX_ARRAY);
335         glEnableClientState(GL_NORMAL_ARRAY);
336         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
337         glNormalPointer(GL_FLOAT, 0, mesh.normal)
338
339         #Odd, drawing in batchs is a LOT faster then drawing it all at once.
340         batchSize = 999    #Warning, batchSize needs to be dividable by 3
341         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
342         extraCount = mesh.vertexCount - extraStartPos
343
344         glCullFace(GL_BACK)
345         for i in xrange(0, int(mesh.vertexCount / batchSize)):
346                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
347         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
348
349         glCullFace(GL_FRONT)
350         glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
351         for i in xrange(0, int(mesh.vertexCount / batchSize)):
352                 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
353         extraStartPos = int(mesh.vertexCount / batchSize) * batchSize
354         extraCount = mesh.vertexCount - extraStartPos
355         glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
356         glCullFace(GL_BACK)
357
358         glDisableClientState(GL_VERTEX_ARRAY)
359         glDisableClientState(GL_NORMAL_ARRAY);
360
361
362 def DrawMeshSteep(mesh, angle):
363         cosAngle = math.sin(angle / 180.0 * math.pi)
364         glDisable(GL_LIGHTING)
365         glDepthFunc(GL_EQUAL)
366         for i in xrange(0, int(mesh.vertexCount), 3):
367                 if mesh.normal[i][2] < -0.999999:
368                         if mesh.vertexes[i + 0][2] > 0.01:
369                                 glColor3f(0.5, 0, 0)
370                                 glBegin(GL_TRIANGLES)
371                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
372                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
373                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
374                                 glEnd()
375                 elif mesh.normal[i][2] < -cosAngle:
376                         glColor3f(-mesh.normal[i][2], 0, 0)
377                         glBegin(GL_TRIANGLES)
378                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
379                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
380                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
381                         glEnd()
382                 elif mesh.normal[i][2] > 0.999999:
383                         if mesh.vertexes[i + 0][2] > 0.01:
384                                 glColor3f(0.5, 0, 0)
385                                 glBegin(GL_TRIANGLES)
386                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
387                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
388                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
389                                 glEnd()
390                 elif mesh.normal[i][2] > cosAngle:
391                         glColor3f(mesh.normal[i][2], 0, 0)
392                         glBegin(GL_TRIANGLES)
393                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
394                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
395                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
396                         glEnd()
397         glDepthFunc(GL_LESS)
398
399
400 def DrawGCodeLayer(layer):
401         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
402         filamentArea = math.pi * filamentRadius * filamentRadius
403         lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
404
405         fillCycle = 0
406         fillColorCycle = [[0.5, 0.5, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5]]
407         moveColor = [0, 0, 1]
408         retractColor = [1, 0, 0.5]
409         supportColor = [0, 1, 1]
410         extrudeColor = [1, 0, 0]
411         innerWallColor = [0, 1, 0]
412         skirtColor = [0, 0.5, 0.5]
413         prevPathWasRetract = False
414
415         glDisable(GL_CULL_FACE)
416         for path in layer:
417                 if path.type == 'move':
418                         if prevPathWasRetract:
419                                 c = retractColor
420                         else:
421                                 c = moveColor
422                 zOffset = 0.01
423                 if path.type == 'extrude':
424                         if path.pathType == 'FILL':
425                                 c = fillColorCycle[fillCycle]
426                                 fillCycle = (fillCycle + 1) % len(fillColorCycle)
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 = [0, 1, 1]
438                 if path.type == 'extrude':
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                                 glColor3fv(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                                         glColor3fv(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                         glColor3fv(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)