1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
13 OpenGL.ERROR_CHECKING = False
14 from OpenGL.GLU import *
15 from OpenGL.GL import *
17 from Cura.gui import printWindow
18 from Cura.util import profile
19 from Cura.util import meshLoader
20 from Cura.util import objectScene
21 from Cura.util import resources
22 from Cura.util import sliceEngine
23 from Cura.util import machineCom
24 from Cura.util import removableStorage
25 from Cura.util import gcodeInterpreter
26 from Cura.gui.util import previewTools
27 from Cura.gui.util import opengl
28 from Cura.gui.util import openglGui
30 class SceneView(openglGui.glGuiPanel):
31 def __init__(self, parent):
32 super(SceneView, self).__init__(parent)
37 self._scene = objectScene.Scene()
40 self._gcodeLoadThread = None
41 self._objectShader = None
43 self._selectedObj = None
44 self._objColors = [None,None,None,None]
47 self._mouseState = None
48 self._viewTarget = numpy.array([0,0,0], numpy.float32)
51 self._platformMesh = meshLoader.loadMeshes(resources.getPathForMesh('ultimaker_platform.stl'))[0]
52 self._platformMesh._drawOffset = numpy.array([0,0,2.5], numpy.float32)
53 self._isSimpleMode = True
56 self._modelMatrix = None
57 self._projMatrix = None
58 self.tempMatrix = None
60 self.openFileButton = openglGui.glButton(self, 4, 'Load', (0,0), self.showLoadModel)
61 self.printButton = openglGui.glButton(self, 6, 'Print', (1,0), self.showPrintWindow)
62 self.printButton.setDisabled(True)
65 self.rotateToolButton = openglGui.glRadioButton(self, 8, 'Rotate', (0,-1), group, self.OnToolSelect)
66 self.scaleToolButton = openglGui.glRadioButton(self, 9, 'Scale', (1,-1), group, self.OnToolSelect)
67 self.mirrorToolButton = openglGui.glRadioButton(self, 10, 'Mirror', (2,-1), group, self.OnToolSelect)
69 self.resetRotationButton = openglGui.glButton(self, 12, 'Reset', (0,-2), self.OnRotateReset)
70 self.layFlatButton = openglGui.glButton(self, 16, 'Lay flat', (0,-3), self.OnLayFlat)
72 self.resetScaleButton = openglGui.glButton(self, 13, 'Reset', (1,-2), self.OnScaleReset)
73 self.scaleMaxButton = openglGui.glButton(self, 17, 'To max', (1,-3), self.OnScaleMax)
75 self.mirrorXButton = openglGui.glButton(self, 14, 'Mirror X', (2,-2), lambda button: self.OnMirror(0))
76 self.mirrorYButton = openglGui.glButton(self, 18, 'Mirror Y', (2,-3), lambda button: self.OnMirror(1))
77 self.mirrorZButton = openglGui.glButton(self, 22, 'Mirror Z', (2,-4), lambda button: self.OnMirror(2))
79 self.rotateToolButton.setExpandArrow(True)
80 self.scaleToolButton.setExpandArrow(True)
81 self.mirrorToolButton.setExpandArrow(True)
83 self.scaleForm = openglGui.glFrame(self, (2, -2))
84 openglGui.glGuiLayoutGrid(self.scaleForm)
85 openglGui.glLabel(self.scaleForm, 'Scale X', (0,0))
86 self.scaleXctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,0), lambda value: self.OnScaleEntry(value, 0))
87 openglGui.glLabel(self.scaleForm, 'Scale Y', (0,1))
88 self.scaleYctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,1), lambda value: self.OnScaleEntry(value, 1))
89 openglGui.glLabel(self.scaleForm, 'Scale Z', (0,2))
90 self.scaleZctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,2), lambda value: self.OnScaleEntry(value, 2))
91 openglGui.glLabel(self.scaleForm, 'Size X (mm)', (0,4))
92 self.scaleXmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,4), lambda value: self.OnScaleEntryMM(value, 0))
93 openglGui.glLabel(self.scaleForm, 'Size Y (mm)', (0,5))
94 self.scaleYmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,5), lambda value: self.OnScaleEntryMM(value, 1))
95 openglGui.glLabel(self.scaleForm, 'Size Z (mm)', (0,6))
96 self.scaleZmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,6), lambda value: self.OnScaleEntryMM(value, 2))
97 openglGui.glLabel(self.scaleForm, 'Uniform scale', (0,8))
98 self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None)
100 self.viewSelection = openglGui.glComboButton(self, 'View mode', [7,19,11,15,23], ['Normal', 'Overhang', 'Transparent', 'X-Ray', 'Layers'], (-1,0), self.OnViewChange)
101 self.layerSelect = openglGui.glSlider(self, 100, 0, 100, (-1,-2), lambda : self.QueueRefresh())
103 self.notification = openglGui.glNotification(self, (0, 0))
105 self._slicer = sliceEngine.Slicer(self._updateSliceProgress)
106 self._sceneUpdateTimer = wx.Timer(self)
107 self.Bind(wx.EVT_TIMER, self._onRunSlicer, self._sceneUpdateTimer)
108 self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
112 self.updateToolButtons()
113 self.updateProfileToControls()
115 def showLoadModel(self, button = 1):
117 dlg=wx.FileDialog(self, 'Open 3D model', os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST|wx.FD_MULTIPLE)
118 dlg.SetWildcard(meshLoader.loadWildcardFilter() + "|GCode file (*.gcode)|*.g;*.gcode;*.G;*.GCODE")
119 if dlg.ShowModal() != wx.ID_OK:
122 filenames = dlg.GetPaths()
124 if len(filenames) < 1:
126 profile.putPreference('lastFile', filenames[0])
128 for filename in filenames:
129 self.GetParent().GetParent().GetParent().addToModelMRU(filename)
130 ext = filename[filename.rfind('.')+1:].upper()
131 if ext == 'G' or ext == 'GCODE':
132 gcodeFilename = filename
133 if gcodeFilename is not None:
134 if self._gcode is not None:
136 for layerVBOlist in self._gcodeVBOs:
137 for vbo in layerVBOlist:
138 self.glReleaseList.append(vbo)
140 self._gcode = gcodeInterpreter.gcode()
141 self._gcodeFilename = gcodeFilename
142 self.printButton.setBottomText('')
143 self.viewSelection.setValue(4)
144 self.printButton.setDisabled(False)
147 if self.viewSelection.getValue() == 4:
148 self.viewSelection.setValue(0)
150 self.loadScene(filenames)
152 def showSaveModel(self):
153 if len(self._scene.objects()) < 1:
155 dlg=wx.FileDialog(self, 'Save 3D model', os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
156 dlg.SetWildcard(meshLoader.saveWildcardFilter())
157 if dlg.ShowModal() != wx.ID_OK:
160 filename = dlg.GetPath()
162 meshLoader.saveMeshes(filename, self._scene.objects())
164 def showPrintWindow(self, button):
166 if machineCom.machineIsConnected():
167 printWindow.printFile(self._gcodeFilename)
168 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
169 drives = removableStorage.getPossibleSDcardDrives()
171 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))
172 if dlg.ShowModal() != wx.ID_OK:
175 drive = drives[dlg.GetSelection()]
179 filename = os.path.basename(profile.getPreference('lastFile'))
180 filename = filename[0:filename.rfind('.')] + '.gcode'
181 threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start()
186 self.Bind(wx.EVT_MENU, lambda e: printWindow.printFile(self._gcodeFilename), menu.Append(-1, 'Print with USB'))
187 self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, 'Save GCode...'))
188 self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, 'Slice engine log...'))
192 def showSaveGCode(self):
193 defPath = profile.getPreference('lastFile')
194 defPath = defPath[0:defPath.rfind('.')] + '.gcode'
195 dlg=wx.FileDialog(self, 'Save toolpath', defPath, style=wx.FD_SAVE)
196 dlg.SetFilename(os.path.basename(defPath))
197 dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
198 if dlg.ShowModal() != wx.ID_OK:
201 filename = dlg.GetPath()
204 threading.Thread(target=self._copyFile,args=(self._gcodeFilename, filename)).start()
206 def _copyFile(self, fileA, fileB, allowEject = False):
208 size = float(os.stat(fileA).st_size)
209 with open(fileA, 'rb') as fsrc:
210 with open(fileB, 'wb') as fdst:
212 buf = fsrc.read(16*1024)
216 self.printButton.setProgressBar(float(fsrc.tell()) / size)
221 self.notification.message("Failed to save")
224 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...'))
226 self.notification.message("Saved as %s" % (fileB))
227 self.printButton.setProgressBar(None)
230 def _showSliceLog(self):
231 dlg = wx.TextEntryDialog(self, "The slicing engine reported the following", "Engine log...", '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
235 def OnToolSelect(self, button):
236 if self.rotateToolButton.getSelected():
237 self.tool = previewTools.toolRotate(self)
238 elif self.scaleToolButton.getSelected():
239 self.tool = previewTools.toolScale(self)
240 elif self.mirrorToolButton.getSelected():
241 self.tool = previewTools.toolNone(self)
243 self.tool = previewTools.toolNone(self)
244 self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected())
245 self.layFlatButton.setHidden(not self.rotateToolButton.getSelected())
246 self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected())
247 self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected())
248 self.scaleForm.setHidden(not self.scaleToolButton.getSelected())
249 self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected())
250 self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected())
251 self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected())
253 def updateToolButtons(self):
254 if self._selectedObj is None:
258 self.rotateToolButton.setHidden(hidden)
259 self.scaleToolButton.setHidden(hidden)
260 self.mirrorToolButton.setHidden(hidden)
262 self.rotateToolButton.setSelected(False)
263 self.scaleToolButton.setSelected(False)
264 self.mirrorToolButton.setSelected(False)
267 def OnViewChange(self):
268 if self.viewSelection.getValue() == 4:
269 self.viewMode = 'gcode'
270 if self._gcode is not None and self._gcode.layerList is not None:
271 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
272 self.layerSelect.setValue(len(self._gcode.layerList) - 1)
273 self._selectObject(None)
274 elif self.viewSelection.getValue() == 1:
275 self.viewMode = 'overhang'
276 elif self.viewSelection.getValue() == 2:
277 self.viewMode = 'transparent'
278 elif self.viewSelection.getValue() == 3:
279 self.viewMode = 'xray'
281 self.viewMode = 'normal'
282 self.layerSelect.setHidden(self.viewMode != 'gcode')
285 def OnRotateReset(self, button):
286 if self._selectedObj is None:
288 self._selectedObj.resetRotation()
289 self._scene.pushFree()
290 self._selectObject(self._selectedObj)
293 def OnLayFlat(self, button):
294 if self._selectedObj is None:
296 self._selectedObj.layFlat()
297 self._scene.pushFree()
298 self._selectObject(self._selectedObj)
301 def OnScaleReset(self, button):
302 if self._selectedObj is None:
304 self._selectedObj.resetScale()
305 self._selectObject(self._selectedObj)
306 self.updateProfileToControls()
309 def OnScaleMax(self, button):
310 if self._selectedObj is None:
312 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
313 self._scene.pushFree()
314 self._selectObject(self._selectedObj)
315 self.updateProfileToControls()
318 def OnMirror(self, axis):
319 if self._selectedObj is None:
321 self._selectedObj.mirror(axis)
324 def OnScaleEntry(self, value, axis):
325 if self._selectedObj is None:
331 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
332 self.updateProfileToControls()
333 self._scene.pushFree()
334 self._selectObject(self._selectedObj)
337 def OnScaleEntryMM(self, value, axis):
338 if self._selectedObj is None:
344 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
345 self.updateProfileToControls()
346 self._scene.pushFree()
347 self._selectObject(self._selectedObj)
350 def OnDeleteAll(self, e):
351 while len(self._scene.objects()) > 0:
352 self._deleteObject(self._scene.objects()[0])
353 self._animView = openglGui.animation(self, self._viewTarget.copy(), numpy.array([0,0,0], numpy.float32), 0.5)
355 def OnMultiply(self, e):
356 if self._focusObj is None:
359 dlg = wx.NumberEntryDialog(self, "How many items do you want?", "Copies", "Multiply", 2, 1, 100)
360 if dlg.ShowModal() != wx.ID_OK:
363 cnt = dlg.GetValue() - 1
369 self._scene.add(newObj)
370 self._scene.centerAll()
371 if not self._scene.checkPlatform(newObj):
376 self.notification.message("Could not create more then %d items" % (n))
377 self._scene.remove(newObj)
378 self._scene.centerAll()
381 def OnSplitObject(self, e):
382 if self._focusObj is None:
384 self._scene.remove(self._focusObj)
385 for obj in self._focusObj.split(self._splitCallback):
386 if numpy.max(obj.getSize()) > 2.0:
388 self._scene.centerAll()
389 self._selectObject(None)
392 def _splitCallback(self, progress):
395 def OnMergeObjects(self, e):
396 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
398 self._scene.merge(self._selectedObj, self._focusObj)
401 def sceneUpdated(self):
402 self._sceneUpdateTimer.Start(500, True)
403 self._slicer.abortSlicer()
404 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
407 def _onRunSlicer(self, e):
408 if self._isSimpleMode:
409 self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
410 self._slicer.runSlicer(self._scene)
411 if self._isSimpleMode:
412 profile.resetTempOverride()
414 def _updateSliceProgress(self, progressValue, ready):
415 self.printButton.setDisabled(not ready)
416 if progressValue >= 0.0:
417 self.printButton.setProgressBar(progressValue)
419 self.printButton.setProgressBar(None)
420 if self._gcode is not None:
422 for layerVBOlist in self._gcodeVBOs:
423 for vbo in layerVBOlist:
424 self.glReleaseList.append(vbo)
427 self.printButton.setProgressBar(None)
428 cost = self._slicer.getFilamentCost()
430 self.printButton.setBottomText('%s\n%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount(), cost))
432 self.printButton.setBottomText('%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount()))
433 self._gcode = gcodeInterpreter.gcode()
434 self._gcodeFilename = self._slicer.getGCodeFilename()
436 self.printButton.setBottomText('')
439 def _loadGCode(self):
440 self._gcode.progressCallback = self._gcodeLoadCallback
441 self._gcode.load(self._gcodeFilename)
443 def _gcodeLoadCallback(self, progress):
444 if self._gcode is None:
446 if len(self._gcode.layerList) % 15 == 0:
448 if self._gcode is None:
450 if self.layerSelect.getValue() == self.layerSelect.getMaxValue():
451 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
452 self.layerSelect.setValue(self.layerSelect.getMaxValue())
454 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
455 if self.viewMode == 'gcode':
459 def loadScene(self, fileList):
460 for filename in fileList:
462 objList = meshLoader.loadMeshes(filename)
464 traceback.print_exc()
467 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
469 self._scene.centerAll()
470 self._selectObject(obj)
473 def _deleteObject(self, obj):
474 if obj == self._selectedObj:
475 self._selectObject(None)
476 if obj == self._focusObj:
477 self._focusObj = None
478 self._scene.remove(obj)
479 for m in obj._meshList:
480 if m.vbo is not None and m.vbo.decRef():
481 self.glReleaseList.append(m.vbo)
486 def _selectObject(self, obj, zoom = True):
487 if obj != self._selectedObj:
488 self._selectedObj = obj
489 self.updateProfileToControls()
490 self.updateToolButtons()
491 if zoom and obj is not None:
492 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
493 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
494 newZoom = obj.getBoundaryCircle() * 6
495 if newZoom > numpy.max(self._machineSize) * 3:
496 newZoom = numpy.max(self._machineSize) * 3
497 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
499 def updateProfileToControls(self):
500 oldSimpleMode = self._isSimpleMode
501 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
502 if self._isSimpleMode and not oldSimpleMode:
503 self._scene.arrangeAll()
505 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
506 self._objColors[0] = profile.getPreferenceColour('model_colour')
507 self._objColors[1] = profile.getPreferenceColour('model_colour2')
508 self._objColors[2] = profile.getPreferenceColour('model_colour3')
509 self._objColors[3] = profile.getPreferenceColour('model_colour4')
510 self._scene.setMachineSize(self._machineSize)
511 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
512 self._scene.setHeadSize(profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_min_y'), profile.getPreferenceFloat('extruder_head_size_max_y'), profile.getPreferenceFloat('extruder_head_size_height'))
514 if self._selectedObj is not None:
515 scale = self._selectedObj.getScale()
516 size = self._selectedObj.getSize()
517 self.scaleXctrl.setValue(round(scale[0], 2))
518 self.scaleYctrl.setValue(round(scale[1], 2))
519 self.scaleZctrl.setValue(round(scale[2], 2))
520 self.scaleXmmctrl.setValue(round(size[0], 2))
521 self.scaleYmmctrl.setValue(round(size[1], 2))
522 self.scaleZmmctrl.setValue(round(size[2], 2))
524 def OnKeyChar(self, keyCode):
525 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
526 if self._selectedObj is not None:
527 self._deleteObject(self._selectedObj)
529 if keyCode == wx.WXK_UP:
530 self.layerSelect.setValue(self.layerSelect.getValue() + 1)
532 elif keyCode == wx.WXK_DOWN:
533 self.layerSelect.setValue(self.layerSelect.getValue() - 1)
535 elif keyCode == wx.WXK_PAGEUP:
536 self.layerSelect.setValue(self.layerSelect.getValue() + 10)
538 elif keyCode == wx.WXK_PAGEDOWN:
539 self.layerSelect.setValue(self.layerSelect.getValue() - 10)
542 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
543 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
544 if keyCode == wx.WXK_F4 and wx.GetKeyState(wx.WXK_SHIFT):
545 from collections import defaultdict
546 from gc import get_objects
547 self._beforeLeakTest = defaultdict(int)
548 for i in get_objects():
549 self._beforeLeakTest[type(i)] += 1
550 if keyCode == wx.WXK_F5 and wx.GetKeyState(wx.WXK_SHIFT):
551 from collections import defaultdict
552 from gc import get_objects
553 self._afterLeakTest = defaultdict(int)
554 for i in get_objects():
555 self._afterLeakTest[type(i)] += 1
556 for k in self._afterLeakTest:
557 if self._afterLeakTest[k]-self._beforeLeakTest[k]:
558 print k, self._afterLeakTest[k], self._beforeLeakTest[k], self._afterLeakTest[k] - self._beforeLeakTest[k]
560 def ShaderUpdate(self, v, f):
561 s = opengl.GLShader(v, f)
563 self._objectLoadShader.release()
564 self._objectLoadShader = s
565 for obj in self._scene.objects():
566 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
569 def OnMouseDown(self,e):
570 self._mouseX = e.GetX()
571 self._mouseY = e.GetY()
572 self._mouseClick3DPos = self._mouse3Dpos
573 self._mouseClickFocus = self._focusObj
575 self._mouseState = 'doubleClick'
577 self._mouseState = 'dragOrClick'
578 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
579 p0 -= self.getObjectCenterPos() - self._viewTarget
580 p1 -= self.getObjectCenterPos() - self._viewTarget
581 if self.tool.OnDragStart(p0, p1):
582 self._mouseState = 'tool'
583 if self._mouseState == 'dragOrClick':
584 if e.GetButton() == 1:
585 if self._focusObj is not None:
586 self._selectObject(self._focusObj, False)
589 def OnMouseUp(self, e):
590 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
592 if self._mouseState == 'dragOrClick':
593 if e.GetButton() == 1:
594 self._selectObject(self._focusObj)
595 if e.GetButton() == 3:
597 if self._focusObj is not None:
598 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
599 self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
600 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
601 if self._selectedObj != self._focusObj and self._focusObj is not None and int(profile.getPreference('extruder_amount')) > 1:
602 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
603 if len(self._scene.objects()) > 0:
604 self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
605 if menu.MenuItemCount > 0:
608 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
609 self._scene.pushFree()
611 elif self._mouseState == 'tool':
612 if self.tempMatrix is not None and self._selectedObj is not None:
613 self._selectedObj.applyMatrix(self.tempMatrix)
614 self._scene.pushFree()
615 self._selectObject(self._selectedObj)
616 self.tempMatrix = None
617 self.tool.OnDragEnd()
619 self._mouseState = None
621 def OnMouseMotion(self,e):
622 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
623 p0 -= self.getObjectCenterPos() - self._viewTarget
624 p1 -= self.getObjectCenterPos() - self._viewTarget
626 if e.Dragging() and self._mouseState is not None:
627 if self._mouseState == 'tool':
628 self.tool.OnDrag(p0, p1)
629 elif not e.LeftIsDown() and e.RightIsDown():
630 self._mouseState = 'drag'
631 if wx.GetKeyState(wx.WXK_SHIFT):
632 a = math.cos(math.radians(self._yaw)) / 3.0
633 b = math.sin(math.radians(self._yaw)) / 3.0
634 self._viewTarget[0] += float(e.GetX() - self._mouseX) * -a
635 self._viewTarget[1] += float(e.GetX() - self._mouseX) * b
636 self._viewTarget[0] += float(e.GetY() - self._mouseY) * b
637 self._viewTarget[1] += float(e.GetY() - self._mouseY) * a
639 self._yaw += e.GetX() - self._mouseX
640 self._pitch -= e.GetY() - self._mouseY
641 if self._pitch > 170:
645 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
646 self._mouseState = 'drag'
647 self._zoom += e.GetY() - self._mouseY
650 if self._zoom > numpy.max(self._machineSize) * 3:
651 self._zoom = numpy.max(self._machineSize) * 3
652 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus:
653 self._mouseState = 'dragObject'
654 z = max(0, self._mouseClick3DPos[2])
655 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
656 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
661 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
662 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
663 diff = cursorZ1 - cursorZ0
664 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
665 if not e.Dragging() or self._mouseState != 'tool':
666 self.tool.OnMouseMove(p0, p1)
668 self._mouseX = e.GetX()
669 self._mouseY = e.GetY()
671 def OnMouseWheel(self, e):
672 delta = float(e.GetWheelRotation()) / float(e.GetWheelDelta())
673 delta = max(min(delta,4),-4)
674 self._zoom *= 1.0 - delta / 10.0
677 if self._zoom > numpy.max(self._machineSize) * 3:
678 self._zoom = numpy.max(self._machineSize) * 3
681 def getMouseRay(self, x, y):
682 if self._viewport is None:
683 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
684 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
685 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
686 p0 -= self._viewTarget
687 p1 -= self._viewTarget
690 def _init3DView(self):
691 # set viewing projection
692 size = self.GetSize()
693 glViewport(0, 0, size.GetWidth(), size.GetHeight())
696 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
698 glDisable(GL_RESCALE_NORMAL)
699 glDisable(GL_LIGHTING)
701 glEnable(GL_DEPTH_TEST)
702 glDisable(GL_CULL_FACE)
704 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
706 glClearColor(0.8, 0.8, 0.8, 1.0)
710 glMatrixMode(GL_PROJECTION)
712 aspect = float(size.GetWidth()) / float(size.GetHeight())
713 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
715 glMatrixMode(GL_MODELVIEW)
717 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
720 if machineCom.machineIsConnected():
721 self.printButton._imageID = 6
722 self.printButton._tooltip = 'Print'
723 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
724 self.printButton._imageID = 2
725 self.printButton._tooltip = 'Toolpath to SD'
727 self.printButton._imageID = 3
728 self.printButton._tooltip = 'Save toolpath'
730 if self._animView is not None:
731 self._viewTarget = self._animView.getPosition()
732 if self._animView.isDone():
733 self._animView = None
734 if self._animZoom is not None:
735 self._zoom = self._animZoom.getPosition()
736 if self._animZoom.isDone():
737 self._animZoom = None
738 if self.viewMode == 'gcode' and self._gcode is not None:
740 self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
743 if self._objectShader is None:
744 self._objectShader = opengl.GLShader("""
745 varying float light_amount;
749 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
750 gl_FrontColor = gl_Color;
752 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
756 varying float light_amount;
760 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
763 self._objectOverhangShader = opengl.GLShader("""
764 uniform float cosAngle;
765 uniform mat3 rotMatrix;
766 varying float light_amount;
770 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
771 gl_FrontColor = gl_Color;
773 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
775 if (normalize(rotMatrix * gl_Normal).z < -cosAngle)
777 light_amount = -10.0;
781 varying float light_amount;
785 if (light_amount == -10.0)
787 gl_FragColor = vec4(1.0, 0.0, 0.0, gl_Color[3]);
789 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
793 self._objectLoadShader = opengl.GLShader("""
794 uniform float intensity;
796 varying float light_amount;
800 vec4 tmp = gl_Vertex;
801 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
802 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
803 gl_Position = gl_ModelViewProjectionMatrix * tmp;
804 gl_FrontColor = gl_Color;
806 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
810 uniform float intensity;
811 varying float light_amount;
815 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
819 glTranslate(0,0,-self._zoom)
820 glRotate(-self._pitch, 1,0,0)
821 glRotate(self._yaw, 0,0,1)
822 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
824 self._viewport = glGetIntegerv(GL_VIEWPORT)
825 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
826 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
828 glClearColor(1,1,1,1)
829 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
831 if self.viewMode != 'gcode':
832 for n in xrange(0, len(self._scene.objects())):
833 obj = self._scene.objects()[n]
834 glColor4ub((n >> 16) & 0xFF, (n >> 8) & 0xFF, (n >> 0) & 0xFF, 0xFF)
835 self._renderObject(obj)
837 if self._mouseX > -1:
839 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0] >> 8
840 if n < len(self._scene.objects()):
841 self._focusObj = self._scene.objects()[n]
843 self._focusObj = None
844 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
845 #self.GetTopLevelParent().SetTitle(hex(n) + " " + str(f))
846 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
847 self._mouse3Dpos -= self._viewTarget
850 glTranslate(0,0,-self._zoom)
851 glRotate(-self._pitch, 1,0,0)
852 glRotate(self._yaw, 0,0,1)
853 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
855 if self.viewMode == 'gcode':
856 if self._gcode is not None and self._gcode.layerList is None:
857 self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
858 self._gcodeLoadThread.daemon = True
859 self._gcodeLoadThread.start()
860 if self._gcode is not None and self._gcode.layerList is not None:
862 glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
864 drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
865 for n in xrange(0, drawUpTill):
866 c = 1.0 - float(drawUpTill - n) / 15
868 if len(self._gcodeVBOs) < n + 1:
869 self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
870 if time.time() - t > 0.5:
873 #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
874 if n == drawUpTill - 1:
875 if len(self._gcodeVBOs[n]) < 6:
876 self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
878 self._gcodeVBOs[n][5].render(GL_QUADS)
880 self._gcodeVBOs[n][6].render(GL_QUADS)
881 glColor3f(c/2, c/2, 0.0)
882 self._gcodeVBOs[n][7].render(GL_QUADS)
884 self._gcodeVBOs[n][8].render(GL_QUADS)
885 self._gcodeVBOs[n][9].render(GL_QUADS)
887 self._gcodeVBOs[n][10].render(GL_LINES)
890 self._gcodeVBOs[n][0].render(GL_LINES)
892 self._gcodeVBOs[n][1].render(GL_LINES)
893 glColor3f(c/2, c/2, 0.0)
894 self._gcodeVBOs[n][2].render(GL_LINES)
896 self._gcodeVBOs[n][3].render(GL_LINES)
897 self._gcodeVBOs[n][4].render(GL_LINES)
900 glStencilFunc(GL_ALWAYS, 1, 1)
901 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
903 if self.viewMode == 'overhang':
904 self._objectOverhangShader.bind()
905 self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(60)))
907 self._objectShader.bind()
908 for obj in self._scene.objects():
909 if obj._loadAnim is not None:
910 if obj._loadAnim.isDone():
915 if self._focusObj == obj:
917 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
920 if self._selectedObj == obj or self._selectedObj is None:
921 #If we want transparent, then first render a solid black model to remove the printer size lines.
922 if self.viewMode == 'transparent':
923 glColor4f(0, 0, 0, 0)
924 self._renderObject(obj)
926 glBlendFunc(GL_ONE, GL_ONE)
927 glDisable(GL_DEPTH_TEST)
929 if self.viewMode == 'xray':
930 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
931 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
932 glEnable(GL_STENCIL_TEST)
934 if self.viewMode == 'overhang':
935 if self._selectedObj == obj and self.tempMatrix is not None:
936 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix() * self.tempMatrix)
938 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix())
940 if not self._scene.checkPlatform(obj):
941 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
942 self._renderObject(obj)
944 self._renderObject(obj, brightness)
945 glDisable(GL_STENCIL_TEST)
947 glEnable(GL_DEPTH_TEST)
948 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
950 if self.viewMode == 'xray':
953 glEnable(GL_STENCIL_TEST)
954 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
955 glDisable(GL_DEPTH_TEST)
956 for i in xrange(2, 15, 2):
957 glStencilFunc(GL_EQUAL, i, 0xFF)
958 glColor(float(i)/10, float(i)/10, float(i)/5)
960 glVertex3f(-1000,-1000,-10)
961 glVertex3f( 1000,-1000,-10)
962 glVertex3f( 1000, 1000,-10)
963 glVertex3f(-1000, 1000,-10)
965 for i in xrange(1, 15, 2):
966 glStencilFunc(GL_EQUAL, i, 0xFF)
967 glColor(float(i)/10, 0, 0)
969 glVertex3f(-1000,-1000,-10)
970 glVertex3f( 1000,-1000,-10)
971 glVertex3f( 1000, 1000,-10)
972 glVertex3f(-1000, 1000,-10)
975 glDisable(GL_STENCIL_TEST)
976 glEnable(GL_DEPTH_TEST)
978 self._objectShader.unbind()
980 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
982 self._objectLoadShader.bind()
983 glColor4f(0.2, 0.6, 1.0, 1.0)
984 for obj in self._scene.objects():
985 if obj._loadAnim is None:
987 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
988 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
989 self._renderObject(obj)
990 self._objectLoadShader.unbind()
995 if self.viewMode == 'gcode':
996 if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
997 glDisable(GL_DEPTH_TEST)
1000 glTranslate(0,-4,-10)
1001 glColor4ub(60,60,60,255)
1002 opengl.glDrawStringCenter('Loading toolpath for visualization...')
1005 #Draw the object box-shadow, so you can see where it will collide with other objects.
1006 if self._selectedObj is not None and len(self._scene.objects()) > 1:
1007 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
1009 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
1011 glEnable(GL_CULL_FACE)
1012 glColor4f(0,0,0,0.12)
1014 glVertex3f(-size[0], size[1], 0.1)
1015 glVertex3f(-size[0], -size[1], 0.1)
1016 glVertex3f( size[0], -size[1], 0.1)
1017 glVertex3f( size[0], size[1], 0.1)
1019 glDisable(GL_CULL_FACE)
1022 #Draw the outline of the selected object, on top of everything else except the GUI.
1023 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
1024 glDisable(GL_DEPTH_TEST)
1025 glEnable(GL_CULL_FACE)
1026 glEnable(GL_STENCIL_TEST)
1028 glStencilFunc(GL_EQUAL, 0, 255)
1030 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
1032 glColor4f(1,1,1,0.5)
1033 self._renderObject(self._selectedObj)
1034 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
1036 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
1037 glDisable(GL_STENCIL_TEST)
1038 glDisable(GL_CULL_FACE)
1039 glEnable(GL_DEPTH_TEST)
1041 if self._selectedObj is not None:
1043 pos = self.getObjectCenterPos()
1044 glTranslate(pos[0], pos[1], pos[2])
1048 def _renderObject(self, obj, brightness = False, addSink = True):
1051 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2 - profile.getProfileSettingFloat('object_sink'))
1053 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
1055 if self.tempMatrix is not None and obj == self._selectedObj:
1056 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
1057 glMultMatrixf(tempMatrix)
1059 offset = obj.getDrawOffset()
1060 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
1062 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
1063 glMultMatrixf(tempMatrix)
1066 for m in obj._meshList:
1068 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
1070 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
1075 def _drawMachine(self):
1076 glEnable(GL_CULL_FACE)
1079 if profile.getPreference('machine_type') == 'ultimaker':
1080 glColor4f(1,1,1,0.5)
1081 self._objectShader.bind()
1082 self._renderObject(self._platformMesh, False, False)
1083 self._objectShader.unbind()
1085 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
1086 v0 = [ size[0] / 2, size[1] / 2, size[2]]
1087 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
1088 v2 = [-size[0] / 2, size[1] / 2, size[2]]
1089 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
1090 v4 = [ size[0] / 2, size[1] / 2, 0]
1091 v5 = [ size[0] / 2,-size[1] / 2, 0]
1092 v6 = [-size[0] / 2, size[1] / 2, 0]
1093 v7 = [-size[0] / 2,-size[1] / 2, 0]
1095 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
1096 glEnableClientState(GL_VERTEX_ARRAY)
1097 glVertexPointer(3, GL_FLOAT, 3*4, vList)
1099 glColor4ub(5, 171, 231, 64)
1100 glDrawArrays(GL_QUADS, 0, 4)
1101 glColor4ub(5, 171, 231, 96)
1102 glDrawArrays(GL_QUADS, 4, 8)
1103 glColor4ub(5, 171, 231, 128)
1104 glDrawArrays(GL_QUADS, 12, 8)
1106 sx = self._machineSize[0]
1107 sy = self._machineSize[1]
1108 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
1109 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
1114 x1 = max(min(x1, sx/2), -sx/2)
1115 y1 = max(min(y1, sy/2), -sy/2)
1116 x2 = max(min(x2, sx/2), -sx/2)
1117 y2 = max(min(y2, sy/2), -sy/2)
1118 if (x & 1) == (y & 1):
1119 glColor4ub(5, 171, 231, 127)
1121 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
1123 glVertex3f(x1, y1, -0.02)
1124 glVertex3f(x2, y1, -0.02)
1125 glVertex3f(x2, y2, -0.02)
1126 glVertex3f(x1, y2, -0.02)
1129 glDisableClientState(GL_VERTEX_ARRAY)
1131 glDisable(GL_CULL_FACE)
1133 def _generateGCodeVBOs(self, layer):
1135 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1136 pointList = numpy.zeros((0,3), numpy.float32)
1138 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1140 a = numpy.concatenate((a[:-1], a[1:]), 1)
1141 a = a.reshape((len(a) * 2, 3))
1142 pointList = numpy.concatenate((pointList, a))
1143 ret.append(opengl.GLVBO(pointList))
1146 def _generateGCodeVBOs2(self, layer):
1147 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1148 filamentArea = math.pi * filamentRadius * filamentRadius
1151 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1152 pointList = numpy.zeros((0,3), numpy.float32)
1154 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1156 if extrudeType == 'FILL':
1159 normal = a[1:] - a[:-1]
1160 lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
1161 normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
1164 ePerDist = path['extrusion'][1:] / lens
1165 lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
1167 normal[:,0] *= lineWidth
1168 normal[:,1] *= lineWidth
1170 b = numpy.zeros((len(a)-1, 0), numpy.float32)
1171 b = numpy.concatenate((b, a[1:] + normal), 1)
1172 b = numpy.concatenate((b, a[1:] - normal), 1)
1173 b = numpy.concatenate((b, a[:-1] - normal), 1)
1174 b = numpy.concatenate((b, a[:-1] + normal), 1)
1175 #b = numpy.concatenate((b, a[:-1]), 1)
1176 #b = numpy.concatenate((b, a[:-1]), 1)
1177 b = b.reshape((len(b) * 4, 3))
1180 normal2 = normal[:-1] + normal[1:]
1181 lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
1182 normal2[:,0] /= lens2
1183 normal2[:,1] /= lens2
1184 normal2[:,0] *= lineWidth[:-1]
1185 normal2[:,1] *= lineWidth[:-1]
1187 c = numpy.zeros((len(a)-2, 0), numpy.float32)
1188 c = numpy.concatenate((c, a[1:-1]), 1)
1189 c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1)
1190 c = numpy.concatenate((c, a[1:-1]+normal2), 1)
1191 c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1)
1193 c = numpy.concatenate((c, a[1:-1]), 1)
1194 c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
1195 c = numpy.concatenate((c, a[1:-1]-normal2), 1)
1196 c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
1198 c = c.reshape((len(c) * 8, 3))
1200 pointList = numpy.concatenate((pointList, b, c))
1202 pointList = numpy.concatenate((pointList, b))
1203 ret.append(opengl.GLVBO(pointList))
1205 pointList = numpy.zeros((0,3), numpy.float32)
1207 if path['type'] == 'move':
1208 a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1209 a = numpy.concatenate((a[:-1], a[1:]), 1)
1210 a = a.reshape((len(a) * 2, 3))
1211 pointList = numpy.concatenate((pointList, a))
1212 if path['type'] == 'retract':
1213 a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1214 a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
1215 a = a.reshape((len(a) * 2, 3))
1216 pointList = numpy.concatenate((pointList, a))
1217 ret.append(opengl.GLVBO(pointList))
1221 def getObjectCenterPos(self):
1222 if self._selectedObj is None:
1223 return [0.0, 0.0, 0.0]
1224 pos = self._selectedObj.getPosition()
1225 size = self._selectedObj.getSize()
1226 return [pos[0], pos[1], size[2]/2 - profile.getProfileSettingFloat('object_sink')]
1228 def getObjectBoundaryCircle(self):
1229 if self._selectedObj is None:
1231 return self._selectedObj.getBoundaryCircle()
1233 def getObjectSize(self):
1234 if self._selectedObj is None:
1235 return [0.0, 0.0, 0.0]
1236 return self._selectedObj.getSize()
1238 def getObjectMatrix(self):
1239 if self._selectedObj is None:
1240 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
1241 return self._selectedObj.getMatrix()
1243 class shaderEditor(wx.Dialog):
1244 def __init__(self, parent, callback, v, f):
1245 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
1246 self._callback = callback
1247 s = wx.BoxSizer(wx.VERTICAL)
1249 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
1250 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
1251 s.Add(self._vertex, 1, flag=wx.EXPAND)
1252 s.Add(self._fragment, 1, flag=wx.EXPAND)
1254 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
1255 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
1257 self.SetPosition(self.GetParent().GetPosition())
1258 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
1261 def OnText(self, e):
1262 self._callback(self._vertex.GetValue(), self._fragment.GetValue())