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)
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)
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
327 for i in xrange(0, int(mesh.vertexCount / batchSize)):
328 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
329 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
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)
340 glDisableClientState(GL_VERTEX_ARRAY)
341 glDisableClientState(GL_NORMAL_ARRAY)
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:
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])
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])
365 elif normals[i][2] > 0.999999:
366 if mesh.vertexes[i + 0][2] > 0.01:
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])
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])
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
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
398 glDisable(GL_CULL_FACE)
400 if path.type == 'move':
401 if prevPathWasRetract:
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':
413 elif path.pathType == 'SUPPORT':
415 elif path.pathType == 'SKIRT':
419 if path.type == 'retract':
421 if path.type == 'extrude':
424 for i in xrange(0, len(path.list) - 1):
426 v1 = path.list[i + 1]
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
434 drawLength += (v0 - v1).vsize()
435 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
438 vv2 = v0 + normal * lineWidth
439 vv3 = v1 + normal * lineWidth
440 vv0 = v0 - normal * lineWidth
441 vv1 = v1 - normal * lineWidth
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)
450 if prevNormal is not None:
451 n = (normal + prevNormal)
453 vv4 = v0 + n * lineWidth
454 vv5 = v0 - n * lineWidth
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)
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)
472 glBegin(GL_LINE_STRIP)
475 glVertex3f(v.x, v.y, v.z)
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)