chiark / gitweb /
Change how the engine is interfaced from the python code. Put the GCode viewer in...
[cura.git] / Cura / gui / sceneView.py
index c7ad9c8573819f808575fcee96846a2c1ae011fc..337a18835306c54f4c2ba590ac2cbcabc99519b5 100644 (file)
@@ -9,9 +9,10 @@ import traceback
 import threading
 import math
 import platform
 import threading
 import math
 import platform
+import cStringIO as StringIO
 
 import OpenGL
 
 import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
 from OpenGL.GLU import *
 from OpenGL.GL import *
 
 from OpenGL.GLU import *
 from OpenGL.GL import *
 
@@ -24,11 +25,12 @@ from Cura.util import resources
 from Cura.util import sliceEngine
 from Cura.util import machineCom
 from Cura.util import removableStorage
 from Cura.util import sliceEngine
 from Cura.util import machineCom
 from Cura.util import removableStorage
-from Cura.util import gcodeInterpreter
+from Cura.util import explorer
 from Cura.util.printerConnection import printerConnectionManager
 from Cura.gui.util import previewTools
 from Cura.gui.util import opengl
 from Cura.gui.util import openglGui
 from Cura.util.printerConnection import printerConnectionManager
 from Cura.gui.util import previewTools
 from Cura.gui.util import opengl
 from Cura.gui.util import openglGui
+from Cura.gui.util import engineResultView
 from Cura.gui.tools import youmagineGui
 from Cura.gui.tools import imageToMesh
 
 from Cura.gui.tools import youmagineGui
 from Cura.gui.tools import imageToMesh
 
@@ -40,10 +42,6 @@ class SceneView(openglGui.glGuiPanel):
                self._pitch = 60
                self._zoom = 300
                self._scene = objectScene.Scene()
                self._pitch = 60
                self._zoom = 300
                self._scene = objectScene.Scene()
-               self._gcode = None
-               self._gcodeVBOs = []
-               self._gcodeFilename = None
-               self._gcodeLoadThread = None
                self._objectShader = None
                self._objectLoadShader = None
                self._focusObj = None
                self._objectShader = None
                self._objectLoadShader = None
                self._focusObj = None
@@ -107,16 +105,16 @@ class SceneView(openglGui.glGuiPanel):
                self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None)
 
                self.viewSelection = openglGui.glComboButton(self, _("View mode"), [7,19,11,15,23], [_("Normal"), _("Overhang"), _("Transparent"), _("X-Ray"), _("Layers")], (-1,0), self.OnViewChange)
                self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None)
 
                self.viewSelection = openglGui.glComboButton(self, _("View mode"), [7,19,11,15,23], [_("Normal"), _("Overhang"), _("Transparent"), _("X-Ray"), _("Layers")], (-1,0), self.OnViewChange)
-               self.layerSelect = openglGui.glSlider(self, 10000, 0, 1, (-1,-2), lambda : self.QueueRefresh())
 
                self.youMagineButton = openglGui.glButton(self, 26, _("Share on YouMagine"), (2,0), lambda button: youmagineGui.youmagineManager(self.GetTopLevelParent(), self._scene))
                self.youMagineButton.setDisabled(True)
 
                self.notification = openglGui.glNotification(self, (0, 0))
 
 
                self.youMagineButton = openglGui.glButton(self, 26, _("Share on YouMagine"), (2,0), lambda button: youmagineGui.youmagineManager(self.GetTopLevelParent(), self._scene))
                self.youMagineButton.setDisabled(True)
 
                self.notification = openglGui.glNotification(self, (0, 0))
 
-               self._slicer = sliceEngine.Slicer(self._updateSliceProgress)
+               self._engine = sliceEngine.Engine(self._updateEngineProgress)
+               self._engineResultView = engineResultView.engineResultView(self)
                self._sceneUpdateTimer = wx.Timer(self)
                self._sceneUpdateTimer = wx.Timer(self)
-               self.Bind(wx.EVT_TIMER, self._onRunSlicer, self._sceneUpdateTimer)
+               self.Bind(wx.EVT_TIMER, self._onRunEngine, self._sceneUpdateTimer)
                self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
 
                self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
 
@@ -127,14 +125,7 @@ class SceneView(openglGui.glGuiPanel):
 
        def loadGCodeFile(self, filename):
                self.OnDeleteAll(None)
 
        def loadGCodeFile(self, filename):
                self.OnDeleteAll(None)
-               if self._gcode is not None:
-                       self._gcode = None
-                       for layerVBOlist in self._gcodeVBOs:
-                               for vbo in layerVBOlist:
-                                       self.glReleaseList.append(vbo)
-                       self._gcodeVBOs = []
-               self._gcode = gcodeInterpreter.gcode()
-               self._gcodeFilename = filename
+               #TODO: Load straight GCodeFile
                self.printButton.setBottomText('')
                self.viewSelection.setValue(4)
                self.printButton.setDisabled(False)
                self.printButton.setBottomText('')
                self.viewSelection.setValue(4)
                self.printButton.setDisabled(False)
@@ -226,10 +217,10 @@ class SceneView(openglGui.glGuiPanel):
 
        def OnPrintButton(self, button):
                if button == 1:
 
        def OnPrintButton(self, button):
                if button == 1:
