From: daid303 Date: Fri, 22 Mar 2013 10:33:02 +0000 (+0100) Subject: Add multi object rendering and selection. X-Git-Tag: 13.05~171 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=7b0efa2d2c34536e2ebbeaa23ec6d6e5f1be59be;p=cura.git Add multi object rendering and selection. --- diff --git a/Cura/gui/sceneView.py b/Cura/gui/sceneView.py index 50ec7d90..cb1916e6 100644 --- a/Cura/gui/sceneView.py +++ b/Cura/gui/sceneView.py @@ -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() diff --git a/Cura/gui/util/opengl.py b/Cura/gui/util/opengl.py index 0adc43bb..98da72c8 100644 --- a/Cura/gui/util/opengl.py +++ b/Cura/gui/util/opengl.py @@ -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) diff --git a/Cura/gui/util/openglGui.py b/Cura/gui/util/openglGui.py index ad9a7f08..3f11a48e 100644 --- a/Cura/gui/util/openglGui.py +++ b/Cura/gui/util/openglGui.py @@ -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 diff --git a/Cura/util/mesh.py b/Cura/util/mesh.py index 18fd76e8..59e3b3f6 100644 --- a/Cura/util/mesh.py +++ b/Cura/util/mesh.py @@ -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