2 from __future__ import absolute_import
9 from Cura.util import meshLoader
10 from Cura.util import util3d
11 from Cura.util import profile
12 from Cura.util.resources import getPathForMesh, getPathForImage
16 OpenGL.ERROR_CHECKING = False
17 from OpenGL.GLUT import *
18 from OpenGL.GLU import *
19 from OpenGL.GL import *
20 from OpenGL.GL import shaders
25 class GLShader(object):
26 def __init__(self, owner, vertexProgram, fragmentProgram):
29 self._vertexProgram = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
30 self._fragmentProgram = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
31 self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
32 except RuntimeError, e:
38 if self._program is not None:
39 shaders.glUseProgram(self._program)
42 shaders.glUseProgram(0)
45 if self._program != None:
46 shaders.glDeleteShader(self._vertexProgram)
47 shaders.glDeleteShader(self._fragmentProgram)
48 glDeleteProgram(self._program)
51 def setUniform(self, name, value):
52 if self._program is not None:
53 glUniform1f(glGetUniformLocation(self._program, name), value)
56 if self._program is not None and bool(glDeleteProgram):
57 print "OpenGL shader was not properly cleaned, trying to clean it up now."
58 self._owner.glReleaseList.append(self)
61 def __init__(self, owner, vertexArray, normalArray):
62 self._buffer = glGenBuffers(1)
63 self._size = len(vertexArray)
65 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
66 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
67 glBindBuffer(GL_ARRAY_BUFFER, 0)
70 glEnableClientState(GL_VERTEX_ARRAY)
71 glEnableClientState(GL_NORMAL_ARRAY)
72 glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
73 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
74 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
76 batchSize = 999 #Warning, batchSize needs to be dividable by 3
77 extraStartPos = int(self._size / batchSize) * batchSize
78 extraCount = self._size - extraStartPos
80 for i in xrange(0, int(self._size / batchSize)):
81 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
82 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
83 glBindBuffer(GL_ARRAY_BUFFER, 0)
84 glDisableClientState(GL_VERTEX_ARRAY)
85 glDisableClientState(GL_NORMAL_ARRAY)
88 if self._buffer is not None:
89 glDeleteBuffers(self._buffer, 1)
93 if self._buffer is not None and bool(glDeleteBuffers):
94 self._owner.glReleaseList.append(self)
96 def DrawMachine(machineSize):
97 glDisable(GL_LIGHTING)
98 glDisable(GL_CULL_FACE)
100 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
104 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
105 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
110 x1 = max(min(x1, sx), 0)
111 y1 = max(min(y1, sy), 0)
112 x2 = max(min(x2, sx), 0)
113 y2 = max(min(y2, sy), 0)
114 if (x & 1) == (y & 1):
115 glColor4ub(5, 171, 231, 127)
117 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
119 glVertex3f(x1, y1, -0.02)
120 glVertex3f(x2, y1, -0.02)
121 glVertex3f(x2, y2, -0.02)
122 glVertex3f(x1, y2, -0.02)
125 glEnable(GL_CULL_FACE)
127 if profile.getPreference('machine_type') == 'ultimaker':
129 glEnable(GL_LIGHTING)
130 glTranslate(100, 200, -1)
131 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 0.8, 0.8])
132 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5])
134 glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR)
137 if platformMesh is None:
139 platformMesh = meshLoader.loadMesh(getPathForMesh('ultimaker_platform.stl'))
144 DrawMesh(platformMesh)
146 glDisable(GL_LIGHTING)
147 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
149 glColor4ub(5, 171, 231, 64)
151 glVertex3f(0, 0, machineSize.z)
152 glVertex3f(0, machineSize.y, machineSize.z)
153 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
154 glVertex3f(machineSize.x, 0, machineSize.z)
157 glColor4ub(5, 171, 231, 96)
160 glVertex3f(0, 0, machineSize.z)
161 glVertex3f(machineSize.x, 0, machineSize.z)
162 glVertex3f(machineSize.x, 0, 0)
164 glVertex3f(0, machineSize.y, machineSize.z)
165 glVertex3f(0, machineSize.y, 0)
166 glVertex3f(machineSize.x, machineSize.y, 0)
167 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
170 glColor4ub(5, 171, 231, 128)
172 glVertex3f(0, 0, machineSize.z)
174 glVertex3f(0, machineSize.y, 0)
175 glVertex3f(0, machineSize.y, machineSize.z)
177 glVertex3f(machineSize.x, 0, 0)
178 glVertex3f(machineSize.x, 0, machineSize.z)
179 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
180 glVertex3f(machineSize.x, machineSize.y, 0)
185 #Draw the X/Y/Z indicator
205 glDisable(GL_DEPTH_TEST)
209 glTranslate(20, 0, 0)
210 noZ = ResetMatrixRotationAndScale()
211 glDrawStringCenter("X")
217 glTranslate(0, 20, 0)
218 glDrawStringCenter("Y")
225 glTranslate(0, 0, 20)
226 glDrawStringCenter("Z")
230 glEnable(GL_DEPTH_TEST)
232 def glDrawStringCenter(s):
234 glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
236 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
238 def glGetStringSize(s):
241 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
245 def glDrawStringLeft(s):
248 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
250 def glDrawStringRight(s):
252 glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
254 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
256 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
257 tx = float(texID % 4) / 4
258 ty = float(int(texID / 4)) / 8
268 glTranslatef(x, y, 0)
269 glEnable(GL_TEXTURE_2D)
271 glTexCoord2f(tx+tsx, ty)
275 glTexCoord2f(tx, ty+tsy)
277 glTexCoord2f(tx+tsx, ty+tsy)
282 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
283 npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
284 npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
285 finalMatrix = npModelMatrix * npProjMatrix
286 finalMatrix = numpy.linalg.inv(finalMatrix)
288 viewport = map(float, viewport)
289 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))
290 vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
291 ret = list(vector)[0:3] / vector[3]
294 def convert3x3MatrixTo4x4(matrix):
295 return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
297 def loadGLTexture(filename):
298 tex = glGenTextures(1)
299 glBindTexture(GL_TEXTURE_2D, tex)
300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
302 img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
303 rgbData = img.GetData()
304 alphaData = img.GetAlphaData()
305 if alphaData is not None:
307 for i in xrange(0, len(alphaData)):
308 data += rgbData[i*3:i*3+3] + alphaData[i]
309 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
311 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
314 def ResetMatrixRotationAndScale():
315 matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
319 scale2D = matrix[0][0]
330 if matrix[3][2] != 0.0:
331 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
332 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
335 matrix[0][0] = scale2D
336 matrix[1][1] = scale2D
337 matrix[2][2] = scale2D
341 glLoadMatrixf(matrix)
345 def DrawBox(vMin, vMax):
346 glBegin(GL_LINE_LOOP)
347 glVertex3f(vMin[0], vMin[1], vMin[2])
348 glVertex3f(vMax[0], vMin[1], vMin[2])
349 glVertex3f(vMax[0], vMax[1], vMin[2])
350 glVertex3f(vMin[0], vMax[1], vMin[2])
353 glBegin(GL_LINE_LOOP)
354 glVertex3f(vMin[0], vMin[1], vMax[2])
355 glVertex3f(vMax[0], vMin[1], vMax[2])
356 glVertex3f(vMax[0], vMax[1], vMax[2])
357 glVertex3f(vMin[0], vMax[1], vMax[2])
360 glVertex3f(vMin[0], vMin[1], vMin[2])
361 glVertex3f(vMin[0], vMin[1], vMax[2])
362 glVertex3f(vMax[0], vMin[1], vMin[2])
363 glVertex3f(vMax[0], vMin[1], vMax[2])
364 glVertex3f(vMax[0], vMax[1], vMin[2])
365 glVertex3f(vMax[0], vMax[1], vMax[2])
366 glVertex3f(vMin[0], vMax[1], vMin[2])
367 glVertex3f(vMin[0], vMax[1], vMax[2])
371 def DrawMeshOutline(mesh):
372 glEnable(GL_CULL_FACE)
373 glEnableClientState(GL_VERTEX_ARRAY);
374 glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
378 glPolygonMode(GL_BACK, GL_LINE)
379 glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
380 glPolygonMode(GL_BACK, GL_FILL)
383 glDisableClientState(GL_VERTEX_ARRAY)
386 def DrawMesh(mesh, insideOut = False):
387 glEnable(GL_CULL_FACE)
388 glEnableClientState(GL_VERTEX_ARRAY)
389 glEnableClientState(GL_NORMAL_ARRAY)
390 for m in mesh._meshList:
391 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
393 glNormalPointer(GL_FLOAT, 0, m.invNormal)
395 glNormalPointer(GL_FLOAT, 0, m.normal)
397 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
398 batchSize = 999 #Warning, batchSize needs to be dividable by 3
399 extraStartPos = int(m.vertexCount / batchSize) * batchSize
400 extraCount = m.vertexCount - extraStartPos
403 for i in xrange(0, int(m.vertexCount / batchSize)):
404 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
405 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
409 glNormalPointer(GL_FLOAT, 0, m.normal)
411 glNormalPointer(GL_FLOAT, 0, m.invNormal)
412 for i in xrange(0, int(m.vertexCount / batchSize)):
413 glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
414 extraStartPos = int(m.vertexCount / batchSize) * batchSize
415 extraCount = m.vertexCount - extraStartPos
416 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
419 glDisableClientState(GL_VERTEX_ARRAY)
420 glDisableClientState(GL_NORMAL_ARRAY)
423 def DrawMeshSteep(mesh, matrix, angle):
424 cosAngle = math.sin(angle / 180.0 * math.pi)
425 glDisable(GL_LIGHTING)
426 glDepthFunc(GL_EQUAL)
427 normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
428 for i in xrange(0, int(mesh.vertexCount), 3):
429 if normals[i][2] < -0.999999:
430 if mesh.vertexes[i + 0][2] > 0.01:
432 glBegin(GL_TRIANGLES)
433 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
434 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
435 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
437 elif normals[i][2] < -cosAngle:
438 glColor3f(-normals[i][2], 0, 0)
439 glBegin(GL_TRIANGLES)
440 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
441 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
442 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
444 elif normals[i][2] > 0.999999:
445 if mesh.vertexes[i + 0][2] > 0.01:
447 glBegin(GL_TRIANGLES)
448 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
449 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
450 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
452 elif normals[i][2] > cosAngle:
453 glColor3f(normals[i][2], 0, 0)
454 glBegin(GL_TRIANGLES)
455 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
456 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
457 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
462 def DrawGCodeLayer(layer, drawQuick = True):
463 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
464 filamentArea = math.pi * filamentRadius * filamentRadius
465 lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
468 fillColorCycle = [[0.5, 0.5, 0.0, 1], [0.0, 0.5, 0.5, 1], [0.5, 0.0, 0.5, 1]]
469 moveColor = [0, 0, 1, 0.5]
470 retractColor = [1, 0, 0.5, 0.5]
471 supportColor = [0, 1, 1, 1]
472 extrudeColor = [[1, 0, 0, 1], [0, 1, 1, 1], [1, 1, 0, 1], [1, 0, 1, 1]]
473 innerWallColor = [0, 1, 0, 1]
474 skirtColor = [0, 0.5, 0.5, 1]
475 prevPathWasRetract = False
477 glDisable(GL_CULL_FACE)
479 if path.type == 'move':
480 if prevPathWasRetract:
487 if path.type == 'extrude':
488 if path.pathType == 'FILL':
489 c = fillColorCycle[fillCycle]
490 fillCycle = (fillCycle + 1) % len(fillColorCycle)
493 elif path.pathType == 'WALL-INNER':
496 elif path.pathType == 'SUPPORT':
498 elif path.pathType == 'SKIRT':
501 c = extrudeColor[path.extruder]
502 if path.type == 'retract':
504 if path.type == 'extrude' and not drawQuick:
507 for i in xrange(0, len(path.list) - 1):
509 v1 = path.list[i + 1]
511 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
512 dist = (v0 - v1).vsize()
513 if dist > 0 and path.layerThickness > 0:
514 extrusionMMperDist = (v1.e - v0.e) / dist
515 lineWidth = extrusionMMperDist * filamentArea / path.layerThickness / 2 * v1.extrudeAmountMultiply
517 drawLength += (v0 - v1).vsize()
518 normal = (v0 - v1).cross(util3d.Vector3(0, 0, 1))
521 vv2 = v0 + normal * lineWidth
522 vv3 = v1 + normal * lineWidth
523 vv0 = v0 - normal * lineWidth
524 vv1 = v1 - normal * lineWidth
528 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
529 glVertex3f(vv1.x, vv1.y, vv1.z - zOffset)
530 glVertex3f(vv3.x, vv3.y, vv3.z - zOffset)
531 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
533 if prevNormal is not None:
534 n = (normal + prevNormal)
536 vv4 = v0 + n * lineWidth
537 vv5 = v0 - n * lineWidth
540 glVertex3f(vv2.x, vv2.y, vv2.z - zOffset)
541 glVertex3f(vv4.x, vv4.y, vv4.z - zOffset)
542 glVertex3f(prevVv3.x, prevVv3.y, prevVv3.z - zOffset)
543 glVertex3f(v0.x, v0.y, v0.z - zOffset)
545 glVertex3f(vv0.x, vv0.y, vv0.z - zOffset)
546 glVertex3f(vv5.x, vv5.y, vv5.z - zOffset)
547 glVertex3f(prevVv1.x, prevVv1.y, prevVv1.z - zOffset)
548 glVertex3f(v0.x, v0.y, v0.z - zOffset)
555 glBegin(GL_LINE_STRIP)
558 glVertex3f(v.x, v.y, v.z)
560 if not path.type == 'move':
561 prevPathWasRetract = False
562 if path.type == 'retract' and path.list[0].almostEqual(path.list[-1]):
563 prevPathWasRetract = True
564 glEnable(GL_CULL_FACE)