chiark / gitweb /
5ada8220457ae726f16fdcf6c2c1516b428d9f32
[cura.git] / Cura / gui / sceneView.py
1 from __future__ import absolute_import
2
3 import wx
4 import numpy
5 import time
6
7 import OpenGL
8 OpenGL.ERROR_CHECKING = False
9 from OpenGL.GLU import *
10 from OpenGL.GL import *
11
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
16
17 class anim(object):
18         def __init__(self, start, end, runTime):
19                 self._start = start.copy()
20                 self._end = end.copy()
21                 self._startTime = time.time()
22                 self._runTime = runTime
23
24         def isDone(self):
25                 return time.time() > self._startTime + self._runTime
26
27         def getPosition(self):
28                 if self.isDone():
29                         return self._end
30                 f = (time.time() - self._startTime) / self._runTime
31                 ts=f*f
32                 tc=f*f*f
33                 f = 6*tc*ts + -15*ts*ts + 10*tc
34                 return self._start + (self._end - self._start) * f
35
36 class SceneView(openglGui.glGuiPanel):
37         def __init__(self, parent):
38                 super(SceneView, self).__init__(parent)
39
40                 self._yaw = 30
41                 self._pitch = 60
42                 self._zoom = 300
43                 self._objectList = []
44                 self._objectShader = None
45                 self._focusObj = None
46                 self._selectedObj = None
47                 self._objColors = [None,None,None,None]
48                 self._mouseX = -1
49                 self._mouseY = -1
50                 self._viewTarget = numpy.array([0,0,0], numpy.float32);
51                 self._animView = None
52                 wx.EVT_IDLE(self, self.OnIdle)
53                 self.updateProfileToControls()
54
55         def OnIdle(self, e):
56                 if self._animView is not None:
57                         self.Refresh()
58
59         def loadScene(self, fileList):
60                 for filename in fileList:
61                         for obj in meshLoader.loadMeshes(filename):
62                                 self._objectList.append(obj)
63
64         def _deleteObject(self, obj):
65                 if obj == self._selectedObj:
66                         self._selectedObj = None
67                 if obj == self._focusObj:
68                         self._focusObj = None
69                 self._objectList.remove(obj)
70                 for m in obj._meshList:
71                         if m.vbo is not None:
72                                 self.glReleaseList.append(m.vbo)
73
74         def updateProfileToControls(self):
75                 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
76                 self._objColors[0] = profile.getPreferenceColour('model_colour')
77                 self._objColors[1] = profile.getPreferenceColour('model_colour2')
78                 self._objColors[2] = profile.getPreferenceColour('model_colour3')
79                 self._objColors[3] = profile.getPreferenceColour('model_colour4')
80
81         def OnKeyChar(self, keyCode):
82                 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
83                         if self._selectedObj is not None:
84                                 self._deleteObject(self._selectedObj)
85                                 self.Refresh()
86
87         def OnMouseDown(self,e):
88                 self._mouseX = e.GetX()
89                 self._mouseY = e.GetY()
90                 if self._focusObj is not None:
91                         self._selectedObj = self._focusObj
92                         newViewPos = (self._selectedObj.getMaximum() + self._selectedObj.getMinimum()) / 2
93                         self._animView = anim(self._viewTarget, newViewPos, 0.5)
94
95         def OnMouseMotion(self,e):
96                 if e.Dragging() and e.LeftIsDown():
97                         self._yaw += e.GetX() - self._mouseX
98                         self._pitch -= e.GetY() - self._mouseY
99                         if self._pitch > 170:
100                                 self._pitch = 170
101                         if self._pitch < 10:
102                                 self._pitch = 10
103                 if e.Dragging() and e.RightIsDown():
104                         self._zoom += e.GetY() - self._mouseY
105                         if self._zoom < 1:
106                                 self._zoom = 1
107                         if self._zoom > numpy.max(self._machineSize) * 3:
108                                 self._zoom = numpy.max(self._machineSize) * 3
109                 self._mouseX = e.GetX()
110                 self._mouseY = e.GetY()
111
112         def _init3DView(self):
113                 # set viewing projection
114                 size = self.GetSize()
115                 glViewport(0, 0, size.GetWidth(), size.GetHeight())
116                 glLoadIdentity()
117
118                 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
119
120                 glDisable(GL_RESCALE_NORMAL)
121                 glDisable(GL_LIGHTING)
122                 glDisable(GL_LIGHT0)
123                 glEnable(GL_DEPTH_TEST)
124                 glDisable(GL_CULL_FACE)
125                 glDisable(GL_BLEND)
126                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
127
128                 glClearColor(0.8, 0.8, 0.8, 1.0)
129                 glClearStencil(0)
130                 glClearDepth(1.0)
131
132                 glMatrixMode(GL_PROJECTION)
133                 glLoadIdentity()
134                 aspect = float(size.GetWidth()) / float(size.GetHeight())
135                 gluPerspective(45.0, aspect, 1.0, 1000.0)
136
137                 glMatrixMode(GL_MODELVIEW)
138                 glLoadIdentity()
139                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
140
141         def OnPaint(self,e):
142                 if self._animView is not None:
143                         self._viewTarget = self._animView.getPosition()
144                         if self._animView.isDone():
145                                 self._animView = None
146                 if self._objectShader is None:
147                         self._objectShader = opengl.GLShader("""
148 uniform float cameraDistance;
149 varying float light_amount;
150
151 void main(void)
152 {
153     gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
154     gl_FrontColor = gl_Color;
155
156         light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
157         light_amount *= 1 - (length(gl_Position.xyz - vec3(0,0,cameraDistance)) / 1.5 / cameraDistance);
158         light_amount += 0.2;
159 }
160                         ""","""
161 uniform float cameraDistance;
162 varying float light_amount;
163
164 void main(void)
165 {
166         gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
167 }
168                         """)
169                 self._init3DView()
170                 glTranslate(0,0,-self._zoom)
171                 glRotate(-self._pitch, 1,0,0)
172                 glRotate(self._yaw, 0,0,1)
173                 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
174                 glClearColor(1,1,1,1)
175                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
176
177                 for n in xrange(0, len(self._objectList)):
178                         obj = self._objectList[n]
179                         glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
180                         self._renderObject(obj)
181
182                 if self._mouseX > -1:
183                         n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
184                         if n < len(self._objectList):
185                                 self._focusObj = self._objectList[n]
186                         else:
187                                 self._focusObj = None
188
189                 self._init3DView()
190                 glTranslate(0,0,-self._zoom)
191                 glRotate(-self._pitch, 1,0,0)
192                 glRotate(self._yaw, 0,0,1)
193                 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
194
195                 self._objectShader.bind()
196                 self._objectShader.setUniform('cameraDistance', self._zoom)
197                 for obj in self._objectList:
198                         col = self._objColors[0]
199                         if self._selectedObj == obj:
200                                 col = map(lambda n: n * 1.5, col)
201                         elif self._focusObj == obj:
202                                 col = map(lambda n: n * 1.2, col)
203                         elif self._focusObj is not None or  self._selectedObj is not None:
204                                 col = map(lambda n: n * 0.8, col)
205                         glColor4f(col[0], col[1], col[2], col[3])
206                         self._renderObject(obj)
207                 self._objectShader.unbind()
208
209                 self._drawMachine()
210
211         def _renderObject(self, obj):
212                 glPushMatrix()
213                 offset = obj.getDrawOffset()
214                 glTranslate(-offset[0], -offset[1], -offset[2])
215                 for m in obj._meshList:
216                         if m.vbo is None:
217                                 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
218                         m.vbo.render()
219                 glPopMatrix()
220
221         def _drawMachine(self):
222                 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
223                 v0 = [ size[0] / 2, size[1] / 2, size[2]]
224                 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
225                 v2 = [-size[0] / 2, size[1] / 2, size[2]]
226                 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
227                 v4 = [ size[0] / 2, size[1] / 2, 0]
228                 v5 = [ size[0] / 2,-size[1] / 2, 0]
229                 v6 = [-size[0] / 2, size[1] / 2, 0]
230                 v7 = [-size[0] / 2,-size[1] / 2, 0]
231
232                 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
233                 glEnable(GL_CULL_FACE)
234                 glEnable(GL_BLEND)
235                 glEnableClientState(GL_VERTEX_ARRAY)
236                 glVertexPointer(3, GL_FLOAT, 3*4, vList)
237
238                 glColor4ub(5, 171, 231, 64)
239                 glDrawArrays(GL_QUADS, 0, 4)
240                 glColor4ub(5, 171, 231, 96)
241                 glDrawArrays(GL_QUADS, 4, 8)
242                 glColor4ub(5, 171, 231, 128)
243                 glDrawArrays(GL_QUADS, 12, 8)
244
245                 sx = self._machineSize[0]
246                 sy = self._machineSize[1]
247                 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
248                         for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
249                                 x1 = x * 10
250                                 x2 = x1 + 10
251                                 y1 = y * 10
252                                 y2 = y1 + 10
253                                 x1 = max(min(x1, sx/2), -sx/2)
254                                 y1 = max(min(y1, sy/2), -sy/2)
255                                 x2 = max(min(x2, sx/2), -sx/2)
256                                 y2 = max(min(y2, sy/2), -sy/2)
257                                 if (x & 1) == (y & 1):
258                                         glColor4ub(5, 171, 231, 127)
259                                 else:
260                                         glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
261                                 glBegin(GL_QUADS)
262                                 glVertex3f(x1, y1, -0.02)
263                                 glVertex3f(x2, y1, -0.02)
264                                 glVertex3f(x2, y2, -0.02)
265                                 glVertex3f(x1, y2, -0.02)
266                                 glEnd()
267
268                 glDisableClientState(GL_VERTEX_ARRAY)
269                 glDisable(GL_BLEND)
270                 glDisable(GL_CULL_FACE)