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.gui.util import opengl
15 from Cura.gui.util import openglGui
18 def __init__(self, start, end, runTime):
21 self._startTime = time.time()
22 self._runTime = runTime
25 return time.time() > self._startTime + self._runTime
27 def getPosition(self):
30 f = (time.time() - self._startTime) / self._runTime
33 f = 6*tc*ts + -15*ts*ts + 10*tc
34 return self._start + (self._end - self._start) * f
36 class SceneView(openglGui.glGuiPanel):
37 def __init__(self, parent):
38 super(SceneView, self).__init__(parent)
44 self._objectShader = None
46 self._selectedObj = None
47 self._objColors = [None,None,None,None]
50 self._mouseState = None
51 self._viewTarget = numpy.array([0,0,0], numpy.float32);
54 wx.EVT_IDLE(self, self.OnIdle)
55 self.updateProfileToControls()
58 if self._animView is not None or self._animZoom is not None:
61 def loadScene(self, fileList):
62 for filename in fileList:
63 for obj in meshLoader.loadMeshes(filename):
64 self._objectList.append(obj)
66 def _deleteObject(self, obj):
67 if obj == self._selectedObj:
68 self._selectedObj = None
69 if obj == self._focusObj:
71 self._objectList.remove(obj)
72 for m in obj._meshList:
74 self.glReleaseList.append(m.vbo)
76 def updateProfileToControls(self):
77 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
78 self._objColors[0] = profile.getPreferenceColour('model_colour')
79 self._objColors[1] = profile.getPreferenceColour('model_colour2')
80 self._objColors[2] = profile.getPreferenceColour('model_colour3')
81 self._objColors[3] = profile.getPreferenceColour('model_colour4')
83 def OnKeyChar(self, keyCode):
84 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
85 if self._selectedObj is not None:
86 self._deleteObject(self._selectedObj)
89 def OnMouseDown(self,e):
90 self._mouseX = e.GetX()
91 self._mouseY = e.GetY()
93 self._mouseState = 'doubleClick'
95 self._mouseState = 'dragOrClick'
97 def OnMouseUp(self, e):
98 if self._mouseState == 'dragOrClick':
100 if self._focusObj is not None:
101 self._selectedObj = self._focusObj
102 newViewPos = numpy.array([self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], self._selectedObj.getMaximum()[2] / 2])
103 self._animView = anim(self._viewTarget.copy(), newViewPos, 0.5)
105 self._selectedObj = None
107 elif self._mouseState == 'doubleClick':
108 if self._selectedObj is not None:
109 newZoom = numpy.linalg.norm(self._selectedObj.getSize()) * 2
110 self._animZoom = anim(self._zoom, newZoom, 0.5)
111 self._mouseState = None
113 def OnMouseMotion(self,e):
115 self._mouseState = 'drag'
116 if not e.LeftIsDown() and e.RightIsDown():
117 self._yaw += e.GetX() - self._mouseX
118 self._pitch -= e.GetY() - self._mouseY
119 if self._pitch > 170:
123 if (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
124 self._zoom += e.GetY() - self._mouseY
127 if self._zoom > numpy.max(self._machineSize) * 3:
128 self._zoom = numpy.max(self._machineSize) * 3
129 self._mouseX = e.GetX()
130 self._mouseY = e.GetY()
132 def _init3DView(self):
133 # set viewing projection
134 size = self.GetSize()
135 glViewport(0, 0, size.GetWidth(), size.GetHeight())
138 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
140 glDisable(GL_RESCALE_NORMAL)
141 glDisable(GL_LIGHTING)
143 glEnable(GL_DEPTH_TEST)
144 glDisable(GL_CULL_FACE)
146 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
148 glClearColor(0.8, 0.8, 0.8, 1.0)
152 glMatrixMode(GL_PROJECTION)
154 aspect = float(size.GetWidth()) / float(size.GetHeight())
155 gluPerspective(45.0, aspect, 1.0, 1000.0)
157 glMatrixMode(GL_MODELVIEW)
159 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
162 if self._animView is not None:
163 self._viewTarget = self._animView.getPosition()
164 if self._animView.isDone():
165 self._animView = None
166 if self._animZoom is not None:
167 self._zoom = self._animZoom.getPosition()
168 if self._animZoom.isDone():
169 self._animZoom = None
170 if self._objectShader is None:
171 self._objectShader = opengl.GLShader("""
172 uniform float cameraDistance;
173 varying float light_amount;
177 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
178 gl_FrontColor = gl_Color;
180 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
181 light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
185 uniform float cameraDistance;
186 varying float light_amount;
190 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
194 glTranslate(0,0,-self._zoom)
195 glRotate(-self._pitch, 1,0,0)
196 glRotate(self._yaw, 0,0,1)
197 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
198 glClearColor(1,1,1,1)
199 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
201 for n in xrange(0, len(self._objectList)):
202 obj = self._objectList[n]
203 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
204 self._renderObject(obj)
206 if self._mouseX > -1:
207 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
208 if n < len(self._objectList):
209 self._focusObj = self._objectList[n]
211 self._focusObj = None
214 glTranslate(0,0,-self._zoom)
215 glRotate(-self._pitch, 1,0,0)
216 glRotate(self._yaw, 0,0,1)
217 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
219 self._objectShader.bind()
220 self._objectShader.setUniform('cameraDistance', self._zoom)
221 for obj in self._objectList:
222 col = self._objColors[0]
223 if self._selectedObj == obj:
224 col = map(lambda n: n * 1.5, col)
225 elif self._focusObj == obj:
226 col = map(lambda n: n * 1.2, col)
227 elif self._focusObj is not None or self._selectedObj is not None:
228 col = map(lambda n: n * 0.8, col)
229 glColor4f(col[0], col[1], col[2], col[3])
230 self._renderObject(obj)
231 self._objectShader.unbind()
235 #Draw the outline of the selected object, on top of everything else except the GUI.
236 if self._selectedObj is not None:
237 glClear(GL_STENCIL_BUFFER_BIT)
239 glDisable(GL_DEPTH_TEST)
240 glEnable(GL_STENCIL_TEST)
241 glStencilFunc(GL_ALWAYS, 1, 1)
242 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
243 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
244 self._renderObject(self._selectedObj)
246 glStencilFunc(GL_EQUAL, 0, 255)
247 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
248 glPolygonMode(GL_FRONT, GL_NONE)
249 glPolygonMode(GL_BACK, GL_LINE)
252 self._renderObject(self._selectedObj)
253 glPolygonMode(GL_BACK, GL_FILL)
254 glPolygonMode(GL_FRONT, GL_FILL)
255 glDisable(GL_STENCIL_TEST)
256 glEnable(GL_DEPTH_TEST)
258 def _renderObject(self, obj):
260 glTranslate(obj.getPosition()[0], obj.getPosition()[1], 0)
261 offset = obj.getDrawOffset()
262 glTranslate(-offset[0], -offset[1], -offset[2])
263 for m in obj._meshList:
265 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
269 def _drawMachine(self):
270 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
271 v0 = [ size[0] / 2, size[1] / 2, size[2]]
272 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
273 v2 = [-size[0] / 2, size[1] / 2, size[2]]
274 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
275 v4 = [ size[0] / 2, size[1] / 2, 0]
276 v5 = [ size[0] / 2,-size[1] / 2, 0]
277 v6 = [-size[0] / 2, size[1] / 2, 0]
278 v7 = [-size[0] / 2,-size[1] / 2, 0]
280 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
281 glEnable(GL_CULL_FACE)
283 glEnableClientState(GL_VERTEX_ARRAY)
284 glVertexPointer(3, GL_FLOAT, 3*4, vList)
286 glColor4ub(5, 171, 231, 64)
287 glDrawArrays(GL_QUADS, 0, 4)
288 glColor4ub(5, 171, 231, 96)
289 glDrawArrays(GL_QUADS, 4, 8)
290 glColor4ub(5, 171, 231, 128)
291 glDrawArrays(GL_QUADS, 12, 8)
293 sx = self._machineSize[0]
294 sy = self._machineSize[1]
295 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
296 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
301 x1 = max(min(x1, sx/2), -sx/2)
302 y1 = max(min(y1, sy/2), -sy/2)
303 x2 = max(min(x2, sx/2), -sx/2)
304 y2 = max(min(y2, sy/2), -sy/2)
305 if (x & 1) == (y & 1):
306 glColor4ub(5, 171, 231, 127)
308 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
310 glVertex3f(x1, y1, -0.02)
311 glVertex3f(x2, y1, -0.02)
312 glVertex3f(x2, y2, -0.02)
313 glVertex3f(x1, y2, -0.02)
316 glDisableClientState(GL_VERTEX_ARRAY)
318 glDisable(GL_CULL_FACE)