-                       connectionEntry = self._printerConnectionManager.getAvailableConnection()
+                       connectionGroup = self._printerConnectionManager.getAvailableGroup()
                        if machineCom.machineIsConnected():
                                self.showPrintWindow()
                        if machineCom.machineIsConnected():
                                self.showPrintWindow()
-                       elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0):
+                       elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
                                drives = removableStorage.getPossibleSDcardDrives()
                                if len(drives) > 1:
                                        dlg = wx.SingleChoiceDialog(self, "Select SD drive", "Multiple removable drives have been found,\nplease select your SD card drive", map(lambda n: n[0], drives))
                                drives = removableStorage.getPossibleSDcardDrives()
                                if len(drives) > 1:
                                        dlg = wx.SingleChoiceDialog(self, "Select SD drive", "Multiple removable drives have been found,\nplease select your SD card drive", map(lambda n: n[0], drives))
@@ -241,37 +232,58 @@ class SceneView(openglGui.glGuiPanel):
                                else:
                                        drive = drives[0]
                                filename = self._scene._objectList[0].getName() + '.gcode'
                                else:
                                        drive = drives[0]
                                filename = self._scene._objectList[0].getName() + '.gcode'
-                               threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start()
-                       elif connectionEntry is not None:
-                               connection = connectionEntry.connection
-                               if connectionEntry.window is None or not connectionEntry.window:
-                                       connectionEntry.window = printWindow2.printWindow(connection)
-                               connectionEntry.window.Show()
-                               connectionEntry.window.Raise()
-                               if not connection.loadFile(self._gcodeFilename):
-                                       if connection.isPrinting():
-                                               self.notification.message("Cannot start print, because other print still running.")
-                                       else:
-                                               self.notification.message("Failed to start print...")
+                               threading.Thread(target=self._saveGCode,args=(drive[1] + filename, drive[1])).start()
+                       elif connectionGroup is not None:
+                               connections = connectionGroup.getAvailableConnections()
+                               if len(connections) < 2:
+                                       connection = connections[0]
+                               else:
+                                       dlg = wx.SingleChoiceDialog(self, "Select the %s connection to use" % (connectionGroup.getName()), "Multiple %s connections found" % (connectionGroup.getName()), map(lambda n: n.getName(), connections))
+                                       if dlg.ShowModal() != wx.ID_OK:
+                                               dlg.Destroy()
+                                               return
+                                       connection = connections[dlg.GetSelection()]
+                                       dlg.Destroy()
+                               self._openPrintWindowForConnection(connection)
                        else:
                                self.showSaveGCode()
                if button == 3:
                        menu = wx.Menu()
                        self.Bind(wx.EVT_MENU, lambda e: self.showPrintWindow(), menu.Append(-1, _("Print with USB")))
                        else:
                                self.showSaveGCode()
                if button == 3:
                        menu = wx.Menu()
                        self.Bind(wx.EVT_MENU, lambda e: self.showPrintWindow(), menu.Append(-1, _("Print with USB")))
+                       connections = self._printerConnectionManager.getAvailableConnections()
+                       menu.connectionMap = {}
+                       for connection in connections:
+                               i = menu.Append(-1, _("Print with %s") % (connection.getName()))
+                               menu.connectionMap[i.GetId()] = connection
+                               self.Bind(wx.EVT_MENU, lambda e: self._openPrintWindowForConnection(e.GetEventObject().connectionMap[e.GetId()]), i)
                        self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, _("Save GCode...")))
                        self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, _("Save GCode...")))
-                       self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, _("Slice engine log...")))
+                       self.Bind(wx.EVT_MENU, lambda e: self._showEngineLog(), menu.Append(-1, _("Slice engine log...")))
                        self.PopupMenu(menu)
                        menu.Destroy()
 
                        self.PopupMenu(menu)
                        menu.Destroy()
 
+       def _openPrintWindowForConnection(self, connection):
+               print '_openPrintWindowForConnection', connection.getName()
+               if connection.window is None or not connection.window:
+                       connection.window = printWindow2.printWindow(connection)
+               connection.window.Show()
+               connection.window.Raise()
+               #TODO: Fix for _engine.getResult
+               if not connection.loadFile(self._gcodeFilename):
+                       if connection.isPrinting():
+                               self.notification.message("Cannot start print, because other print still running.")
+                       else:
+                               self.notification.message("Failed to start print...")
+
        def showPrintWindow(self):
                if self._gcodeFilename is None:
                        return
                if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                        wx.MessageBox(_("USB printing on the Ultimaker2 is not supported."), _("USB Printing Error"), wx.OK | wx.ICON_WARNING)
                        return
        def showPrintWindow(self):
                if self._gcodeFilename is None:
                        return
                if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                        wx.MessageBox(_("USB printing on the Ultimaker2 is not supported."), _("USB Printing Error"), wx.OK | wx.ICON_WARNING)
                        return
-               self._usbPrintMonitor.loadFile(self._gcodeFilename, self._slicer.getID())
-               if self._gcodeFilename == self._slicer.getGCodeFilename():
-                       self._slicer.submitSliceInfoOnline()
+               #TODO: Fix for _engine.getResult
+               self._usbPrintMonitor.loadFile(self._gcodeFilename, self._engine.getID())
+               if self._gcodeFilename is None:
+                       self._engine.submitInfoOnline()
 
        def showSaveGCode(self):
                if len(self._scene._objectList) < 1:
 
        def showSaveGCode(self):
                if len(self._scene._objectList) < 1:
