2 from __future__ import absolute_import
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
15 OpenGL.ERROR_CHECKING = False
16 from OpenGL.GLUT import *
17 from OpenGL.GLU import *
18 from OpenGL.GL import *
21 def InitGL(window, view3D, zoom):
22 # set viewing projection
23 glMatrixMode(GL_MODELVIEW)
25 size = window.GetSize()
26 glViewport(0, 0, size.GetWidth(), size.GetHeight())
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])
31 glEnable(GL_RESCALE_NORMAL)
34 glEnable(GL_DEPTH_TEST)
35 glEnable(GL_CULL_FACE)
38 glClearColor(1.0, 1.0, 1.0, 1.0)
42 glMatrixMode(GL_PROJECTION)
44 aspect = float(size.GetWidth()) / float(size.GetHeight())
46 gluPerspective(45.0, aspect, 1.0, 1000.0)
48 glOrtho(-aspect * (zoom), aspect * (zoom), -1.0 * (zoom), 1.0 * (zoom), -1000.0, 1000.0)
50 glMatrixMode(GL_MODELVIEW)
52 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
56 def DrawMachine(machineSize):
57 glDisable(GL_LIGHTING)
58 glDisable(GL_CULL_FACE)
60 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
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):
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)
77 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
79 glVertex3f(x1, y1, -0.02)
80 glVertex3f(x2, y1, -0.02)
81 glVertex3f(x2, y2, -0.02)
82 glVertex3f(x1, y2, -0.02)
85 glEnable(GL_CULL_FACE)
87 if profile.getPreference('machine_type') == 'ultimaker':
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])
94 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
97 if platformMesh is None:
99 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
104 DrawMesh(platformMesh)
106 glDisable(GL_LIGHTING)
107 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
109 glColor4ub(5, 171, 231, 64)
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)
117 glColor4ub(5, 171, 231, 96)
120 glVertex3f(0, 0, machineSize.z)
121 glVertex3f(machineSize.x, 0, machineSize.z)
122 glVertex3f(machineSize.x, 0, 0)
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)
130 glColor4ub(5, 171, 231, 128)
132 glVertex3f(0, 0, machineSize.z)
134 glVertex3f(0, machineSize.y, 0)
135 glVertex3f(0, machineSize.y, machineSize.z)
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)
145 #Draw the X/Y/Z indicator
165 glDisable(GL_DEPTH_TEST)
169 glTranslate(20, 0, 0)
170 noZ = ResetMatrixRotationAndScale()
171 glDrawStringCenter("X")
177 glTranslate(0, 20, 0)
178 glDrawStringCenter("Y")
185 glTranslate(0, 0, 20)
186 glDrawStringCenter("Z")
190 glEnable(GL_DEPTH_TEST)
192 def glDrawStringCenter(s):
194 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
196 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
198 def glGetStringSize(s):
201 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
205 def glDrawStringLeft(s):
208 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
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)
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]
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]
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:
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)
239 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
242 def ResetMatrixRotationAndScale():
243 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
247 scale2D = matrix[0][0]
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)
263 matrix[0][0] = scale2D
264 matrix[1][1] = scale2D
265 matrix[2][2] = scale2D
269 glLoadMatrixf(matrix)
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])
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])
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])
299 def DrawMeshOutline(mesh):
300 glEnable(GL_CULL_FACE)
301 glEnableClientState(GL_VERTEX_ARRAY);
302 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
306 glPolygonMode(GL_BACK, GL_LINE)
307 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
308 glPolygonMode(GL_BACK, GL_FILL)
311 glDisableClientState(GL_VERTEX_ARRAY)
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)
320 glNormalPointer(GL_FLOAT, 0, mesh.invNormal)
322 glNormalPointer(GL_FLOAT, 0, mesh.normal)
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
330 for i in xrange(0, int(mesh.vertexCount / batchSize)):
331 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
332 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
336 glNormalPointer(GL_FLOAT, 0, mesh.normal)
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)
346 glDisableClientState(GL_VERTEX_ARRAY)
347 glDisableClientState(GL_NORMAL_ARRAY)
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:
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])
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])
371 elif normals[i][2] > 0.999999:
372 if mesh.vertexes[i + 0][2] > 0.01:
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])
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])
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
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
404 glDisable(GL_CULL_FACE)
406 if path.type == 'move':
407 if prevPathWasRetract:
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':
419 elif path.pathType == 'SUPPORT':
421 elif path.pathType == 'SKIRT':
425 if path.type == 'retract':
427 if path.type == 'extrude':
430 for i in xrange(0, len(path.list) - 1):
432 v1 = path.list[i + 1]
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
440 drawLength += (v0 - v1).vsize()
441 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
444 vv2 = v0 + normal * lineWidth
445 vv3 = v1 + normal * lineWidth
446 vv0 = v0 - normal * lineWidth
447 vv1 = v1 - normal * lineWidth
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)
456 if prevNormal is not None:
457 n = (normal + prevNormal)
459 vv4 = v0 + n * lineWidth
460 vv5 = v0 - n * lineWidth
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)
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)
478 glBegin(GL_LINE_STRIP)
481 glVertex3f(v.x, v.y, v.z)
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)