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.gui.util import opengl
16 from Cura.gui.util import openglGui
19 def __init__(self, start, end, runTime):
22 self._startTime = time.time()
23 self._runTime = runTime
26 return time.time() > self._startTime + self._runTime
28 def getPosition(self):
31 f = (time.time() - self._startTime) / self._runTime
34 #f = 6*tc*ts + -15*ts*ts + 10*tc
36 return self._start + (self._end - self._start) * f
38 class SceneView(openglGui.glGuiPanel):
39 def __init__(self, parent):
40 super(SceneView, self).__init__(parent)
45 self._scene = objectScene.Scene()
46 self._objectShader = None
48 self._selectedObj = None
49 self._objColors = [None,None,None,None]
52 self._mouseState = None
53 self._viewTarget = numpy.array([0,0,0], numpy.float32);
56 wx.EVT_IDLE(self, self.OnIdle)
57 self.updateProfileToControls()
60 if self._animView is not None or self._animZoom is not None:
63 for obj in self._scene.objects():
64 if obj._loadAnim is not None:
68 def loadScene(self, fileList):
69 for filename in fileList:
70 for obj in meshLoader.loadMeshes(filename):
71 obj._loadAnim = anim(1, 0, 2)
74 def _deleteObject(self, obj):
75 if obj == self._selectedObj:
76 self._selectedObj = None
77 if obj == self._focusObj:
79 self._scene.remove(obj)
80 for m in obj._meshList:
82 self.glReleaseList.append(m.vbo)
84 def updateProfileToControls(self):
85 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
86 self._objColors[0] = profile.getPreferenceColour('model_colour')
87 self._objColors[1] = profile.getPreferenceColour('model_colour2')
88 self._objColors[2] = profile.getPreferenceColour('model_colour3')
89 self._objColors[3] = profile.getPreferenceColour('model_colour4')
91 def OnKeyChar(self, keyCode):
92 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
93 if self._selectedObj is not None:
94 self._deleteObject(self._selectedObj)
97 if keyCode == wx.WXK_F3:
98 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
100 def ShaderUpdate(self, v, f):
101 s = opengl.GLShader(v, f)
103 self._objectLoadShader.release()
104 self._objectLoadShader = s
107 def OnMouseDown(self,e):
108 self._mouseX = e.GetX()
109 self._mouseY = e.GetY()
111 self._mouseState = 'doubleClick'
113 self._mouseState = 'dragOrClick'
115 def OnMouseUp(self, e):
116 if self._mouseState == 'dragOrClick':
118 if self._focusObj is not None:
119 self._selectedObj = self._focusObj
120 newViewPos = numpy.array([self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], self._selectedObj.getMaximum()[2] / 2])
121 self._animView = anim(self._viewTarget.copy(), newViewPos, 0.5)
122 newZoom = self._selectedObj.getBoundaryCircle() * 6
123 self._animZoom = anim(self._zoom, newZoom, 0.5)
125 self._selectedObj = None
127 self._mouseState = None
129 def OnMouseMotion(self,e):
131 if not e.LeftIsDown() and e.RightIsDown():
132 self._mouseState = 'drag'
133 self._yaw += e.GetX() - self._mouseX
134 self._pitch -= e.GetY() - self._mouseY
135 if self._pitch > 170:
139 if (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
140 self._mouseState = 'drag'
141 self._zoom += e.GetY() - self._mouseY
144 if self._zoom > numpy.max(self._machineSize) * 3:
145 self._zoom = numpy.max(self._machineSize) * 3
146 self._mouseX = e.GetX()
147 self._mouseY = e.GetY()
149 def _init3DView(self):
150 # set viewing projection
151 size = self.GetSize()
152 glViewport(0, 0, size.GetWidth(), size.GetHeight())
155 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
157 glDisable(GL_RESCALE_NORMAL)
158 glDisable(GL_LIGHTING)
160 glEnable(GL_DEPTH_TEST)
161 glDisable(GL_CULL_FACE)
163 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
165 glClearColor(0.8, 0.8, 0.8, 1.0)
169 glMatrixMode(GL_PROJECTION)
171 aspect = float(size.GetWidth()) / float(size.GetHeight())
172 gluPerspective(45.0, aspect, 1.0, 1000.0)
174 glMatrixMode(GL_MODELVIEW)
176 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
179 if self._animView is not None:
180 self._viewTarget = self._animView.getPosition()
181 if self._animView.isDone():
182 self._animView = None
183 if self._animZoom is not None:
184 self._zoom = self._animZoom.getPosition()
185 if self._animZoom.isDone():
186 self._animZoom = None
187 if self._objectShader is None:
188 self._objectShader = opengl.GLShader("""
189 uniform float cameraDistance;
190 varying float light_amount;
194 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
195 gl_FrontColor = gl_Color;
197 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
198 light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
202 uniform float cameraDistance;
203 varying float light_amount;
207 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
210 self._objectLoadShader = opengl.GLShader("""
211 uniform float cameraDistance;
212 uniform float intensity;
213 varying float light_amount;
217 vec4 tmp = gl_Vertex;
218 tmp.x += sin(tmp.z/5+intensity*30) * 10 * intensity;
219 tmp.y += sin(tmp.z/3+intensity*40) * 10 * intensity;
220 gl_Position = gl_ModelViewProjectionMatrix * tmp;
221 gl_FrontColor = gl_Color;
223 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
224 light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
228 uniform float cameraDistance;
229 uniform float intensity;
230 varying float light_amount;
234 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1-intensity);
238 glTranslate(0,0,-self._zoom)
239 glRotate(-self._pitch, 1,0,0)
240 glRotate(self._yaw, 0,0,1)
241 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
243 self.viewport = glGetIntegerv(GL_VIEWPORT)
244 self.modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
245 self.projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
247 glClearColor(1,1,1,1)
248 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
250 for n in xrange(0, len(self._scene.objects())):
251 obj = self._scene.objects()[n]
252 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
253 self._renderObject(obj)
255 if self._mouseX > -1:
256 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
257 if n < len(self._scene.objects()):
258 self._focusObj = self._scene.objects()[n]
260 self._focusObj = None
261 #f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
262 #mouse3Dpos = opengl.unproject(self._mouseX, self.viewport[1] + self.viewport[3] - self._mouseY, f, self.modelMatrix, self.projMatrix, self.viewport)
265 glTranslate(0,0,-self._zoom)
266 glRotate(-self._pitch, 1,0,0)
267 glRotate(self._yaw, 0,0,1)
268 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
270 self._objectShader.bind()
271 self._objectShader.setUniform('cameraDistance', self._zoom)
272 for obj in self._scene.objects():
273 if obj._loadAnim is not None:
275 col = self._objColors[0]
276 if self._selectedObj == obj:
277 col = map(lambda n: n * 1.5, col)
278 elif self._focusObj == obj:
279 col = map(lambda n: n * 1.2, col)
280 elif self._focusObj is not None or self._selectedObj is not None:
281 col = map(lambda n: n * 0.8, col)
282 glColor4f(col[0], col[1], col[2], col[3])
283 self._renderObject(obj)
284 self._objectShader.unbind()
287 self._objectLoadShader.bind()
288 self._objectLoadShader.setUniform('cameraDistance', self._zoom)
289 glColor4f(0.2, 0.6, 1.0, 1.0)
290 for obj in self._scene.objects():
291 if obj._loadAnim is None:
293 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
294 self._renderObject(obj)
295 if obj._loadAnim.isDone():
297 self._objectLoadShader.unbind()
302 #Draw the outline of the selected object, on top of everything else except the GUI.
303 if self._selectedObj is not None:
304 glClear(GL_STENCIL_BUFFER_BIT)
306 glDisable(GL_DEPTH_TEST)
307 glEnable(GL_STENCIL_TEST)
308 glStencilFunc(GL_ALWAYS, 1, 1)
309 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
310 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
311 self._renderObject(self._selectedObj)
313 glStencilFunc(GL_EQUAL, 0, 255)
314 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
315 glPolygonMode(GL_FRONT, GL_NONE)
316 glPolygonMode(GL_BACK, GL_LINE)
319 self._renderObject(self._selectedObj)
320 glPolygonMode(GL_BACK, GL_FILL)
321 glPolygonMode(GL_FRONT, GL_FILL)
322 glDisable(GL_STENCIL_TEST)
323 glEnable(GL_DEPTH_TEST)
325 def _renderObject(self, obj):
327 glTranslate(obj.getPosition()[0], obj.getPosition()[1], 0)
328 offset = obj.getDrawOffset()
329 glTranslate(-offset[0], -offset[1], -offset[2])
330 for m in obj._meshList:
332 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
336 def _drawMachine(self):
337 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
338 v0 = [ size[0] / 2, size[1] / 2, size[2]]
339 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
340 v2 = [-size[0] / 2, size[1] / 2, size[2]]
341 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
342 v4 = [ size[0] / 2, size[1] / 2, 0]
343 v5 = [ size[0] / 2,-size[1] / 2, 0]
344 v6 = [-size[0] / 2, size[1] / 2, 0]
345 v7 = [-size[0] / 2,-size[1] / 2, 0]
347 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
348 glEnable(GL_CULL_FACE)
350 glEnableClientState(GL_VERTEX_ARRAY)
351 glVertexPointer(3, GL_FLOAT, 3*4, vList)
353 glColor4ub(5, 171, 231, 64)
354 glDrawArrays(GL_QUADS, 0, 4)
355 glColor4ub(5, 171, 231, 96)
356 glDrawArrays(GL_QUADS, 4, 8)
357 glColor4ub(5, 171, 231, 128)
358 glDrawArrays(GL_QUADS, 12, 8)
360 sx = self._machineSize[0]
361 sy = self._machineSize[1]
362 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
363 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
368 x1 = max(min(x1, sx/2), -sx/2)
369 y1 = max(min(y1, sy/2), -sy/2)
370 x2 = max(min(x2, sx/2), -sx/2)
371 y2 = max(min(y2, sy/2), -sy/2)
372 if (x & 1) == (y & 1):
373 glColor4ub(5, 171, 231, 127)
375 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
377 glVertex3f(x1, y1, -0.02)
378 glVertex3f(x2, y1, -0.02)
379 glVertex3f(x2, y2, -0.02)
380 glVertex3f(x1, y2, -0.02)
383 glDisableClientState(GL_VERTEX_ARRAY)
385 glDisable(GL_CULL_FACE)
387 class shaderEditor(wx.Dialog):
388 def __init__(self, parent, callback, v, f):
389 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
390 self._callback = callback
391 s = wx.BoxSizer(wx.VERTICAL)
393 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
394 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
395 s.Add(self._vertex, 1, flag=wx.EXPAND)
396 s.Add(self._fragment, 1, flag=wx.EXPAND)
398 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
399 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
401 self.SetPosition(self.GetParent().GetPosition())
402 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
406 self._callback(self._vertex.GetValue(), self._fragment.GetValue())