@@ -286,35 +298,43 @@ class SceneView(openglGui.glGuiPanel):
                filename = dlg.GetPath()
                dlg.Destroy()
 
                filename = dlg.GetPath()
                dlg.Destroy()
 
-               threading.Thread(target=self._copyFile,args=(self._gcodeFilename, filename)).start()
+               threading.Thread(target=self._saveGCode,args=(filename,)).start()
 
 
-       def _copyFile(self, fileA, fileB, allowEject = False):
+       def _saveGCode(self, targetFilename, ejectDrive = False):
+               data = self._engine.getResult().getGCode()
                try:
                try:
-                       size = float(os.stat(fileA).st_size)
-                       with open(fileA, 'rb') as fsrc:
-                               with open(fileB, 'wb') as fdst:
-                                       while 1:
-                                               buf = fsrc.read(16*1024)
-                                               if not buf:
-                                                       break
-                                               fdst.write(buf)
-                                               self.printButton.setProgressBar(float(fsrc.tell()) / size)
-                                               self._queueRefresh()
+                       size = float(len(data))
+                       fsrc = StringIO.StringIO(data)
+                       with open(targetFilename, 'wb') as fdst:
+                               while 1:
+                                       buf = fsrc.read(16*1024)
+                                       if not buf:
+                                               break
+                                       fdst.write(buf)
+                                       self.printButton.setProgressBar(float(fsrc.tell()) / size)
+                                       self._queueRefresh()
                except:
                except:
-                       import sys
-                       print sys.exc_info()
+                       import sys, traceback
+                       traceback.print_exc()
                        self.notification.message("Failed to save")
                else:
                        self.notification.message("Failed to save")
                else:
-                       if allowEject:
-                               self.notification.message("Saved as %s" % (fileB), lambda : self.notification.message('You can now eject the card.') if removableStorage.ejectDrive(allowEject) else self.notification.message('Safe remove failed...'))
+                       if ejectDrive:
+                               self.notification.message("Saved as %s" % (targetFilename), lambda : self._doEjectSD(ejectDrive), 31, 'Eject')
+                       elif explorer.hasExplorer():
+                               self.notification.message("Saved as %s" % (targetFilename), lambda : explorer.openExplorer(targetFilename), 4, 'Open folder')
                        else:
                        else:
-                               self.notification.message("Saved as %s" % (fileB))
+                               self.notification.message("Saved as %s" % (targetFilename))
                self.printButton.setProgressBar(None)
                self.printButton.setProgressBar(None)
-               if fileA == self._slicer.getGCodeFilename():
-                       self._slicer.submitSliceInfoOnline()
+               self._engine.getResult().submitInfoOnline()
 
 
-       def _showSliceLog(self):
-               dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
+       def _doEjectSD(self, drive):
+               if removableStorage.ejectDrive(drive):
+                       self.notification.message('You can now eject the card.')
+               else:
+                       self.notification.message('Safe remove failed...')
+
+       def _showEngineLog(self):
+               dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._engine.getResult().getLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
                dlg.ShowModal()
                dlg.Destroy()
 
                dlg.ShowModal()
                dlg.Destroy()
 
@@ -353,9 +373,6 @@ class SceneView(openglGui.glGuiPanel):
        def OnViewChange(self):
                if self.viewSelection.getValue() == 4:
                        self.viewMode = 'gcode'
        def OnViewChange(self):
                if self.viewSelection.getValue() == 4:
                        self.viewMode = 'gcode'
-                       if self._gcode is not None and self._gcode.layerList is not None:
-                               self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
-                       self._selectObject(None)
                elif self.viewSelection.getValue() == 1:
                        self.viewMode = 'overhang'
                elif self.viewSelection.getValue() == 2:
                elif self.viewSelection.getValue() == 1:
                        self.viewMode = 'overhang'
                elif self.viewSelection.getValue() == 2:
@@ -364,14 +381,14 @@ class SceneView(openglGui.glGuiPanel):
                        self.viewMode = 'xray'
                else:
                        self.viewMode = 'normal'
                        self.viewMode = 'xray'
                else:
                        self.viewMode = 'normal'
-               self.layerSelect.setHidden(self.viewMode != 'gcode')
+               self._engineResultView.setEnabled(self.viewMode == 'gcode')
                self.QueueRefresh()
 
        def OnRotateReset(self, button):
                if self._selectedObj is None:
                        return
                self._selectedObj.resetRotation()
                self.QueueRefresh()
 
        def OnRotateReset(self, button):
                if self._selectedObj is None:
                        return
                self._selectedObj.resetRotation()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -379,7 +396,7 @@ class SceneView(openglGui.glGuiPanel):
                if self._selectedObj is None:
                        return
                self._selectedObj.layFlat()
                if self._selectedObj is None:
                        return
                self._selectedObj.layFlat()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -396,19 +413,19 @@ class SceneView(openglGui.glGuiPanel):
                        return
                machine = profile.getMachineSetting('machine_type')
                self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
                        return
                machine = profile.getMachineSetting('machine_type')
                self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                #self.sceneUpdated()
                if machine == "ultimaker2":
                        #This is bad and Jaime should feel bad!
                        self._selectedObj.setPosition(numpy.array([0.0,-10.0]))
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
                        self._selectedObj.setPosition(numpy.array([0.0,0.0]))
                #self.sceneUpdated()
                if machine == "ultimaker2":
                        #This is bad and Jaime should feel bad!
                        self._selectedObj.setPosition(numpy.array([0.0,-10.0]))
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
                        self._selectedObj.setPosition(numpy.array([0.0,0.0]))
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                else:
                        self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
                else:
                        self._selectedObj.setPosition(numpy.array([0.0, 0.0]))
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
                        self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.updateProfileToControls()
                self.sceneUpdated()
                self._selectObject(self._selectedObj)
                self.updateProfileToControls()
                self.sceneUpdated()
