X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=Cura%2Fgui%2FsceneView.py;h=337a18835306c54f4c2ba590ac2cbcabc99519b5;hb=6208201bafdeaf82883181471c6da3a41283cfe7;hp=5974fd8b674ec483fd4e22d382d8f52fe01d7fd3;hpb=103989f26ff3dfa1b4b3308bd4bd02d0627351f7;p=cura.git diff --git a/Cura/gui/sceneView.py b/Cura/gui/sceneView.py index 5974fd8b..337a1883 100644 --- a/Cura/gui/sceneView.py +++ b/Cura/gui/sceneView.py @@ -9,13 +9,15 @@ import traceback import threading import math import platform +import cStringIO as StringIO import OpenGL -OpenGL.ERROR_CHECKING = False +#OpenGL.ERROR_CHECKING = False from OpenGL.GLU import * from OpenGL.GL import * from Cura.gui import printWindow +from Cura.gui import printWindow2 from Cura.util import profile from Cura.util import meshLoader from Cura.util import objectScene @@ -23,10 +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 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.gui.util import engineResultView from Cura.gui.tools import youmagineGui from Cura.gui.tools import imageToMesh @@ -38,10 +42,6 @@ class SceneView(openglGui.glGuiPanel): 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 @@ -54,8 +54,10 @@ class SceneView(openglGui.glGuiPanel): self._animView = None self._animZoom = None self._platformMesh = {} + self._platformTexture = None self._isSimpleMode = True self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh()) + self._printerConnectionManager = printerConnectionManager.PrinterConnectionManager() self._viewport = None self._modelMatrix = None @@ -103,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.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._slicer = sliceEngine.Slicer(self._updateSliceProgress) + self._engine = sliceEngine.Engine(self._updateEngineProgress) + self._engineResultView = engineResultView.engineResultView(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) @@ -123,14 +125,7 @@ class SceneView(openglGui.glGuiPanel): 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) @@ -222,9 +217,10 @@ class SceneView(openglGui.glGuiPanel): def OnPrintButton(self, button): if button == 1: + connectionGroup = self._printerConnectionManager.getAvailableGroup() if machineCom.machineIsConnected(): self.showPrintWindow() - elif len(removableStorage.getPossibleSDcardDrives()) > 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)) @@ -236,23 +232,58 @@ class SceneView(openglGui.glGuiPanel): 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() + 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"))) + 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._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() + 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 - self._usbPrintMonitor.loadFile(self._gcodeFilename, self._slicer.getID()) - if self._gcodeFilename == self._slicer.getGCodeFilename(): - self._slicer.submitSliceInfoOnline() + 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 + #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: @@ -267,35 +298,43 @@ class SceneView(openglGui.glGuiPanel): 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: - 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: - import sys - print sys.exc_info() + import sys, traceback + traceback.print_exc() 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: - self.notification.message("Saved as %s" % (fileB)) + self.notification.message("Saved as %s" % (targetFilename)) 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() @@ -334,9 +373,6 @@ class SceneView(openglGui.glGuiPanel): 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: @@ -345,14 +381,14 @@ class SceneView(openglGui.glGuiPanel): 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._scene.pushFree() + self._scene.pushFree(self._selectedObj) self._selectObject(self._selectedObj) self.sceneUpdated() @@ -360,7 +396,7 @@ class SceneView(openglGui.glGuiPanel): if self._selectedObj is None: return self._selectedObj.layFlat() - self._scene.pushFree() + self._scene.pushFree(self._selectedObj) self._selectObject(self._selectedObj) self.sceneUpdated() @@ -375,8 +411,21 @@ class SceneView(openglGui.glGuiPanel): def OnScaleMax(self, button): if self._selectedObj is None: return - self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32)) - self._scene.pushFree() + machine = profile.getMachineSetting('machine_type') + self._selectedObj.setPosition(numpy.array([0.0, 0.0])) + 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._scene.pushFree(self._selectedObj) + else: + self._selectedObj.setPosition(numpy.array([0.0, 0.0])) + 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._scene.pushFree(self._selectedObj) self._selectObject(self._selectedObj) self.updateProfileToControls() self.sceneUpdated() @@ -396,7 +445,7 @@ class SceneView(openglGui.glGuiPanel): 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() @@ -409,7 +458,7 @@ class SceneView(openglGui.glGuiPanel): 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() @@ -459,7 +508,7 @@ class SceneView(openglGui.glGuiPanel): 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() @@ -478,66 +527,45 @@ class SceneView(openglGui.glGuiPanel): def sceneUpdated(self): self._sceneUpdateTimer.Start(500, True) - self._slicer.abortSlicer() - self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32)) + self._engine.abortEngine() + self._scene.updateSizeOffsets() self.QueueRefresh() - def _onRunSlicer(self, e): + def _onRunEngine(self, e): if self._isSimpleMode: self.GetTopLevelParent().simpleSettingsPanel.setupSlice() - self._slicer.runSlicer(self._scene) + self._engine.runEngine(self._scene) 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 - self.printButton.setDisabled(not ready) + self.printButton.setDisabled(not finished) 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) - text = '%s' % (self._slicer.getPrintTime()) + text = '%s' % (result.getPrintTime()) 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) - cost = self._slicer.getFilamentCost(e) + cost = result.getFilamentCost(e) 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() - 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: @@ -556,7 +584,8 @@ class SceneView(openglGui.glGuiPanel): else: obj._loadAnim = None self._scene.add(obj) - self._scene.centerAll() + if not self._scene.checkPlatform(obj): + self._scene.centerAll() self._selectObject(obj) if obj.getScale()[0] < 1.0: self.notification.message("Warning: Object scaled down.") @@ -578,7 +607,7 @@ class SceneView(openglGui.glGuiPanel): def _selectObject(self, obj, zoom = True): if obj != self._selectedObj: self._selectedObj = obj - self.updateProfileToControls() + self.updateModelSettingsToControls() self.updateToolButtons() if zoom and obj is not None: newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2]) @@ -594,15 +623,16 @@ class SceneView(openglGui.glGuiPanel): if self._isSimpleMode != oldSimpleMode: self._scene.arrangeAll() self.sceneUpdated() + self._scene.updateSizeOffsets(True) self._machineSize = numpy.array([profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')]) 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') - self._scene.setMachineSize(self._machineSize) - self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32)) - self._scene.setHeadSize(profile.getMachineSettingFloat('extruder_head_size_min_x'), profile.getMachineSettingFloat('extruder_head_size_max_x'), profile.getMachineSettingFloat('extruder_head_size_min_y'), profile.getMachineSettingFloat('extruder_head_size_max_y'), profile.getMachineSettingFloat('extruder_head_size_height')) + self._scene.updateMachineDimensions() + self.updateModelSettingsToControls() + def updateModelSettingsToControls(self): if self._selectedObj is not None: scale = self._selectedObj.getScale() size = self._selectedObj.getSize() @@ -614,21 +644,59 @@ class SceneView(openglGui.glGuiPanel): 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: - 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.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.layerSelect.setValue(self.layerSelect.getValue() + 10) + self._yaw = 0 + self._pitch = 0 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): @@ -699,12 +767,12 @@ class SceneView(openglGui.glGuiPanel): 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._scene.pushFree() + self._scene.pushFree(self._selectedObj) self._selectObject(self._selectedObj) self.tempMatrix = None self.tool.OnDragEnd() @@ -814,12 +882,16 @@ class SceneView(openglGui.glGuiPanel): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) def OnPaint(self,e): + connectionGroup = self._printerConnectionManager.getAvailableGroup() if machineCom.machineIsConnected(): self.printButton._imageID = 6 self.printButton._tooltip = _("Print") - elif len(removableStorage.getPossibleSDcardDrives()) > 0: + elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionGroup is None or connectionGroup.getPriority() < 0): self.printButton._imageID = 2 self.printButton._tooltip = _("Toolpath to SD") + 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") @@ -832,11 +904,6 @@ class SceneView(openglGui.glGuiPanel): 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(""" @@ -954,72 +1021,15 @@ void main(void) 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() - 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(): @@ -1110,44 +1120,60 @@ void main(void) 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() - 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 and len(self._scene.objects()) > 1: - size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend() - glPushMatrix() - glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0) + if self._selectedObj is not None: glEnable(GL_BLEND) glEnable(GL_CULL_FACE) - glColor4f(0,0,0,0.12) - glBegin(GL_QUADS) - glVertex3f(-size[0], size[1], 0.1) - glVertex3f(-size[0], -size[1], 0.1) - glVertex3f( size[0], -size[1], 0.1) - glVertex3f( size[0], size[1], 0.1) - glEnd() + glColor4f(0,0,0,0.16) + glDepthMask(False) + for obj in self._scene.objects(): + glPushMatrix() + glTranslatef(obj.getPosition()[0], obj.getPosition()[1], 0) + glBegin(GL_TRIANGLE_FAN) + for p in obj._boundaryHull[::-1]: + glVertex3f(p[0], p[1], 0) + glEnd() + glPopMatrix() + 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) - 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: @@ -1203,7 +1229,7 @@ void main(void) 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 @@ -1217,7 +1243,7 @@ void main(void) size = [profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')] machine = profile.getMachineSetting('machine_type') - if profile.getMachineSetting('machine_type').startswith('ultimaker'): + if machine.startswith('ultimaker'): if machine not in self._platformMesh: meshes = meshLoader.loadMeshes(resources.getPathForMesh(machine + '_platform.stl')) if len(meshes) > 0: @@ -1282,156 +1308,59 @@ void main(void) glVertex3f(-size[0] / 2, -size[1] / 2+10, 0) glEnd() - #Cornerpoints for big blue square - v0 = [ size[0] / 2, size[1] / 2, size[2]] - v1 = [ size[0] / 2,-size[1] / 2, size[2]] - v2 = [-size[0] / 2, size[1] / 2, size[2]] - v3 = [-size[0] / 2,-size[1] / 2, size[2]] - v4 = [ size[0] / 2, size[1] / 2, 0] - v5 = [ size[0] / 2,-size[1] / 2, 0] - v6 = [-size[0] / 2, size[1] / 2, 0] - v7 = [-size[0] / 2,-size[1] / 2, 0] - - vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7] - glEnableClientState(GL_VERTEX_ARRAY) - glVertexPointer(3, GL_FLOAT, 3*4, vList) - - glColor4ub(5, 171, 231, 64) - glDrawArrays(GL_QUADS, 0, 4) - glColor4ub(5, 171, 231, 96) - glDrawArrays(GL_QUADS, 4, 8) + glDepthMask(False) + + 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])): + if not circular: + if n % 2 == 0: + glColor4ub(5, 171, 231, 96) + else: + glColor4ub(5, 171, 231, 64) + else: + 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-1][0], polys[0][n-1][1], height) + glEnd() glColor4ub(5, 171, 231, 128) - glDrawArrays(GL_QUADS, 12, 8) - glDisableClientState(GL_VERTEX_ARRAY) + glBegin(GL_TRIANGLE_FAN) + for p in polys[0][::-1]: + glVertex3f(p[0], p[1], height) + glEnd() #Draw checkerboard - sx = self._machineSize[0] - sy = self._machineSize[1] - for x in xrange(-int(sx/20)-1, int(sx / 20) + 1): - for y in xrange(-int(sx/20)-1, int(sy / 20) + 1): - x1 = x * 10 - x2 = x1 + 10 - y1 = y * 10 - y2 = y1 + 10 - x1 = max(min(x1, sx/2), -sx/2) - y1 = max(min(y1, sy/2), -sy/2) - x2 = max(min(x2, sx/2), -sx/2) - y2 = max(min(y2, sy/2), -sy/2) - #Black or "white" checker - if (x & 1) == (y & 1): - glColor4ub(5, 171, 231, 127) - else: - glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128) - glBegin(GL_QUADS) - glVertex3f(x1, y1, -0.02) - glVertex3f(x2, y1, -0.02) - glVertex3f(x2, y2, -0.02) - glVertex3f(x1, y2, -0.02) - glEnd() - #if UM2, draw bat-area zone for head. THe head can't stop there, because its bat-area. + if self._platformTexture is None: + self._platformTexture = opengl.loadGLTexture('checkerboard.png') + glBindTexture(GL_TEXTURE_2D, self._platformTexture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) + glColor4f(1,1,1,0.5) + glBindTexture(GL_TEXTURE_2D, self._platformTexture) + glEnable(GL_TEXTURE_2D) + glBegin(GL_TRIANGLE_FAN) + for p in polys[0]: + glTexCoord2f(p[0]/20, p[1]/20) + glVertex3f(p[0], p[1], 0) + glEnd() + glDisable(GL_TEXTURE_2D) + glColor4ub(127, 127, 127, 200) + for poly in polys[1:]: + glBegin(GL_TRIANGLE_FAN) + for p in poly: + glTexCoord2f(p[0]/20, p[1]/20) + glVertex3f(p[0], p[1], 0) + glEnd() + + glDepthMask(True) 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]