1 from __future__ import absolute_import
8 OpenGL.ERROR_CHECKING = False
9 from OpenGL.GLU import *
10 from OpenGL.GL import *
12 from Cura.util import profile
13 from Cura.util import meshLoader
14 from Cura.util import objectScene
15 from Cura.util import resources
16 from Cura.gui.util import opengl
17 from Cura.gui.util import openglGui
20 def __init__(self, start, end, runTime):
23 self._startTime = time.time()
24 self._runTime = runTime
27 return time.time() > self._startTime + self._runTime
29 def getPosition(self):
32 f = (time.time() - self._startTime) / self._runTime
35 #f = 6*tc*ts + -15*ts*ts + 10*tc
37 return self._start + (self._end - self._start) * f
39 class SceneView(openglGui.glGuiPanel):
40 def __init__(self, parent):
41 super(SceneView, self).__init__(parent)
46 self._scene = objectScene.Scene()
47 self._objectShader = None
49 self._selectedObj = None
50 self._objColors = [None,None,None,None]
53 self._mouseState = None
54 self._viewTarget = numpy.array([0,0,0], numpy.float32)
57 self._platformMesh = meshLoader.loadMeshes(resources.getPathForMesh('ultimaker_platform.stl'))[0]
58 self._platformMesh._drawOffset = numpy.array([0,0,0.5], numpy.float32)
59 wx.EVT_IDLE(self, self.OnIdle)
60 self.updateProfileToControls()
63 if self._animView is not None or self._animZoom is not None:
66 for obj in self._scene.objects():
67 if obj._loadAnim is not None:
71 def loadScene(self, fileList):
72 for filename in fileList:
73 for obj in meshLoader.loadMeshes(filename):
74 obj._loadAnim = anim(1, 0, 2)
76 self._selectObject(obj)
78 def _deleteObject(self, obj):
79 if obj == self._selectedObj:
80 self._selectedObj = None
81 if obj == self._focusObj:
83 self._scene.remove(obj)
84 for m in obj._meshList:
86 self.glReleaseList.append(m.vbo)
88 def _selectObject(self, obj):
89 self._selectedObj = obj
90 newViewPos = numpy.array([self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], self._selectedObj.getMaximum()[2] / 2])
91 self._animView = anim(self._viewTarget.copy(), newViewPos, 0.5)
92 newZoom = self._selectedObj.getBoundaryCircle() * 6
93 self._animZoom = anim(self._zoom, newZoom, 0.5)
95 def updateProfileToControls(self):
96 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
97 self._objColors[0] = profile.getPreferenceColour('model_colour')
98 self._objColors[1] = profile.getPreferenceColour('model_colour2')
99 self._objColors[2] = profile.getPreferenceColour('model_colour3')
100 self._objColors[3] = profile.getPreferenceColour('model_colour4')
101 self._scene.setMachineSize(self._machineSize)
103 def OnKeyChar(self, keyCode):
104 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
105 if self._selectedObj is not None:
106 self._deleteObject(self._selectedObj)
109 if keyCode == wx.WXK_F3:
110 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
112 def ShaderUpdate(self, v, f):
113 s = opengl.GLShader(v, f)
115 self._objectLoadShader.release()
116 self._objectLoadShader = s
119 def OnMouseDown(self,e):
120 self._mouseX = e.GetX()
121 self._mouseY = e.GetY()
122 self._mouseClick3DPos = self._mouse3Dpos
124 self._mouseState = 'doubleClick'
126 self._mouseState = 'dragOrClick'
127 if self._mouseState == 'dragOrClick':
129 if self._focusObj is not None:
130 self._selectedObj = self._focusObj
133 def OnMouseUp(self, e):
134 if self._mouseState == 'dragOrClick':
136 if self._focusObj is not None:
137 self._selectObject(self._focusObj)
139 self._selectedObj = None
141 if self._mouseState == 'drag' and self._selectedObj is not None:
142 self._scene.pushFree()
144 self._mouseState = None
146 def OnMouseMotion(self,e):
147 if e.Dragging() and self._mouseState is not None:
148 self._mouseState = 'drag'
149 if not e.LeftIsDown() and e.RightIsDown():
150 self._yaw += e.GetX() - self._mouseX
151 self._pitch -= e.GetY() - self._mouseY
152 if self._pitch > 170:
156 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
157 self._zoom += e.GetY() - self._mouseY
160 if self._zoom > numpy.max(self._machineSize) * 3:
161 self._zoom = numpy.max(self._machineSize) * 3
162 elif e.LeftIsDown() and self._selectedObj is not None:
163 z = max(0, self._mouseClick3DPos[2])
164 p0 = opengl.unproject(self._mouseX, self.viewport[1] + self.viewport[3] - self._mouseY, 0, self.modelMatrix, self.projMatrix, self.viewport)
165 p1 = opengl.unproject(self._mouseX, self.viewport[1] + self.viewport[3] - self._mouseY, 1, self.modelMatrix, self.projMatrix, self.viewport)
166 p2 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 0, self.modelMatrix, self.projMatrix, self.viewport)
167 p3 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 1, self.modelMatrix, self.projMatrix, self.viewport)
172 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
173 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
174 diff = cursorZ1 - cursorZ0
175 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
177 self._mouseX = e.GetX()
178 self._mouseY = e.GetY()
180 def _init3DView(self):
181 # set viewing projection
182 size = self.GetSize()
183 glViewport(0, 0, size.GetWidth(), size.GetHeight())
186 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
188 glDisable(GL_RESCALE_NORMAL)
189 glDisable(GL_LIGHTING)
191 glEnable(GL_DEPTH_TEST)
192 glDisable(GL_CULL_FACE)
194 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
196 glClearColor(0.8, 0.8, 0.8, 1.0)
200 glMatrixMode(GL_PROJECTION)
202 aspect = float(size.GetWidth()) / float(size.GetHeight())
203 gluPerspective(45.0, aspect, 1.0, 1000.0)
205 glMatrixMode(GL_MODELVIEW)
207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
210 if self._animView is not None:
211 self._viewTarget = self._animView.getPosition()
212 if self._animView.isDone():
213 self._animView = None
214 if self._animZoom is not None:
215 self._zoom = self._animZoom.getPosition()
216 if self._animZoom.isDone():
217 self._animZoom = None
218 if self._objectShader is None:
219 self._objectShader = opengl.GLShader("""
220 uniform float cameraDistance;
221 varying float light_amount;
225 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
226 gl_FrontColor = gl_Color;
228 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
229 light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
233 uniform float cameraDistance;
234 varying float light_amount;
238 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
241 self._objectLoadShader = opengl.GLShader("""
242 uniform float cameraDistance;
243 uniform float intensity;
245 varying float light_amount;
249 vec4 tmp = gl_Vertex;
250 tmp.x += sin(tmp.z/5+intensity*30) * scale * intensity;
251 tmp.y += sin(tmp.z/3+intensity*40) * scale * intensity;
252 gl_Position = gl_ModelViewProjectionMatrix * tmp;
253 gl_FrontColor = gl_Color;
255 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
256 light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
260 uniform float cameraDistance;
261 uniform float intensity;
262 varying float light_amount;
266 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1-intensity);
270 glTranslate(0,0,-self._zoom)
271 glRotate(-self._pitch, 1,0,0)
272 glRotate(self._yaw, 0,0,1)
273 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
275 self.viewport = glGetIntegerv(GL_VIEWPORT)
276 self.modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
277 self.projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
279 glClearColor(1,1,1,1)
280 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
282 for n in xrange(0, len(self._scene.objects())):
283 obj = self._scene.objects()[n]
284 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
285 self._renderObject(obj)
287 if self._mouseX > -1:
288 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
289 if n < len(self._scene.objects()):
290 self._focusObj = self._scene.objects()[n]
292 self._focusObj = None
293 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
294 self._mouse3Dpos = opengl.unproject(self._mouseX, self.viewport[1] + self.viewport[3] - self._mouseY, f, self.modelMatrix, self.projMatrix, self.viewport)
297 glTranslate(0,0,-self._zoom)
298 glRotate(-self._pitch, 1,0,0)
299 glRotate(self._yaw, 0,0,1)
300 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
302 glStencilFunc(GL_ALWAYS, 1, 1)
303 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
304 self._objectShader.bind()
305 self._objectShader.setUniform('cameraDistance', self._zoom)
306 for obj in self._scene.objects():
307 if obj._loadAnim is not None:
308 if obj._loadAnim.isDone():
312 col = self._objColors[0]
313 if not self._scene.checkPlatform(obj):
314 col = [0.5,0.5,0.5,0.8]
315 glDisable(GL_STENCIL_TEST)
316 if self._selectedObj == obj:
317 col = map(lambda n: n * 1.5, col)
318 glEnable(GL_STENCIL_TEST)
319 elif self._focusObj == obj:
320 col = map(lambda n: n * 1.2, col)
321 elif self._focusObj is not None or self._selectedObj is not None:
322 col = map(lambda n: n * 0.8, col)
323 glColor4f(col[0], col[1], col[2], col[3])
324 self._renderObject(obj)
325 self._objectShader.unbind()
327 glDisable(GL_STENCIL_TEST)
329 self._objectLoadShader.bind()
330 self._objectLoadShader.setUniform('cameraDistance', self._zoom)
331 glColor4f(0.2, 0.6, 1.0, 1.0)
332 for obj in self._scene.objects():
333 if obj._loadAnim is None:
335 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
336 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 20)
337 self._renderObject(obj)
338 self._objectLoadShader.unbind()
343 #Draw the outline of the selected object, on top of everything else except the GUI.
344 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
345 glDisable(GL_DEPTH_TEST)
346 glEnable(GL_CULL_FACE)
347 glEnable(GL_STENCIL_TEST)
348 glStencilFunc(GL_EQUAL, 0, 255)
349 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
352 self._renderObject(self._selectedObj)
353 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
354 glDisable(GL_STENCIL_TEST)
355 glDisable(GL_CULL_FACE)
356 glEnable(GL_DEPTH_TEST)
358 def _renderObject(self, obj):
360 glTranslate(obj.getPosition()[0], obj.getPosition()[1], 0)
361 offset = obj.getDrawOffset()
362 glTranslate(-offset[0], -offset[1], -offset[2])
363 for m in obj._meshList:
365 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
369 def _drawMachine(self):
370 glEnable(GL_CULL_FACE)
373 if profile.getPreference('machine_type') == 'ultimaker':
375 self._objectShader.bind()
376 self._objectShader.setUniform('cameraDistance', self._zoom)
377 self._renderObject(self._platformMesh)
378 self._objectShader.unbind()
380 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
381 v0 = [ size[0] / 2, size[1] / 2, size[2]]
382 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
383 v2 = [-size[0] / 2, size[1] / 2, size[2]]
384 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
385 v4 = [ size[0] / 2, size[1] / 2, 0]
386 v5 = [ size[0] / 2,-size[1] / 2, 0]
387 v6 = [-size[0] / 2, size[1] / 2, 0]
388 v7 = [-size[0] / 2,-size[1] / 2, 0]
390 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
391 glEnableClientState(GL_VERTEX_ARRAY)
392 glVertexPointer(3, GL_FLOAT, 3*4, vList)
394 glColor4ub(5, 171, 231, 64)
395 glDrawArrays(GL_QUADS, 0, 4)
396 glColor4ub(5, 171, 231, 96)
397 glDrawArrays(GL_QUADS, 4, 8)
398 glColor4ub(5, 171, 231, 128)
399 glDrawArrays(GL_QUADS, 12, 8)
401 sx = self._machineSize[0]
402 sy = self._machineSize[1]
403 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
404 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
409 x1 = max(min(x1, sx/2), -sx/2)
410 y1 = max(min(y1, sy/2), -sy/2)
411 x2 = max(min(x2, sx/2), -sx/2)
412 y2 = max(min(y2, sy/2), -sy/2)
413 if (x & 1) == (y & 1):
414 glColor4ub(5, 171, 231, 127)
416 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
418 glVertex3f(x1, y1, -0.02)
419 glVertex3f(x2, y1, -0.02)
420 glVertex3f(x2, y2, -0.02)
421 glVertex3f(x1, y2, -0.02)
424 glDisableClientState(GL_VERTEX_ARRAY)
426 glDisable(GL_CULL_FACE)
428 class shaderEditor(wx.Dialog):
429 def __init__(self, parent, callback, v, f):
430 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
431 self._callback = callback
432 s = wx.BoxSizer(wx.VERTICAL)
434 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
435 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
436 s.Add(self._vertex, 1, flag=wx.EXPAND)
437 s.Add(self._fragment, 1, flag=wx.EXPAND)
439 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
440 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
442 self.SetPosition(self.GetParent().GetPosition())
443 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
447 self._callback(self._vertex.GetValue(), self._fragment.GetValue())