@@ -428,7 +445,7 @@ class SceneView(openglGui.glGuiPanel):
                        return
                self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
                        return
                self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -441,7 +458,7 @@ class SceneView(openglGui.glGuiPanel):
                        return
                self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
                        return
                self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
                self.updateProfileToControls()
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
                self._selectObject(self._selectedObj)
                self.sceneUpdated()
 
@@ -491,7 +508,7 @@ class SceneView(openglGui.glGuiPanel):
                if self._focusObj is None:
                        return
                self._focusObj.setPosition(numpy.array([0.0, 0.0]))
                if self._focusObj is None:
                        return
                self._focusObj.setPosition(numpy.array([0.0, 0.0]))
-               self._scene.pushFree()
+               self._scene.pushFree(self._selectedObj)
                newViewPos = numpy.array([self._focusObj.getPosition()[0], self._focusObj.getPosition()[1], self._focusObj.getSize()[2] / 2])
                self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
                self.sceneUpdated()
                newViewPos = numpy.array([self._focusObj.getPosition()[0], self._focusObj.getPosition()[1], self._focusObj.getSize()[2] / 2])
                self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
                self.sceneUpdated()
@@ -510,66 +527,45 @@ class SceneView(openglGui.glGuiPanel):
 
        def sceneUpdated(self):
                self._sceneUpdateTimer.Start(500, True)
 
        def sceneUpdated(self):
                self._sceneUpdateTimer.Start(500, True)
-               self._slicer.abortSlicer()
+               self._engine.abortEngine()
                self._scene.updateSizeOffsets()
                self.QueueRefresh()
 
                self._scene.updateSizeOffsets()
                self.QueueRefresh()
 
-       def _onRunSlicer(self, e):
+       def _onRunEngine(self, e):
                if self._isSimpleMode:
                        self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
                if self._isSimpleMode:
                        self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
-               self._slicer.runSlicer(self._scene)
+               self._engine.runEngine(self._scene)
                if self._isSimpleMode:
                        profile.resetTempOverride()
 
                if self._isSimpleMode:
                        profile.resetTempOverride()
 
-       def _updateSliceProgress(self, progressValue, ready):
-               if not ready:
+       def _updateEngineProgress(self, progressValue):
+               result = self._engine.getResult()
+               finished = result is not None and result.isFinished()
+               if not finished:
                        if self.printButton.getProgressBar() is not None and progressValue >= 0.0 and abs(self.printButton.getProgressBar() - progressValue) < 0.01:
                                return
                        if self.printButton.getProgressBar() is not None and progressValue >= 0.0 and abs(self.printButton.getProgressBar() - progressValue) < 0.01:
                                return
-               self.printButton.setDisabled(not ready)
+               self.printButton.setDisabled(not finished)
                if progressValue >= 0.0:
                        self.printButton.setProgressBar(progressValue)
                else:
                        self.printButton.setProgressBar(None)
                if progressValue >= 0.0:
                        self.printButton.setProgressBar(progressValue)
                else:
                        self.printButton.setProgressBar(None)
-               if self._gcode is not None:
-                       self._gcode = None
-                       for layerVBOlist in self._gcodeVBOs:
-                               for vbo in layerVBOlist:
-                                       self.glReleaseList.append(vbo)
-                       self._gcodeVBOs = []
-               if ready:
+               self._engineResultView.setResult(result)
+               if finished:
                        self.printButton.setProgressBar(None)
                        self.printButton.setProgressBar(None)
-                       text = '%s' % (self._slicer.getPrintTime())
+                       text = '%s' % (result.getPrintTime())
                        for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))):
                        for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))):
-                               amount = self._slicer.getFilamentAmount(e)
+                               amount = result.getFilamentAmount(e)
                                if amount is None:
                                        continue
                                text += '\n%s' % (amount)
                                if amount is None:
                                        continue
                                text += '\n%s' % (amount)
-                               cost = self._slicer.getFilamentCost(e)
+                               cost = result.getFilamentCost(e)
                                if cost is not None:
                                        text += '\n%s' % (cost)
                        self.printButton.setBottomText(text)
                                if cost is not None:
                                        text += '\n%s' % (cost)
                        self.printButton.setBottomText(text)
-                       self._gcode = gcodeInterpreter.gcode()
-                       self._gcodeFilename = self._slicer.getGCodeFilename()
                else:
                        self.printButton.setBottomText('')
                self.QueueRefresh()
 
                else:
                        self.printButton.setBottomText('')
                self.QueueRefresh()
 
-       def _loadGCode(self):
-               self._gcode.progressCallback = self._gcodeLoadCallback
-               self._gcode.load(self._gcodeFilename)
-
-       def _gcodeLoadCallback(self, progress):
-               if not self or self._gcode is None:
-                       return True
-               if len(self._gcode.layerList) % 15 == 0:
-                       time.sleep(0.1)
-               if self._gcode is None:
-                       return True
-               self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
-               if self.viewMode == 'gcode':
-                       self._queueRefresh()
-               return False
-
        def loadScene(self, fileList):
                for filename in fileList:
                        try:
        def loadScene(self, fileList):
                for filename in fileList:
                        try:
