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._gcode.filename)
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._gcode.filename, drive[1] + filename, drive[1])).start()
186 self.Bind(wx.EVT_MENU, lambda e: printWindow.printFile(self._gcode.filename), 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._gcode.filename, 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)
219 self.notification.message("Failed to save")
222 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...'))
224 self.notification.message("Saved as %s" % (fileB))
225 self.printButton.setProgressBar(None)
228 def _showSliceLog(self):
229 dlg = wx.TextEntryDialog(self, "The slicing engine reported the following", "Engine log...", '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
233 def OnToolSelect(self, button):
234 if self.rotateToolButton.getSelected():
235 self.tool = previewTools.toolRotate(self)
236 elif self.scaleToolButton.getSelected():
237 self.tool = previewTools.toolScale(self)
238 elif self.mirrorToolButton.getSelected():
239 self.tool = previewTools.toolNone(self)
241 self.tool = previewTools.toolNone(self)
242 self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected())
243 self.layFlatButton.setHidden(not self.rotateToolButton.getSelected())
244 self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected())
245 self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected())
246 self.scaleForm.setHidden(not self.scaleToolButton.getSelected())
247 self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected())
248 self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected())
249 self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected())
251 def updateToolButtons(self):
252 if self._selectedObj is None:
256 self.rotateToolButton.setHidden(hidden)
257 self.scaleToolButton.setHidden(hidden)
258 self.mirrorToolButton.setHidden(hidden)
260 self.rotateToolButton.setSelected(False)
261 self.scaleToolButton.setSelected(False)
262 self.mirrorToolButton.setSelected(False)
265 def OnViewChange(self):
266 if self.viewSelection.getValue() == 4:
267 self.viewMode = 'gcode'
268 if self._gcode is not None and self._gcode.layerList is not None:
269 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
270 self.layerSelect.setValue(len(self._gcode.layerList) - 1)
271 self._selectObject(None)
272 elif self.viewSelection.getValue() == 1:
273 self.viewMode = 'overhang'
274 elif self.viewSelection.getValue() == 2:
275 self.viewMode = 'transparent'
276 elif self.viewSelection.getValue() == 3:
277 self.viewMode = 'xray'
279 self.viewMode = 'normal'
280 self.layerSelect.setHidden(self.viewMode != 'gcode')
283 def OnRotateReset(self, button):
284 if self._selectedObj is None:
286 self._selectedObj.resetRotation()
287 self._scene.pushFree()
288 self._selectObject(self._selectedObj)
291 def OnLayFlat(self, button):
292 if self._selectedObj is None:
294 self._selectedObj.layFlat()
295 self._scene.pushFree()
296 self._selectObject(self._selectedObj)
299 def OnScaleReset(self, button):
300 if self._selectedObj is None:
302 self._selectedObj.resetScale()
303 self._selectObject(self._selectedObj)
304 self.updateProfileToControls()
307 def OnScaleMax(self, button):
308 if self._selectedObj is None:
310 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2)
311 self._scene.pushFree()
312 self._selectObject(self._selectedObj)
313 self.updateProfileToControls()
316 def OnMirror(self, axis):
317 if self._selectedObj is None:
319 self._selectedObj.mirror(axis)
322 def OnScaleEntry(self, value, axis):
323 if self._selectedObj is None:
329 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
330 self.updateProfileToControls()
331 self._scene.pushFree()
332 self._selectObject(self._selectedObj)
335 def OnScaleEntryMM(self, value, axis):
336 if self._selectedObj is None:
342 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
343 self.updateProfileToControls()
344 self._scene.pushFree()
345 self._selectObject(self._selectedObj)
348 def OnDeleteAll(self, e):
349 while len(self._scene.objects()) > 0:
350 self._deleteObject(self._scene.objects()[0])
351 self._animView = openglGui.animation(self, self._viewTarget.copy(), numpy.array([0,0,0], numpy.float32), 0.5)
353 def OnMultiply(self, e):
354 if self._focusObj is None:
357 dlg = wx.NumberEntryDialog(self, "How many items do you want?", "Copies", "Multiply", 2, 1, 100)
358 if dlg.ShowModal() != wx.ID_OK:
361 cnt = dlg.GetValue() - 1
367 self._scene.add(newObj)
368 self._scene.centerAll()
369 if not self._scene.checkPlatform(newObj):
374 self.notification.message("Could not create more then %d items" % (n))
375 self._scene.remove(newObj)
376 self._scene.centerAll()
379 def OnSplitObject(self, e):
380 if self._focusObj is None:
382 self._scene.remove(self._focusObj)
383 for obj in self._focusObj.split(self._splitCallback):
385 self._scene.centerAll()
386 self._selectObject(None)
389 def _splitCallback(self, progress):
392 def OnMergeObjects(self, e):
393 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
395 self._scene.merge(self._selectedObj, self._focusObj)
398 def sceneUpdated(self):
399 self._sceneUpdateTimer.Start(500, True)
400 self._slicer.abortSlicer()
401 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
404 def _onRunSlicer(self, e):
405 if self._isSimpleMode:
406 self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
407 self._slicer.runSlicer(self._scene)
408 if self._isSimpleMode:
409 profile.resetTempOverride()
411 def _updateSliceProgress(self, progressValue, ready):
412 self.printButton.setDisabled(not ready)
413 if progressValue >= 0.0:
414 self.printButton.setProgressBar(progressValue)
416 self.printButton.setProgressBar(None)
417 if self._gcode is not None:
419 for layerVBOlist in self._gcodeVBOs:
420 for vbo in layerVBOlist:
421 self.glReleaseList.append(vbo)
424 self.printButton.setProgressBar(None)
425 cost = self._slicer.getFilamentCost()
427 self.printButton.setBottomText('%s\n%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount(), cost))
429 self.printButton.setBottomText('%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount()))
430 self._gcode = gcodeInterpreter.gcode()
431 self._gcodeFilename = self._slicer.getGCodeFilename()
433 self.printButton.setBottomText('')
436 def _loadGCode(self):
437 self._gcode.progressCallback = self._gcodeLoadCallback
438 self._gcode.load(self._gcodeFilename)
440 def _gcodeLoadCallback(self, progress):
441 if self._gcode is None:
443 if len(self._gcode.layerList) % 15 == 0:
445 if self._gcode is None:
447 if self.layerSelect.getValue() == self.layerSelect.getMaxValue():
448 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
449 self.layerSelect.setValue(self.layerSelect.getMaxValue())
451 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
452 if self.viewMode == 'gcode':
456 def loadScene(self, fileList):
457 for filename in fileList:
459 objList = meshLoader.loadMeshes(filename)
461 traceback.print_exc()
464 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
466 self._scene.centerAll()
467 self._selectObject(obj)
470 def _deleteObject(self, obj):
471 if obj == self._selectedObj:
472 self._selectObject(None)
473 if obj == self._focusObj:
474 self._focusObj = None
475 self._scene.remove(obj)
476 for m in obj._meshList:
477 if m.vbo is not None and m.vbo.decRef():
478 self.glReleaseList.append(m.vbo)
483 def _selectObject(self, obj, zoom = True):
484 if obj != self._selectedObj:
485 self._selectedObj = obj
486 self.updateProfileToControls()
487 self.updateToolButtons()
488 if zoom and obj is not None:
489 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
490 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
491 newZoom = obj.getBoundaryCircle() * 6
492 if newZoom > numpy.max(self._machineSize) * 3:
493 newZoom = numpy.max(self._machineSize) * 3
494 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
496 def updateProfileToControls(self):
497 oldSimpleMode = self._isSimpleMode
498 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
499 if self._isSimpleMode and not oldSimpleMode:
500 self._scene.arrangeAll()
502 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
503 self._objColors[0] = profile.getPreferenceColour('model_colour')
504 self._objColors[1] = profile.getPreferenceColour('model_colour2')
505 self._objColors[2] = profile.getPreferenceColour('model_colour3')
506 self._objColors[3] = profile.getPreferenceColour('model_colour4')
507 self._scene.setMachineSize(self._machineSize)
508 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
509 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'))
511 if self._selectedObj is not None:
512 scale = self._selectedObj.getScale()
513 size = self._selectedObj.getSize()
514 self.scaleXctrl.setValue(round(scale[0], 2))
515 self.scaleYctrl.setValue(round(scale[1], 2))
516 self.scaleZctrl.setValue(round(scale[2], 2))
517 self.scaleXmmctrl.setValue(round(size[0], 2))
518 self.scaleYmmctrl.setValue(round(size[1], 2))
519 self.scaleZmmctrl.setValue(round(size[2], 2))
521 def OnKeyChar(self, keyCode):
522 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
523 if self._selectedObj is not None:
524 self._deleteObject(self._selectedObj)
526 if keyCode == wx.WXK_UP:
527 self.layerSelect.setValue(self.layerSelect.getValue() + 1)
529 elif keyCode == wx.WXK_DOWN:
530 self.layerSelect.setValue(self.layerSelect.getValue() - 1)
532 elif keyCode == wx.WXK_PAGEUP:
533 self.layerSelect.setValue(self.layerSelect.getValue() + 10)
535 elif keyCode == wx.WXK_PAGEDOWN:
536 self.layerSelect.setValue(self.layerSelect.getValue() - 10)
539 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
540 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
541 if keyCode == wx.WXK_F4 and wx.GetKeyState(wx.WXK_SHIFT):
542 from collections import defaultdict
543 from gc import get_objects
544 self._beforeLeakTest = defaultdict(int)
545 for i in get_objects():
546 self._beforeLeakTest[type(i)] += 1
547 if keyCode == wx.WXK_F5 and wx.GetKeyState(wx.WXK_SHIFT):
548 from collections import defaultdict
549 from gc import get_objects
550 self._afterLeakTest = defaultdict(int)
551 for i in get_objects():
552 self._afterLeakTest[type(i)] += 1
553 for k in self._afterLeakTest:
554 if self._afterLeakTest[k]-self._beforeLeakTest[k]:
555 print k, self._afterLeakTest[k], self._beforeLeakTest[k], self._afterLeakTest[k] - self._beforeLeakTest[k]
557 def ShaderUpdate(self, v, f):
558 s = opengl.GLShader(v, f)
560 self._objectLoadShader.release()
561 self._objectLoadShader = s
562 for obj in self._scene.objects():
563 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
566 def OnMouseDown(self,e):
567 self._mouseX = e.GetX()
568 self._mouseY = e.GetY()
569 self._mouseClick3DPos = self._mouse3Dpos
570 self._mouseClickFocus = self._focusObj
572 self._mouseState = 'doubleClick'
574 self._mouseState = 'dragOrClick'
575 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
576 p0 -= self.getObjectCenterPos() - self._viewTarget
577 p1 -= self.getObjectCenterPos() - self._viewTarget
578 if self.tool.OnDragStart(p0, p1):
579 self._mouseState = 'tool'
580 if self._mouseState == 'dragOrClick':
581 if e.GetButton() == 1:
582 if self._focusObj is not None:
583 self._selectObject(self._focusObj, False)
586 def OnMouseUp(self, e):
587 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
589 if self._mouseState == 'dragOrClick':
590 if e.GetButton() == 1:
591 self._selectObject(self._focusObj)
592 if e.GetButton() == 3:
594 if self._focusObj is not None:
595 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
596 self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
597 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
598 if self._selectedObj != self._focusObj and self._focusObj is not None and int(profile.getPreference('extruder_amount')) > 1:
599 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
600 if len(self._scene.objects()) > 0:
601 self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
602 if menu.MenuItemCount > 0:
605 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
606 self._scene.pushFree()
608 elif self._mouseState == 'tool':
609 if self.tempMatrix is not None and self._selectedObj is not None:
610 self._selectedObj.applyMatrix(self.tempMatrix)
611 self._scene.pushFree()
612 self._selectObject(self._selectedObj)
613 self.tempMatrix = None
614 self.tool.OnDragEnd()
616 self._mouseState = None
618 def OnMouseMotion(self,e):
619 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
620 p0 -= self.getObjectCenterPos() - self._viewTarget
621 p1 -= self.getObjectCenterPos() - self._viewTarget
623 if e.Dragging() and self._mouseState is not None:
624 if self._mouseState == 'tool':
625 self.tool.OnDrag(p0, p1)
626 elif not e.LeftIsDown() and e.RightIsDown():
627 self._mouseState = 'drag'
628 if wx.GetKeyState(wx.WXK_SHIFT):
629 a = math.cos(math.radians(self._yaw)) / 3.0
630 b = math.sin(math.radians(self._yaw)) / 3.0
631 self._viewTarget[0] += float(e.GetX() - self._mouseX) * -a
632 self._viewTarget[1] += float(e.GetX() - self._mouseX) * b
633 self._viewTarget[0] += float(e.GetY() - self._mouseY) * b
634 self._viewTarget[1] += float(e.GetY() - self._mouseY) * a
636 self._yaw += e.GetX() - self._mouseX
637 self._pitch -= e.GetY() - self._mouseY
638 if self._pitch > 170:
642 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
643 self._mouseState = 'drag'
644 self._zoom += e.GetY() - self._mouseY
647 if self._zoom > numpy.max(self._machineSize) * 3:
648 self._zoom = numpy.max(self._machineSize) * 3
649 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus:
650 self._mouseState = 'dragObject'
651 z = max(0, self._mouseClick3DPos[2])
652 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
653 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
658 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
659 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
660 diff = cursorZ1 - cursorZ0
661 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
662 if not e.Dragging() or self._mouseState != 'tool':
663 self.tool.OnMouseMove(p0, p1)
665 self._mouseX = e.GetX()
666 self._mouseY = e.GetY()
668 def OnMouseWheel(self, e):
669 delta = float(e.GetWheelRotation()) / float(e.GetWheelDelta())
670 delta = max(min(delta,4),-4)
671 self._zoom *= 1.0 - delta / 10.0
674 if self._zoom > numpy.max(self._machineSize) * 3:
675 self._zoom = numpy.max(self._machineSize) * 3
678 def getMouseRay(self, x, y):
679 if self._viewport is None:
680 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
681 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
682 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
683 p0 -= self._viewTarget
684 p1 -= self._viewTarget
687 def _init3DView(self):
688 # set viewing projection
689 size = self.GetSize()
690 glViewport(0, 0, size.GetWidth(), size.GetHeight())
693 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
695 glDisable(GL_RESCALE_NORMAL)
696 glDisable(GL_LIGHTING)
698 glEnable(GL_DEPTH_TEST)
699 glDisable(GL_CULL_FACE)
701 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
703 glClearColor(0.8, 0.8, 0.8, 1.0)
707 glMatrixMode(GL_PROJECTION)
709 aspect = float(size.GetWidth()) / float(size.GetHeight())
710 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
712 glMatrixMode(GL_MODELVIEW)
714 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
717 if machineCom.machineIsConnected():
718 self.printButton._imageID = 6
719 self.printButton._tooltip = 'Print'
720 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
721 self.printButton._imageID = 2
722 self.printButton._tooltip = 'Toolpath to SD'
724 self.printButton._imageID = 3
725 self.printButton._tooltip = 'Save toolpath'
727 if self._animView is not None:
728 self._viewTarget = self._animView.getPosition()
729 if self._animView.isDone():
730 self._animView = None
731 if self._animZoom is not None:
732 self._zoom = self._animZoom.getPosition()
733 if self._animZoom.isDone():
734 self._animZoom = None
735 if self.viewMode == 'gcode' and self._gcode is not None:
737 self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
740 if self._objectShader is None:
741 self._objectShader = opengl.GLShader("""
742 varying float light_amount;
746 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
747 gl_FrontColor = gl_Color;
749 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
753 varying float light_amount;
757 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
760 self._objectOverhangShader = opengl.GLShader("""
761 uniform float cosAngle;
762 uniform mat3 rotMatrix;
763 varying float light_amount;
767 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
768 gl_FrontColor = gl_Color;
770 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
772 if (normalize(rotMatrix * gl_Normal).z < -cosAngle)
774 light_amount = -10.0;
778 varying float light_amount;
782 if (light_amount == -10.0)
784 gl_FragColor = vec4(1.0, 0.0, 0.0, gl_Color[3]);
786 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
790 self._objectLoadShader = opengl.GLShader("""
791 uniform float intensity;
793 varying float light_amount;
797 vec4 tmp = gl_Vertex;
798 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
799 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
800 gl_Position = gl_ModelViewProjectionMatrix * tmp;
801 gl_FrontColor = gl_Color;
803 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
807 uniform float intensity;
808 varying float light_amount;
812 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
816 glTranslate(0,0,-self._zoom)
817 glRotate(-self._pitch, 1,0,0)
818 glRotate(self._yaw, 0,0,1)
819 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
821 self._viewport = glGetIntegerv(GL_VIEWPORT)
822 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
823 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
825 glClearColor(1,1,1,1)
826 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
828 if self.viewMode != 'gcode':
829 for n in xrange(0, len(self._scene.objects())):
830 obj = self._scene.objects()[n]
831 glColor4ub((n >> 16) & 0xFF, (n >> 8) & 0xFF, (n >> 0) & 0xFF, 0xFF)
832 self._renderObject(obj)
834 if self._mouseX > -1:
836 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0] >> 8
837 if n < len(self._scene.objects()):
838 self._focusObj = self._scene.objects()[n]
840 self._focusObj = None
841 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
842 #self.GetTopLevelParent().SetTitle(hex(n) + " " + str(f))
843 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
844 self._mouse3Dpos -= self._viewTarget
847 glTranslate(0,0,-self._zoom)
848 glRotate(-self._pitch, 1,0,0)
849 glRotate(self._yaw, 0,0,1)
850 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
852 if self.viewMode == 'gcode':
853 if self._gcode is not None and self._gcode.layerList is None:
854 self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
855 self._gcodeLoadThread.daemon = True
856 self._gcodeLoadThread.start()
857 if self._gcode is not None and self._gcode.layerList is not None:
859 glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
861 drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
862 for n in xrange(0, drawUpTill):
863 c = 1.0 - float(drawUpTill - n) / 15
865 if len(self._gcodeVBOs) < n + 1:
866 self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
867 if time.time() - t > 0.5:
870 #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
871 if n == drawUpTill - 1:
872 if len(self._gcodeVBOs[n]) < 6:
873 self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
875 self._gcodeVBOs[n][5].render(GL_QUADS)
877 self._gcodeVBOs[n][6].render(GL_QUADS)
878 glColor3f(c/2, c/2, 0.0)
879 self._gcodeVBOs[n][7].render(GL_QUADS)
881 self._gcodeVBOs[n][8].render(GL_QUADS)
882 self._gcodeVBOs[n][9].render(GL_QUADS)
884 self._gcodeVBOs[n][10].render(GL_LINES)
887 self._gcodeVBOs[n][0].render(GL_LINES)
889 self._gcodeVBOs[n][1].render(GL_LINES)
890 glColor3f(c/2, c/2, 0.0)
891 self._gcodeVBOs[n][2].render(GL_LINES)
893 self._gcodeVBOs[n][3].render(GL_LINES)
894 self._gcodeVBOs[n][4].render(GL_LINES)
897 glStencilFunc(GL_ALWAYS, 1, 1)
898 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
900 if self.viewMode == 'overhang':
901 self._objectOverhangShader.bind()
902 self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(60)))
904 self._objectShader.bind()
905 for obj in self._scene.objects():
906 if obj._loadAnim is not None:
907 if obj._loadAnim.isDone():
912 if self._focusObj == obj:
914 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
917 if self._selectedObj == obj or self._selectedObj is None:
918 #If we want transparent, then first render a solid black model to remove the printer size lines.
919 if self.viewMode == 'transparent':
920 glColor4f(0, 0, 0, 0)
921 self._renderObject(obj)
923 glBlendFunc(GL_ONE, GL_ONE)
924 glDisable(GL_DEPTH_TEST)
926 if self.viewMode == 'xray':
927 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
928 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
929 glEnable(GL_STENCIL_TEST)
931 if self.viewMode == 'overhang':
932 if self._selectedObj == obj and self.tempMatrix is not None:
933 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix() * self.tempMatrix)
935 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix())
937 if not self._scene.checkPlatform(obj):
938 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
939 self._renderObject(obj)
941 self._renderObject(obj, brightness)
942 glDisable(GL_STENCIL_TEST)
944 glEnable(GL_DEPTH_TEST)
945 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
947 if self.viewMode == 'xray':
950 glEnable(GL_STENCIL_TEST)
951 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
952 glDisable(GL_DEPTH_TEST)
953 for i in xrange(2, 15, 2):
954 glStencilFunc(GL_EQUAL, i, 0xFF)
955 glColor(float(i)/10, float(i)/10, float(i)/5)
957 glVertex3f(-1000,-1000,-10)
958 glVertex3f( 1000,-1000,-10)
959 glVertex3f( 1000, 1000,-10)
960 glVertex3f(-1000, 1000,-10)
962 for i in xrange(1, 15, 2):
963 glStencilFunc(GL_EQUAL, i, 0xFF)
964 glColor(float(i)/10, 0, 0)
966 glVertex3f(-1000,-1000,-10)
967 glVertex3f( 1000,-1000,-10)
968 glVertex3f( 1000, 1000,-10)
969 glVertex3f(-1000, 1000,-10)
972 glDisable(GL_STENCIL_TEST)
973 glEnable(GL_DEPTH_TEST)
975 self._objectShader.unbind()
977 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
979 self._objectLoadShader.bind()
980 glColor4f(0.2, 0.6, 1.0, 1.0)
981 for obj in self._scene.objects():
982 if obj._loadAnim is None:
984 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
985 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
986 self._renderObject(obj)
987 self._objectLoadShader.unbind()
992 if self.viewMode == 'gcode':
993 if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
994 glDisable(GL_DEPTH_TEST)
997 glTranslate(0,-4,-10)
998 glColor4ub(60,60,60,255)
999 opengl.glDrawStringCenter('Loading toolpath for visualization...')
1002 #Draw the object box-shadow, so you can see where it will collide with other objects.
1003 if self._selectedObj is not None and len(self._scene.objects()) > 1:
1004 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
1006 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
1008 glEnable(GL_CULL_FACE)
1009 glColor4f(0,0,0,0.12)
1011 glVertex3f(-size[0], size[1], 0.1)
1012 glVertex3f(-size[0], -size[1], 0.1)
1013 glVertex3f( size[0], -size[1], 0.1)
1014 glVertex3f( size[0], size[1], 0.1)
1016 glDisable(GL_CULL_FACE)
1019 #Draw the outline of the selected object, on top of everything else except the GUI.
1020 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
1021 glDisable(GL_DEPTH_TEST)
1022 glEnable(GL_CULL_FACE)
1023 glEnable(GL_STENCIL_TEST)
1025 glStencilFunc(GL_EQUAL, 0, 255)
1027 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
1029 glColor4f(1,1,1,0.5)
1030 self._renderObject(self._selectedObj)
1031 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
1033 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
1034 glDisable(GL_STENCIL_TEST)
1035 glDisable(GL_CULL_FACE)
1036 glEnable(GL_DEPTH_TEST)
1038 if self._selectedObj is not None:
1040 pos = self.getObjectCenterPos()
1041 glTranslate(pos[0], pos[1], pos[2])
1045 def _renderObject(self, obj, brightness = False, addSink = True):
1048 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2 - profile.getProfileSettingFloat('object_sink'))
1050 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
1052 if self.tempMatrix is not None and obj == self._selectedObj:
1053 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
1054 glMultMatrixf(tempMatrix)
1056 offset = obj.getDrawOffset()
1057 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
1059 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
1060 glMultMatrixf(tempMatrix)
1063 for m in obj._meshList:
1065 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
1067 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
1072 def _drawMachine(self):
1073 glEnable(GL_CULL_FACE)
1076 if profile.getPreference('machine_type') == 'ultimaker':
1077 glColor4f(1,1,1,0.5)
1078 self._objectShader.bind()
1079 self._renderObject(self._platformMesh, False, False)
1080 self._objectShader.unbind()
1082 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
1083 v0 = [ size[0] / 2, size[1] / 2, size[2]]
1084 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
1085 v2 = [-size[0] / 2, size[1] / 2, size[2]]
1086 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
1087 v4 = [ size[0] / 2, size[1] / 2, 0]
1088 v5 = [ size[0] / 2,-size[1] / 2, 0]
1089 v6 = [-size[0] / 2, size[1] / 2, 0]
1090 v7 = [-size[0] / 2,-size[1] / 2, 0]
1092 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
1093 glEnableClientState(GL_VERTEX_ARRAY)
1094 glVertexPointer(3, GL_FLOAT, 3*4, vList)
1096 glColor4ub(5, 171, 231, 64)
1097 glDrawArrays(GL_QUADS, 0, 4)
1098 glColor4ub(5, 171, 231, 96)
1099 glDrawArrays(GL_QUADS, 4, 8)
1100 glColor4ub(5, 171, 231, 128)
1101 glDrawArrays(GL_QUADS, 12, 8)
1103 sx = self._machineSize[0]
1104 sy = self._machineSize[1]
1105 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
1106 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
1111 x1 = max(min(x1, sx/2), -sx/2)
1112 y1 = max(min(y1, sy/2), -sy/2)
1113 x2 = max(min(x2, sx/2), -sx/2)
1114 y2 = max(min(y2, sy/2), -sy/2)
1115 if (x & 1) == (y & 1):
1116 glColor4ub(5, 171, 231, 127)
1118 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
1120 glVertex3f(x1, y1, -0.02)
1121 glVertex3f(x2, y1, -0.02)
1122 glVertex3f(x2, y2, -0.02)
1123 glVertex3f(x1, y2, -0.02)
1126 glDisableClientState(GL_VERTEX_ARRAY)
1128 glDisable(GL_CULL_FACE)
1130 def _generateGCodeVBOs(self, layer):
1132 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1133 pointList = numpy.zeros((0,3), numpy.float32)
1135 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1137 a = numpy.concatenate((a[:-1], a[1:]), 1)
1138 a = a.reshape((len(a) * 2, 3))
1139 pointList = numpy.concatenate((pointList, a))
1140 ret.append(opengl.GLVBO(pointList))
1143 def _generateGCodeVBOs2(self, layer):
1144 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1145 filamentArea = math.pi * filamentRadius * filamentRadius
1148 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1149 pointList = numpy.zeros((0,3), numpy.float32)
1151 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1153 if extrudeType == 'FILL':
1156 normal = a[1:] - a[:-1]
1157 lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
1158 normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
1161 ePerDist = path['extrusion'][1:] / lens
1162 lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
1164 normal[:,0] *= lineWidth
1165 normal[:,1] *= lineWidth
1167 b = numpy.zeros((len(a)-1, 0), numpy.float32)
1168 b = numpy.concatenate((b, a[1:] + normal), 1)
1169 b = numpy.concatenate((b, a[1:] - normal), 1)
1170 b = numpy.concatenate((b, a[:-1] - normal), 1)
1171 b = numpy.concatenate((b, a[:-1] + normal), 1)
1172 #b = numpy.concatenate((b, a[:-1]), 1)
1173 #b = numpy.concatenate((b, a[:-1]), 1)
1174 b = b.reshape((len(b) * 4, 3))
1177 normal2 = normal[:-1] + normal[1:]
1178 lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
1179 normal2[:,0] /= lens2
1180 normal2[:,1] /= lens2
1181 normal2[:,0] *= lineWidth[:-1]
1182 normal2[:,1] *= lineWidth[:-1]
1184 c = numpy.zeros((len(a)-2, 0), numpy.float32)
1185 c = numpy.concatenate((c, a[1:-1]), 1)
1186 c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1)
1187 c = numpy.concatenate((c, a[1:-1]+normal2), 1)
1188 c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1)
1190 c = numpy.concatenate((c, a[1:-1]), 1)
1191 c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
1192 c = numpy.concatenate((c, a[1:-1]-normal2), 1)
1193 c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
1195 c = c.reshape((len(c) * 8, 3))
1197 pointList = numpy.concatenate((pointList, b, c))
1199 pointList = numpy.concatenate((pointList, b))
1200 ret.append(opengl.GLVBO(pointList))
1202 pointList = numpy.zeros((0,3), numpy.float32)
1204 if path['type'] == 'move':
1205 a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1206 a = numpy.concatenate((a[:-1], a[1:]), 1)
1207 a = a.reshape((len(a) * 2, 3))
1208 pointList = numpy.concatenate((pointList, a))
1209 # if path['type'] == 'retract':
1210 # a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1211 # a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,0.3], numpy.float32)), 1)
1212 # a = a.reshape((len(a) * 2, 3))
1213 # pointList = numpy.concatenate((pointList, a))
1214 ret.append(opengl.GLVBO(pointList))
1218 def getObjectCenterPos(self):
1219 if self._selectedObj is None:
1220 return [0.0, 0.0, 0.0]
1221 pos = self._selectedObj.getPosition()
1222 size = self._selectedObj.getSize()
1223 return [pos[0], pos[1], size[2]/2 - profile.getProfileSettingFloat('object_sink')]
1225 def getObjectBoundaryCircle(self):
1226 if self._selectedObj is None:
1228 return self._selectedObj.getBoundaryCircle()
1230 def getObjectSize(self):
1231 if self._selectedObj is None:
1232 return [0.0, 0.0, 0.0]
1233 return self._selectedObj.getSize()
1235 def getObjectMatrix(self):
1236 if self._selectedObj is None:
1237 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
1238 return self._selectedObj.getMatrix()
1240 class shaderEditor(wx.Dialog):
1241 def __init__(self, parent, callback, v, f):
1242 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
1243 self._callback = callback
1244 s = wx.BoxSizer(wx.VERTICAL)
1246 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
1247 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
1248 s.Add(self._vertex, 1, flag=wx.EXPAND)
1249 s.Add(self._fragment, 1, flag=wx.EXPAND)
1251 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
1252 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
1254 self.SetPosition(self.GetParent().GetPosition())
1255 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
1258 def OnText(self, e):
1259 self._callback(self._vertex.GetValue(), self._fragment.GetValue())