chiark / gitweb /
Add multi object rendering and selection.
authordaid303 <daid303@gmail.com>
Fri, 22 Mar 2013 10:33:02 +0000 (11:33 +0100)
committerdaid303 <daid303@gmail.com>
Fri, 22 Mar 2013 10:33:02 +0000 (11:33 +0100)
Cura/gui/sceneView.py
Cura/gui/util/opengl.py
Cura/gui/util/openglGui.py
Cura/util/mesh.py

index 50ec7d90cc0cb6f3827ace4691f3b31ce9278c2c..cb1916e605b356b31c2628abe102c9f9a3009d8d 100644 (file)
@@ -1,8 +1,7 @@
 from __future__ import absolute_import
 from __future__ import division
 
-import numpy
-from ctypes import c_void_p
+import wx
 
 import OpenGL
 OpenGL.ERROR_CHECKING = False
@@ -23,8 +22,11 @@ class SceneView(openglGui.glGuiPanel):
                self._zoom = 100
                self._objectList = []
                self._objectShader = None
+               self._focusObj = None
+               self._selectedObj = None
                self._objColors = [None,None,None,None]
-               self._tmpVertex = None
+               self._mouseX = -1
+               self._mouseY = -1
                self.updateProfileToControls()
 
        def loadScene(self, fileList):
@@ -32,33 +34,54 @@ class SceneView(openglGui.glGuiPanel):
                        for obj in meshLoader.loadMeshes(filename):
                                self._objectList.append(obj)
 
+       def _deleteObject(self, obj):
+               if obj == self._selectedObj:
+                       self._selectedObj = None
+               if obj == self._focusObj:
+                       self._focusObj = None
+               self._objectList.remove(obj)
+               for m in obj._meshList:
+                       if m.vbo is not None:
+                               self.glReleaseList.append(m.vbo)
+
        def updateProfileToControls(self):
                self._objColors[0] = profile.getPreferenceColour('model_colour')
                self._objColors[1] = profile.getPreferenceColour('model_colour2')
                self._objColors[2] = profile.getPreferenceColour('model_colour3')
                self._objColors[3] = profile.getPreferenceColour('model_colour4')
 
+       def OnKeyChar(self, keyCode):
+               if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
+                       if self._selectedObj is not None:
+                               self._deleteObject(self._selectedObj)
+                               self.Refresh()
+
+       def OnMouseDown(self,e):
+               if self._focusObj is not None:
+                       self._selectedObj = self._focusObj
+
        def OnMouseMotion(self,e):
                if e.Dragging() and e.LeftIsDown():
-                       self._yaw += e.GetX() - self.oldX
-                       self._pitch -= e.GetY() - self.oldY
+                       self._yaw += e.GetX() - self._mouseX
+                       self._pitch -= e.GetY() - self._mouseY
                        if self._pitch > 170:
                                self._pitch = 170
                        if self._pitch < 10:
                                self._pitch = 10
                if e.Dragging() and e.RightIsDown():
-                       self._zoom += e.GetY() - self.oldY
+                       self._zoom += e.GetY() - self._mouseY
                        if self._zoom < 1:
                                self._zoom = 1
                        if self._zoom > 500:
                                self._zoom = 500
-               self.oldX = e.GetX()
-               self.oldY = e.GetY()
+               self._mouseX = e.GetX()
+               self._mouseY = e.GetY()
 
        def _init3DView(self):
                # set viewing projection
                size = self.GetSize()
                glViewport(0, 0, size.GetWidth(), size.GetHeight())
+               glLoadIdentity()
 
                glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
 
@@ -84,7 +107,7 @@ class SceneView(openglGui.glGuiPanel):
 
        def OnPaint(self,e):
                if self._objectShader is None:
-                       self._objectShader = opengl.GLShader("""
+                       self._objectShader = opengl.GLShader(self, """
 uniform float cameraDistance;
 varying float light_amount;
 
@@ -103,7 +126,7 @@ varying float light_amount;
 
 void main(void)
 {
-       gl_FragColor = gl_Color * light_amount;
+       gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
 }
                        """)
                self._init3DView()
@@ -111,14 +134,47 @@ void main(void)
                glRotate(-self._pitch, 1,0,0)
                glRotate(self._yaw, 0,0,1)
                glTranslate(0,0,-15)
-               glColor3f(self._objColors[0][0], self._objColors[0][1], self._objColors[0][2])
+               glClearColor(1,1,1,1)
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
+
+               for n in xrange(0, len(self._objectList)):
+                       obj = self._objectList[n]
+                       glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
+                       self._renderObject(obj)
+
+               if self._mouseX > -1:
+                       n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
+                       if n < len(self._objectList):
+                               self._focusObj = self._objectList[n]
+                       else:
+                               self._focusObj = None
+
+               self._init3DView()
+               glTranslate(0,0,-self._zoom)
+               glRotate(-self._pitch, 1,0,0)
+               glRotate(self._yaw, 0,0,1)
+               glTranslate(0,0,-15)
 
                self._objectShader.bind()
                self._objectShader.setUniform('cameraDistance', self._zoom)
-               if self._tmpVertex is None:
-                       for obj in self._objectList:
-                               for m in obj._meshList:
-                                       self._tmpVertex = opengl.GLVBO(m.vertexes, m.normal)
-
-               self._tmpVertex.render()
+               for obj in self._objectList:
+                       col = self._objColors[0]
+                       if self._selectedObj == obj:
+                               col = map(lambda n: n * 1.3, col)
+                       elif self._focusObj == obj:
+                               col = map(lambda n: n * 1.2, col)
+                       elif self._focusObj is not None or  self._selectedObj is not None:
+                               col = map(lambda n: n * 0.8, col)
+                       glColor4f(col[0], col[1], col[2], col[3])
+                       self._renderObject(obj)
                self._objectShader.unbind()
+
+       def _renderObject(self, obj):
+               glPushMatrix()
+               offset = (obj.getMinimum() + obj.getMaximum()) / 2
+               glTranslate(-offset[0], -offset[1], -obj.getMinimum()[2])
+               for m in obj._meshList:
+                       if m.vbo is None:
+                               m.vbo = opengl.GLVBO(self, m.vertexes, m.normal)
+                       m.vbo.render()
+               glPopMatrix()
index 0adc43bb823487795c40e27f89d15515f5871e6d..98da72c88ee5c90357163ebe67826bb9e5f67f98 100644 (file)
@@ -23,7 +23,8 @@ glutInit()
 platformMesh = None
 
 class GLShader(object):
-       def __init__(self, vertexProgram, fragmentProgram):
+       def __init__(self, owner, vertexProgram, fragmentProgram):
+               self._owner = owner
                try:
                        self._vertexProgram = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
                        self._fragmentProgram = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
@@ -40,18 +41,27 @@ class GLShader(object):
        def unbind(self):
                shaders.glUseProgram(0)
 
-       def delete(self):
-               shaders.glDeleteShader(self._vertexProgram)
-               shaders.glDeleteShader(self._fragmentProgram)
-               glDeleteProgram(self._program)
+       def release(self):
+               if self._program != None:
+                       shaders.glDeleteShader(self._vertexProgram)
+                       shaders.glDeleteShader(self._fragmentProgram)
+                       glDeleteProgram(self._program)
+                       self._program = None
 
        def setUniform(self, name, value):
-               glUniform1f(glGetUniformLocation(self._program, name), value)
+               if self._program is not None:
+                       glUniform1f(glGetUniformLocation(self._program, name), value)
+
+       def __del__(self):
+               if self._program is not None and bool(glDeleteProgram):
+                       print "OpenGL shader was not properly cleaned, trying to clean it up now."
+                       self._owner.glReleaseList.append(self)
 
 class GLVBO(object):
-       def __init__(self, vertexArray, normalArray):
+       def __init__(self, owner, vertexArray, normalArray):
                self._buffer = glGenBuffers(1)
                self._size = len(vertexArray)
+               self._owner = owner
                glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
                glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
                glBindBuffer(GL_ARRAY_BUFFER, 0)
@@ -59,8 +69,6 @@ class GLVBO(object):
        def render(self):
                glEnableClientState(GL_VERTEX_ARRAY)
                glEnableClientState(GL_NORMAL_ARRAY)
-               #glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
-               #glNormalPointer(GL_FLOAT, 0, m.normal)
                glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
                glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
                glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
@@ -82,9 +90,8 @@ class GLVBO(object):
                        self._buffer = None
 
        def __del__(self):
-               if self._buffer is not None:
-                       print "OpenGL buffer was not properly cleaned, trying to clean it up now."
-                       glDeleteBuffers(self._buffer, 1)
+               if self._buffer is not None and bool(glDeleteBuffers):
+                       self._owner.glReleaseList.append(self)
 
 def DrawMachine(machineSize):
        glDisable(GL_LIGHTING)
index ad9a7f083aefae32ea73f0137e955794ae9d5d85..3f11a48e16c79196cbf29daf66d6926d27a8f68b 100644 (file)
@@ -114,35 +114,44 @@ class glGuiPanel(glcanvas.GLCanvas):
                self._glRobotTexture = None
                self._buttonSize = 64
 
+               self.glReleaseList = []
+
                wx.EVT_PAINT(self, self._OnGuiPaint)
                wx.EVT_SIZE(self, self._OnSize)
                wx.EVT_ERASE_BACKGROUND(self, self._OnEraseBackground)
-               wx.EVT_LEFT_DOWN(self, self._OnGuiMouseLeftDown)
-               wx.EVT_LEFT_UP(self, self._OnGuiMouseLeftUp)
+               wx.EVT_LEFT_DOWN(self, self._OnGuiMouseDown)
+               wx.EVT_LEFT_UP(self, self._OnGuiMouseUp)
+               wx.EVT_RIGHT_DOWN(self, self._OnGuiMouseDown)
+               wx.EVT_RIGHT_UP(self, self._OnGuiMouseUp)
+               wx.EVT_MIDDLE_DOWN(self, self._OnGuiMouseDown)
+               wx.EVT_MIDDLE_UP(self, self._OnGuiMouseUp)
                wx.EVT_MOTION(self, self._OnGuiMouseMotion)
-               wx.EVT_CHAR(self, self.OnKeyChar)
+               wx.EVT_CHAR(self, self._OnGuiKeyChar)
                wx.EVT_KILL_FOCUS(self, self.OnFocusLost)
 
-       def OnKeyChar(self, e):
+       def _OnGuiKeyChar(self, e):
                if self._focus is not None:
                        self._focus.OnKeyChar(e.GetKeyCode())
                        self.Refresh()
+               else:
+                       self.OnKeyChar(e.GetKeyCode())
 
        def OnFocusLost(self, e):
                self._focus = None
                self.Refresh()
 
-       def _OnGuiMouseLeftDown(self,e):
+       def _OnGuiMouseDown(self,e):
                self.SetFocus()
                if self._container.OnMouseDown(e.GetX(), e.GetY()):
                        self.Refresh()
                        return
-               self.OnMouseLeftDown(e)
-       def _OnGuiMouseLeftUp(self, e):
+               self.OnMouseDown(e)
+
+       def _OnGuiMouseUp(self, e):
                if self._container.OnMouseUp(e.GetX(), e.GetY()):
                        self.Refresh()
                        return
-               self.OnMouseLeftUp(e)
+               self.OnMouseUp(e)
 
        def _OnGuiMouseMotion(self,e):
                self.Refresh()
@@ -171,6 +180,9 @@ class glGuiPanel(glcanvas.GLCanvas):
                dc = wx.PaintDC(self)
                try:
                        self.SetCurrent(self._context)
+                       for obj in self.glReleaseList:
+                               obj.release()
+                       del self.glReleaseList[:]
                        self.OnPaint(e)
                        self._drawGui()
                        glFlush()
@@ -234,12 +246,14 @@ class glGuiPanel(glcanvas.GLCanvas):
                self._container.updateLayout()
                self.Refresh()
 
-       def OnMouseLeftDown(self,e):
+       def OnMouseDown(self,e):
                pass
-       def OnMouseLeftUp(self,e):
+       def OnMouseUp(self,e):
                pass
        def OnMouseMotion(self, e):
                pass
+       def OnKeyChar(self, keyCode):
+               pass
        def OnPaint(self, e):
                pass
 
index 18fd76e85da396bf34976544ee346a3356133377..59e3b3f62a04f42ed954972cb300780b1e2f3b3a 100644 (file)
@@ -60,6 +60,7 @@ class mesh(object):
        def __init__(self):
                self.vertexes = None
                self.vertexCount = 0
+               self.vbo = None
 
        def _addFace(self, x0, y0, z0, x1, y1, z1, x2, y2, z2):
                n = self.vertexCount