@@ -648,21 +644,59 @@ class SceneView(openglGui.glGuiPanel):
                        self.scaleZmmctrl.setValue(round(size[2], 2))
 
        def OnKeyChar(self, keyCode):
                        self.scaleZmmctrl.setValue(round(size[2], 2))
 
        def OnKeyChar(self, keyCode):
+               if self._engineResultView.OnKeyChar(keyCode):
+                       return
                if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE or (keyCode == wx.WXK_BACK and platform.system() == "Darwin"):
                        if self._selectedObj is not None:
                                self._deleteObject(self._selectedObj)
                                self.QueueRefresh()
                if keyCode == wx.WXK_UP:
                if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE or (keyCode == wx.WXK_BACK and platform.system() == "Darwin"):
                        if self._selectedObj is not None:
                                self._deleteObject(self._selectedObj)
                                self.QueueRefresh()
                if keyCode == wx.WXK_UP:
-                       self.layerSelect.setValue(self.layerSelect.getValue() + 1)
+                       if wx.GetKeyState(wx.WXK_SHIFT):
+                               self._zoom /= 1.2
+                               if self._zoom < 1:
+                                       self._zoom = 1
+                       else:
+                               self._pitch -= 15
                        self.QueueRefresh()
                elif keyCode == wx.WXK_DOWN:
                        self.QueueRefresh()
                elif keyCode == wx.WXK_DOWN:
-                       self.layerSelect.setValue(self.layerSelect.getValue() - 1)
+                       if wx.GetKeyState(wx.WXK_SHIFT):
+                               self._zoom *= 1.2
+                               if self._zoom > numpy.max(self._machineSize) * 3:
+                                       self._zoom = numpy.max(self._machineSize) * 3
+                       else:
+                               self._pitch += 15
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_LEFT:
+                       self._yaw -= 15
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_RIGHT:
+                       self._yaw += 15
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='):
+                       self._zoom /= 1.2
+                       if self._zoom < 1:
+                               self._zoom = 1
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'):
+                       self._zoom *= 1.2
+                       if self._zoom > numpy.max(self._machineSize) * 3:
+                               self._zoom = numpy.max(self._machineSize) * 3
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_HOME:
+                       self._yaw = 30
+                       self._pitch = 60
                        self.QueueRefresh()
                elif keyCode == wx.WXK_PAGEUP:
                        self.QueueRefresh()
                elif keyCode == wx.WXK_PAGEUP:
-                       self.layerSelect.setValue(self.layerSelect.getValue() + 10)
+                       self._yaw = 0
+                       self._pitch = 0
                        self.QueueRefresh()
                elif keyCode == wx.WXK_PAGEDOWN:
                        self.QueueRefresh()
                elif keyCode == wx.WXK_PAGEDOWN:
-                       self.layerSelect.setValue(self.layerSelect.getValue() - 10)
+                       self._yaw = 0
+                       self._pitch = 90
+                       self.QueueRefresh()
+               elif keyCode == wx.WXK_END:
+                       self._yaw = 90
+                       self._pitch = 90
                        self.QueueRefresh()
 
                if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
                        self.QueueRefresh()
 
                if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
@@ -733,12 +767,12 @@ class SceneView(openglGui.glGuiPanel):
                                                self.PopupMenu(menu)
                                        menu.Destroy()
                elif self._mouseState == 'dragObject' and self._selectedObj is not None:
                                                self.PopupMenu(menu)
                                        menu.Destroy()
                elif self._mouseState == 'dragObject' and self._selectedObj is not None:
-                       self._scene.pushFree()
+                       self._scene.pushFree(self._selectedObj)
                        self.sceneUpdated()
                elif self._mouseState == 'tool':
                        if self.tempMatrix is not None and self._selectedObj is not None:
                                self._selectedObj.applyMatrix(self.tempMatrix)
                        self.sceneUpdated()
                elif self._mouseState == 'tool':
                        if self.tempMatrix is not None and self._selectedObj is not None:
                                self._selectedObj.applyMatrix(self.tempMatrix)
-                               self._scene.pushFree()
+                               self._scene.pushFree(self._selectedObj)
                                self._selectObject(self._selectedObj)
                        self.tempMatrix = None
                        self.tool.OnDragEnd()
                                self._selectObject(self._selectedObj)
                        self.tempMatrix = None
                        self.tool.OnDragEnd()
@@ -848,16 +882,16 @@ class SceneView(openglGui.glGuiPanel):
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
 
        def OnPaint(self,e):
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
 
        def OnPaint(self,e):
-               connectionEntry = self._printerConnectionManager.getAvailableConnection()
+               connectionGroup = self._printerConnectionManager.getAvailableGroup()
                if machineCom.machineIsConnected():
                        self.printButton._imageID = 6
                        self.printButton._tooltip = _("Print")
                if machineCom.machineIsConnected():
                        self.printButton._imageID = 6
                        self.printButton._tooltip = _("Print")
-               elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0):
+               elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0):
                        self.printButton._imageID = 2
                        self.printButton._tooltip = _("Toolpath to SD")
                        self.printButton._imageID = 2
                        self.printButton._tooltip = _("Toolpath to SD")
-               elif connectionEntry is not None:
-                       self.printButton._imageID = connectionEntry.icon
-                       self.printButton._tooltip = _("Print with %s") % (connectionEntry.name)
+               elif connectionGroup is not None:
+                       self.printButton._imageID = connectionGroup.getIconID()
+                       self.printButton._tooltip = _("Print with %s") % (connectionGroup.getName())
                else:
                        self.printButton._imageID = 3
                        self.printButton._tooltip = _("Save toolpath")
                else:
                        self.printButton._imageID = 3
                        self.printButton._tooltip = _("Save toolpath")
@@ -870,11 +904,6 @@ class SceneView(openglGui.glGuiPanel):
                        self._zoom = self._animZoom.getPosition()
                        if self._animZoom.isDone():
                                self._animZoom = None
                        self._zoom = self._animZoom.getPosition()
                        if self._animZoom.isDone():
                                self._animZoom = None
-               if self.viewMode == 'gcode' and self._gcode is not None:
-                       try:
-                               self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
-                       except:
-                               pass
                if self._objectShader is None:
                        if opengl.hasShaderSupport():
                                self._objectShader = opengl.GLShader("""
                if self._objectShader is None:
                        if opengl.hasShaderSupport():
                                self._objectShader = opengl.GLShader("""
@@ -992,72 +1021,15 @@ void main(void)
                glRotate(self._yaw, 0,0,1)
                glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
 
                glRotate(self._yaw, 0,0,1)
                glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
 
-               if self.viewMode == 'gcode':
-                       if self._gcode is not None and self._gcode.layerList is None:
-                               self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
-                               self._gcodeLoadThread.daemon = True
-                               self._gcodeLoadThread.start()
-                       if self._gcode is not None and self._gcode.layerList is not None:
-                               glPushMatrix()
-                               if profile.getMachineSetting('machine_center_is_zero') != 'True':
-                                       glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
-                               t = time.time()
-                               drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
-                               for n in xrange(0, drawUpTill):
-                                       c = 1.0 - float(drawUpTill - n) / 15
-                                       c = max(0.3, c)
-                                       if len(self._gcodeVBOs) < n + 1:
-                                               self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
-                                               if time.time() - t > 0.5:
-                                                       self.QueueRefresh()
-                                                       break
-                                       #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
-                                       if n == drawUpTill - 1:
-                                               if len(self._gcodeVBOs[n]) < 9:
-                                                       self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
-                                               glColor3f(c, 0, 0)
-                                               self._gcodeVBOs[n][8].render(GL_QUADS)
-                                               glColor3f(c/2, 0, c)
-                                               self._gcodeVBOs[n][9].render(GL_QUADS)
-                                               glColor3f(0, c, c/2)
-                                               self._gcodeVBOs[n][10].render(GL_QUADS)
-                                               glColor3f(c, 0, 0)
-                                               self._gcodeVBOs[n][11].render(GL_QUADS)
-
-                                               glColor3f(0, c, 0)
-                                               self._gcodeVBOs[n][12].render(GL_QUADS)
-                                               glColor3f(c/2, c/2, 0.0)
-                                               self._gcodeVBOs[n][13].render(GL_QUADS)
-                                               glColor3f(0, c, c)
-                                               self._gcodeVBOs[n][14].render(GL_QUADS)
-                                               self._gcodeVBOs[n][15].render(GL_QUADS)
-                                               glColor3f(0, 0, c)
-                                               self._gcodeVBOs[n][16].render(GL_LINES)
-                                       else:
-                                               glColor3f(c, 0, 0)
-                                               self._gcodeVBOs[n][0].render(GL_LINES)
-                                               glColor3f(c/2, 0, c)
-                                               self._gcodeVBOs[n][1].render(GL_LINES)
-                                               glColor3f(0, c, c/2)
-                                               self._gcodeVBOs[n][2].render(GL_LINES)
-                                               glColor3f(c, 0, 0)
-                                               self._gcodeVBOs[n][3].render(GL_LINES)
-
-                                               glColor3f(0, c, 0)
-                                               self._gcodeVBOs[n][4].render(GL_LINES)
-                                               glColor3f(c/2, c/2, 0.0)
-                                               self._gcodeVBOs[n][5].render(GL_LINES)
-                                               glColor3f(0, c, c)
-                                               self._gcodeVBOs[n][6].render(GL_LINES)
-                                               self._gcodeVBOs[n][7].render(GL_LINES)
-                               glPopMatrix()
-               else:
+               self._objectShader.unbind()
+               self._engineResultView.OnDraw()
+               if self.viewMode != 'gcode':
                        glStencilFunc(GL_ALWAYS, 1, 1)
                        glStencilOp(GL_INCR, GL_INCR, GL_INCR)
 
                        if self.viewMode == 'overhang':
                                self._objectOverhangShader.bind()
                        glStencilFunc(GL_ALWAYS, 1, 1)
                        glStencilOp(GL_INCR, GL_INCR, GL_INCR)
 
                        if self.viewMode == 'overhang':
                                self._objectOverhangShader.bind()
-                               self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - 60)))
+                               self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - profile.getProfileSettingFloat('support_angle'))))
                        else:
                                self._objectShader.bind()
                        for obj in self._scene.objects():
                        else:
                                self._objectShader.bind()
                        for obj in self._scene.objects():
@@ -1148,28 +1120,31 @@ void main(void)
 
                self._drawMachine()
 
 
                self._drawMachine()
 
-               if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID():
-                       glEnable(GL_BLEND)
+               if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._engine.getID():
                        z = self._usbPrintMonitor.getZ()
                        z = self._usbPrintMonitor.getZ()
-                       size = self._machineSize
-                       glColor4ub(255,255,0,128)
-                       glBegin(GL_QUADS)
-                       glVertex3f(-size[0]/2,-size[1]/2, z)
-                       glVertex3f( size[0]/2,-size[1]/2, z)
-                       glVertex3f( size[0]/2, size[1]/2, z)
-                       glVertex3f(-size[0]/2, size[1]/2, z)
-                       glEnd()
+                       if self.viewMode == 'gcode':
+                               layer_height = profile.getProfileSettingFloat('layer_height')
+                               layer1_height = profile.getProfileSettingFloat('bottom_thickness')
+                               if layer_height > 0:
+                                       if layer1_height > 0:
+                                               layer = int((z - layer1_height) / layer_height) + 1
+                                       else:
+                                               layer = int(z / layer_height)
+                               else:
+                                       layer = 1
+                               self.layerSelect.setValue(layer)
+                       else:
+                               size = self._machineSize
+                               glEnable(GL_BLEND)
+                               glColor4ub(255,255,0,128)
+                               glBegin(GL_QUADS)
+                               glVertex3f(-size[0]/2,-size[1]/2, z)
+                               glVertex3f( size[0]/2,-size[1]/2, z)
+                               glVertex3f( size[0]/2, size[1]/2, z)
+                               glVertex3f(-size[0]/2, size[1]/2, z)
+                               glEnd()
 
 
-               if self.viewMode == 'gcode':
-                       if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
-                               glDisable(GL_DEPTH_TEST)
-                               glPushMatrix()
-                               glLoadIdentity()
-                               glTranslate(0,-4,-10)
-                               glColor4ub(60,60,60,255)
-                               opengl.glDrawStringCenter(_("Loading toolpath for visualization..."))
-                               glPopMatrix()
-               else:
+               if self.viewMode != 'gcode':
                        #Draw the object box-shadow, so you can see where it will collide with other objects.
                        if self._selectedObj is not None:
                                glEnable(GL_BLEND)
                        #Draw the object box-shadow, so you can see where it will collide with other objects.
                        if self._selectedObj is not None:
                                glEnable(GL_BLEND)
@@ -1184,20 +1159,21 @@ void main(void)
                                                glVertex3f(p[0], p[1], 0)
                                        glEnd()
                                        glPopMatrix()
                                                glVertex3f(p[0], p[1], 0)
                                        glEnd()
                                        glPopMatrix()
-                               glPushMatrix()
-                               glColor4f(0,0,0,0.06)
-                               glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
-                               glBegin(GL_TRIANGLE_FAN)
-                               for p in self._selectedObj._printAreaHull[::-1]:
-                                       glVertex3f(p[0], p[1], 0)
-                               glEnd()
-                               glBegin(GL_TRIANGLE_FAN)
-                               for p in self._selectedObj._headAreaMinHull[::-1]:
-                                       glVertex3f(p[0], p[1], 0)
-                               glEnd()
+                               if self._scene.isOneAtATime():
+                                       glPushMatrix()
+                                       glColor4f(0,0,0,0.06)
+                                       glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+                                       glBegin(GL_TRIANGLE_FAN)
+                                       for p in self._selectedObj._printAreaHull[::-1]:
+                                               glVertex3f(p[0], p[1], 0)
+                                       glEnd()
+                                       glBegin(GL_TRIANGLE_FAN)
+                                       for p in self._selectedObj._headAreaMinHull[::-1]:
+                                               glVertex3f(p[0], p[1], 0)
+                                       glEnd()
+                                       glPopMatrix()
                                glDepthMask(True)
                                glDisable(GL_CULL_FACE)
                                glDepthMask(True)
                                glDisable(GL_CULL_FACE)
-                               glPopMatrix()
 
                        #Draw the outline of the selected object, on top of everything else except the GUI.
                        if self._selectedObj is not None and self._selectedObj._loadAnim is None:
 
                        #Draw the outline of the selected object, on top of everything else except the GUI.
                        if self._selectedObj is not None and self._selectedObj._loadAnim is None:
@@ -1253,7 +1229,7 @@ void main(void)
                n = 0
                for m in obj._meshList:
                        if m.vbo is None:
                n = 0
                for m in obj._meshList:
                        if m.vbo is None:
-                               m.vbo = opengl.GLVBO(m.vertexes, m.normal)
+                               m.vbo = opengl.GLVBO(GL_TRIANGLES, m.vertexes, m.normal)
                        if brightness:
                                glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
                                n += 1
                        if brightness:
                                glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
                                n += 1
@@ -1336,12 +1312,17 @@ void main(void)
 
                polys = profile.getMachineSizePolygons()
                height = profile.getMachineSettingFloat('machine_height')
 
                polys = profile.getMachineSizePolygons()
                height = profile.getMachineSettingFloat('machine_height')
+               circular = profile.getMachineSetting('machine_shape') == 'Circular'
                glBegin(GL_QUADS)
                for n in xrange(0, len(polys[0])):
                glBegin(GL_QUADS)
                for n in xrange(0, len(polys[0])):
-                       if n % 2 == 0:
-                               glColor4ub(5, 171, 231, 96)
+                       if not circular:
+                               if n % 2 == 0:
+                                       glColor4ub(5, 171, 231, 96)
+                               else:
+                                       glColor4ub(5, 171, 231, 64)
                        else:
                        else:
-                               glColor4ub(5, 171, 231, 64)
+                               glColor4ub(5, 171, 231, 96)
+
                        glVertex3f(polys[0][n][0], polys[0][n][1], height)
                        glVertex3f(polys[0][n][0], polys[0][n][1], 0)
                        glVertex3f(polys[0][n-1][0], polys[0][n-1][1], 0)
                        glVertex3f(polys[0][n][0], polys[0][n][1], height)
                        glVertex3f(polys[0][n][0], polys[0][n][1], 0)
                        glVertex3f(polys[0][n-1][0], polys[0][n-1][1], 0)
@@ -1380,106 +1361,6 @@ void main(void)
                glDisable(GL_BLEND)
                glDisable(GL_CULL_FACE)
 
                glDisable(GL_BLEND)
                glDisable(GL_CULL_FACE)
 
-       def _generateGCodeVBOs(self, layer):
-               ret = []
-               for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
-                       if ':' in extrudeType:
-                               extruder = int(extrudeType[extrudeType.find(':')+1:])
-                               extrudeType = extrudeType[0:extrudeType.find(':')]
-                       else:
-                               extruder = None
-                       pointList = numpy.zeros((0,3), numpy.float32)
-                       for path in layer:
-                               if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
-                                       a = path['points']
-                                       a = numpy.concatenate((a[:-1], a[1:]), 1)
-                                       a = a.reshape((len(a) * 2, 3))
-                                       pointList = numpy.concatenate((pointList, a))
-                       ret.append(opengl.GLVBO(pointList))
-               return ret
-
-       def _generateGCodeVBOs2(self, layer):
-               filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
-               filamentArea = math.pi * filamentRadius * filamentRadius
-               useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
-
-               ret = []
-               for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
-                       if ':' in extrudeType:
-                               extruder = int(extrudeType[extrudeType.find(':')+1:])
-                               extrudeType = extrudeType[0:extrudeType.find(':')]
-                       else:
-                               extruder = None
-                       pointList = numpy.zeros((0,3), numpy.float32)
-                       for path in layer:
-                               if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
-                                       a = path['points']
-                                       if extrudeType == 'FILL':
-                                               a[:,2] += 0.01
-
-                                       normal = a[1:] - a[:-1]
-                                       lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
-                                       normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
-                                       normal[:,2] /= lens
-
-                                       ePerDist = path['extrusion'][1:] / lens
-                                       if useFilamentArea:
-                                               lineWidth = ePerDist / path['layerThickness'] / 2.0
-                                       else:
-                                               lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
-
-                                       normal[:,0] *= lineWidth
-                                       normal[:,1] *= lineWidth
-
-                                       b = numpy.zeros((len(a)-1, 0), numpy.float32)
-                                       b = numpy.concatenate((b, a[1:] + normal), 1)
-                                       b = numpy.concatenate((b, a[1:] - normal), 1)
-                                       b = numpy.concatenate((b, a[:-1] - normal), 1)
-                                       b = numpy.concatenate((b, a[:-1] + normal), 1)
-                                       b = b.reshape((len(b) * 4, 3))
-
-                                       if len(a) > 2:
-                                               normal2 = normal[:-1] + normal[1:]
-                                               lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
-                                               normal2[:,0] /= lens2
-                                               normal2[:,1] /= lens2
-                                               normal2[:,0] *= lineWidth[:-1]
-                                               normal2[:,1] *= lineWidth[:-1]
-
-                                               c = numpy.zeros((len(a)-2, 0), numpy.float32)
-                                               c = numpy.concatenate((c, a[1:-1]), 1)
-                                               c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1)
-                                               c = numpy.concatenate((c, a[1:-1]+normal2), 1)
-                                               c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1)
-
-                                               c = numpy.concatenate((c, a[1:-1]), 1)
-                                               c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
-                                               c = numpy.concatenate((c, a[1:-1]-normal2), 1)
-                                               c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
-
-                                               c = c.reshape((len(c) * 8, 3))
-
-                                               pointList = numpy.concatenate((pointList, b, c))
-                                       else:
-                                               pointList = numpy.concatenate((pointList, b))
-                       ret.append(opengl.GLVBO(pointList))
-
-               pointList = numpy.zeros((0,3), numpy.float32)
-               for path in layer:
-                       if path['type'] == 'move':
-                               a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
-                               a = numpy.concatenate((a[:-1], a[1:]), 1)
-                               a = a.reshape((len(a) * 2, 3))
-                               pointList = numpy.concatenate((pointList, a))
-                       if path['type'] == 'retract':
-                               a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
-                               a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
-                               a = a.reshape((len(a) * 2, 3))
-                               pointList = numpy.concatenate((pointList, a))
-               ret.append(opengl.GLVBO(pointList))
-
-               return ret
-
        def getObjectCenterPos(self):
                if self._selectedObj is None:
                        return [0.0, 0.0, 0.0]
        def getObjectCenterPos(self):
                if self._selectedObj is None:
                        return [0.0, 0.0, 0.0]