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 if self._gcodeFilename == self._slicer.getGCodeFilename():
169 self._slicer.submitSliceInfoOnline()
170 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
171 drives = removableStorage.getPossibleSDcardDrives()
173 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))
174 if dlg.ShowModal() != wx.ID_OK:
177 drive = drives[dlg.GetSelection()]
181 filename = self._scene._objectList[0].getName() + '.gcode'
182 threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start()
187 self.Bind(wx.EVT_MENU, lambda e: printWindow.printFile(self._gcodeFilename), menu.Append(-1, 'Print with USB'))
188 self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, 'Save GCode...'))
189 self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, 'Slice engine log...'))
193 def showSaveGCode(self):
194 defPath = profile.getPreference('lastFile')
195 defPath = defPath[0:defPath.rfind('.')] + '.gcode'
196 dlg=wx.FileDialog(self, 'Save toolpath', defPath, style=wx.FD_SAVE)
197 dlg.SetFilename(self._scene._objectList[0].getName())
198 dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
199 if dlg.ShowModal() != wx.ID_OK:
202 filename = dlg.GetPath()
205 threading.Thread(target=self._copyFile,args=(self._gcodeFilename, filename)).start()
207 def _copyFile(self, fileA, fileB, allowEject = False):
209 size = float(os.stat(fileA).st_size)
210 with open(fileA, 'rb') as fsrc:
211 with open(fileB, 'wb') as fdst:
213 buf = fsrc.read(16*1024)
217 self.printButton.setProgressBar(float(fsrc.tell()) / size)
222 self.notification.message("Failed to save")
225 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...'))
227 self.notification.message("Saved as %s" % (fileB))
228 self.printButton.setProgressBar(None)
229 if fileA == self._slicer.getGCodeFilename():
230 self._slicer.submitSliceInfoOnline()
232 def _showSliceLog(self):
233 dlg = wx.TextEntryDialog(self, "The slicing engine reported the following", "Engine log...", '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
237 def OnToolSelect(self, button):
238 if self.rotateToolButton.getSelected():
239 self.tool = previewTools.toolRotate(self)
240 elif self.scaleToolButton.getSelected():
241 self.tool = previewTools.toolScale(self)
242 elif self.mirrorToolButton.getSelected():
243 self.tool = previewTools.toolNone(self)
245 self.tool = previewTools.toolNone(self)
246 self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected())
247 self.layFlatButton.setHidden(not self.rotateToolButton.getSelected())
248 self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected())
249 self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected())
250 self.scaleForm.setHidden(not self.scaleToolButton.getSelected())
251 self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected())
252 self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected())
253 self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected())
255 def updateToolButtons(self):
256 if self._selectedObj is None:
260 self.rotateToolButton.setHidden(hidden)
261 self.scaleToolButton.setHidden(hidden)
262 self.mirrorToolButton.setHidden(hidden)
264 self.rotateToolButton.setSelected(False)
265 self.scaleToolButton.setSelected(False)
266 self.mirrorToolButton.setSelected(False)
269 def OnViewChange(self):
270 if self.viewSelection.getValue() == 4:
271 self.viewMode = 'gcode'
272 if self._gcode is not None and self._gcode.layerList is not None:
273 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
274 self.layerSelect.setValue(len(self._gcode.layerList) - 1)
275 self._selectObject(None)
276 elif self.viewSelection.getValue() == 1:
277 self.viewMode = 'overhang'
278 elif self.viewSelection.getValue() == 2:
279 self.viewMode = 'transparent'
280 elif self.viewSelection.getValue() == 3:
281 self.viewMode = 'xray'
283 self.viewMode = 'normal'
284 self.layerSelect.setHidden(self.viewMode != 'gcode')
287 def OnRotateReset(self, button):
288 if self._selectedObj is None:
290 self._selectedObj.resetRotation()
291 self._scene.pushFree()
292 self._selectObject(self._selectedObj)
295 def OnLayFlat(self, button):
296 if self._selectedObj is None:
298 self._selectedObj.layFlat()
299 self._scene.pushFree()
300 self._selectObject(self._selectedObj)
303 def OnScaleReset(self, button):
304 if self._selectedObj is None:
306 self._selectedObj.resetScale()
307 self._selectObject(self._selectedObj)
308 self.updateProfileToControls()
311 def OnScaleMax(self, button):
312 if self._selectedObj is None:
314 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2 - numpy.array([1,1,1], numpy.float32))
315 self._scene.pushFree()
316 self._selectObject(self._selectedObj)
317 self.updateProfileToControls()
320 def OnMirror(self, axis):
321 if self._selectedObj is None:
323 self._selectedObj.mirror(axis)
326 def OnScaleEntry(self, value, axis):
327 if self._selectedObj is None:
333 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
334 self.updateProfileToControls()
335 self._scene.pushFree()
336 self._selectObject(self._selectedObj)
339 def OnScaleEntryMM(self, value, axis):
340 if self._selectedObj is None:
346 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
347 self.updateProfileToControls()
348 self._scene.pushFree()
349 self._selectObject(self._selectedObj)
352 def OnDeleteAll(self, e):
353 while len(self._scene.objects()) > 0:
354 self._deleteObject(self._scene.objects()[0])
355 self._animView = openglGui.animation(self, self._viewTarget.copy(), numpy.array([0,0,0], numpy.float32), 0.5)
357 def OnMultiply(self, e):
358 if self._focusObj is None:
361 dlg = wx.NumberEntryDialog(self, "How many copies do you want?", "Copies", "Multiply", 1, 1, 100)
362 if dlg.ShowModal() != wx.ID_OK:
371 self._scene.add(newObj)
372 self._scene.centerAll()
373 if not self._scene.checkPlatform(newObj):
378 self.notification.message("Could not create more then %d items" % (n - 1))
379 self._scene.remove(newObj)
380 self._scene.centerAll()
383 def OnSplitObject(self, e):
384 if self._focusObj is None:
386 self._scene.remove(self._focusObj)
387 for obj in self._focusObj.split(self._splitCallback):
388 if numpy.max(obj.getSize()) > 2.0:
390 self._scene.centerAll()
391 self._selectObject(None)
394 def _splitCallback(self, progress):
397 def OnMergeObjects(self, e):
398 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
400 self._scene.merge(self._selectedObj, self._focusObj)
403 def sceneUpdated(self):
404 self._sceneUpdateTimer.Start(500, True)
405 self._slicer.abortSlicer()
406 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
409 def _onRunSlicer(self, e):
410 if self._isSimpleMode:
411 self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
412 self._slicer.runSlicer(self._scene)
413 if self._isSimpleMode:
414 profile.resetTempOverride()
416 def _updateSliceProgress(self, progressValue, ready):
417 self.printButton.setDisabled(not ready)
418 if progressValue >= 0.0:
419 self.printButton.setProgressBar(progressValue)
421 self.printButton.setProgressBar(None)
422 if self._gcode is not None:
424 for layerVBOlist in self._gcodeVBOs:
425 for vbo in layerVBOlist:
426 self.glReleaseList.append(vbo)
429 self.printButton.setProgressBar(None)
430 cost = self._slicer.getFilamentCost()
432 self.printButton.setBottomText('%s\n%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount(), cost))
434 self.printButton.setBottomText('%s\n%s' % (self._slicer.getPrintTime(), self._slicer.getFilamentAmount()))
435 self._gcode = gcodeInterpreter.gcode()
436 self._gcodeFilename = self._slicer.getGCodeFilename()
438 self.printButton.setBottomText('')
441 def _loadGCode(self):
442 self._gcode.progressCallback = self._gcodeLoadCallback
443 self._gcode.load(self._gcodeFilename)
445 def _gcodeLoadCallback(self, progress):
446 if self._gcode is None:
448 if len(self._gcode.layerList) % 15 == 0:
450 if self._gcode is None:
452 if self.layerSelect.getValue() == self.layerSelect.getMaxValue():
453 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
454 self.layerSelect.setValue(self.layerSelect.getMaxValue())
456 self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
457 if self.viewMode == 'gcode':
461 def loadScene(self, fileList):
462 for filename in fileList:
464 objList = meshLoader.loadMeshes(filename)
466 traceback.print_exc()
469 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
471 self._scene.centerAll()
472 self._selectObject(obj)
475 def _deleteObject(self, obj):
476 if obj == self._selectedObj:
477 self._selectObject(None)
478 if obj == self._focusObj:
479 self._focusObj = None
480 self._scene.remove(obj)
481 for m in obj._meshList:
482 if m.vbo is not None and m.vbo.decRef():
483 self.glReleaseList.append(m.vbo)
488 def _selectObject(self, obj, zoom = True):
489 if obj != self._selectedObj:
490 self._selectedObj = obj
491 self.updateProfileToControls()
492 self.updateToolButtons()
493 if zoom and obj is not None:
494 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
495 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
496 newZoom = obj.getBoundaryCircle() * 6
497 if newZoom > numpy.max(self._machineSize) * 3:
498 newZoom = numpy.max(self._machineSize) * 3
499 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
501 def updateProfileToControls(self):
502 oldSimpleMode = self._isSimpleMode
503 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
504 if self._isSimpleMode and not oldSimpleMode:
505 self._scene.arrangeAll()
507 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
508 self._objColors[0] = profile.getPreferenceColour('model_colour')
509 self._objColors[1] = profile.getPreferenceColour('model_colour2')
510 self._objColors[2] = profile.getPreferenceColour('model_colour3')
511 self._objColors[3] = profile.getPreferenceColour('model_colour4')
512 self._scene.setMachineSize(self._machineSize)
513 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
514 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'))
516 if self._selectedObj is not None:
517 scale = self._selectedObj.getScale()
518 size = self._selectedObj.getSize()
519 self.scaleXctrl.setValue(round(scale[0], 2))
520 self.scaleYctrl.setValue(round(scale[1], 2))
521 self.scaleZctrl.setValue(round(scale[2], 2))
522 self.scaleXmmctrl.setValue(round(size[0], 2))
523 self.scaleYmmctrl.setValue(round(size[1], 2))
524 self.scaleZmmctrl.setValue(round(size[2], 2))
526 def OnKeyChar(self, keyCode):
527 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
528 if self._selectedObj is not None:
529 self._deleteObject(self._selectedObj)
531 if keyCode == wx.WXK_UP:
532 self.layerSelect.setValue(self.layerSelect.getValue() + 1)
534 elif keyCode == wx.WXK_DOWN:
535 self.layerSelect.setValue(self.layerSelect.getValue() - 1)
537 elif keyCode == wx.WXK_PAGEUP:
538 self.layerSelect.setValue(self.layerSelect.getValue() + 10)
540 elif keyCode == wx.WXK_PAGEDOWN:
541 self.layerSelect.setValue(self.layerSelect.getValue() - 10)
544 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
545 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
546 if keyCode == wx.WXK_F4 and wx.GetKeyState(wx.WXK_SHIFT):
547 from collections import defaultdict
548 from gc import get_objects
549 self._beforeLeakTest = defaultdict(int)
550 for i in get_objects():
551 self._beforeLeakTest[type(i)] += 1
552 if keyCode == wx.WXK_F5 and wx.GetKeyState(wx.WXK_SHIFT):
553 from collections import defaultdict
554 from gc import get_objects
555 self._afterLeakTest = defaultdict(int)
556 for i in get_objects():
557 self._afterLeakTest[type(i)] += 1
558 for k in self._afterLeakTest:
559 if self._afterLeakTest[k]-self._beforeLeakTest[k]:
560 print k, self._afterLeakTest[k], self._beforeLeakTest[k], self._afterLeakTest[k] - self._beforeLeakTest[k]
562 def ShaderUpdate(self, v, f):
563 s = opengl.GLShader(v, f)
565 self._objectLoadShader.release()
566 self._objectLoadShader = s
567 for obj in self._scene.objects():
568 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
571 def OnMouseDown(self,e):
572 self._mouseX = e.GetX()
573 self._mouseY = e.GetY()
574 self._mouseClick3DPos = self._mouse3Dpos
575 self._mouseClickFocus = self._focusObj
577 self._mouseState = 'doubleClick'
579 self._mouseState = 'dragOrClick'
580 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
581 p0 -= self.getObjectCenterPos() - self._viewTarget
582 p1 -= self.getObjectCenterPos() - self._viewTarget
583 if self.tool.OnDragStart(p0, p1):
584 self._mouseState = 'tool'
585 if self._mouseState == 'dragOrClick':
586 if e.GetButton() == 1:
587 if self._focusObj is not None:
588 self._selectObject(self._focusObj, False)
591 def OnMouseUp(self, e):
592 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
594 if self._mouseState == 'dragOrClick':
595 if e.GetButton() == 1:
596 self._selectObject(self._focusObj)
597 if e.GetButton() == 3:
599 if self._focusObj is not None:
600 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
601 self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
602 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
603 if self._selectedObj != self._focusObj and self._focusObj is not None and int(profile.getPreference('extruder_amount')) > 1:
604 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
605 if len(self._scene.objects()) > 0:
606 self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
607 if menu.MenuItemCount > 0:
610 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
611 self._scene.pushFree()
613 elif self._mouseState == 'tool':
614 if self.tempMatrix is not None and self._selectedObj is not None:
615 self._selectedObj.applyMatrix(self.tempMatrix)
616 self._scene.pushFree()
617 self._selectObject(self._selectedObj)
618 self.tempMatrix = None
619 self.tool.OnDragEnd()
621 self._mouseState = None
623 def OnMouseMotion(self,e):
624 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
625 p0 -= self.getObjectCenterPos() - self._viewTarget
626 p1 -= self.getObjectCenterPos() - self._viewTarget
628 if e.Dragging() and self._mouseState is not None:
629 if self._mouseState == 'tool':
630 self.tool.OnDrag(p0, p1)
631 elif not e.LeftIsDown() and e.RightIsDown():
632 self._mouseState = 'drag'
633 if wx.GetKeyState(wx.WXK_SHIFT):
634 a = math.cos(math.radians(self._yaw)) / 3.0
635 b = math.sin(math.radians(self._yaw)) / 3.0
636 self._viewTarget[0] += float(e.GetX() - self._mouseX) * -a
637 self._viewTarget[1] += float(e.GetX() - self._mouseX) * b
638 self._viewTarget[0] += float(e.GetY() - self._mouseY) * b
639 self._viewTarget[1] += float(e.GetY() - self._mouseY) * a
641 self._yaw += e.GetX() - self._mouseX
642 self._pitch -= e.GetY() - self._mouseY
643 if self._pitch > 170:
647 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
648 self._mouseState = 'drag'
649 self._zoom += e.GetY() - self._mouseY
652 if self._zoom > numpy.max(self._machineSize) * 3:
653 self._zoom = numpy.max(self._machineSize) * 3
654 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus:
655 self._mouseState = 'dragObject'
656 z = max(0, self._mouseClick3DPos[2])
657 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
658 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
663 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
664 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
665 diff = cursorZ1 - cursorZ0
666 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
667 if not e.Dragging() or self._mouseState != 'tool':
668 self.tool.OnMouseMove(p0, p1)
670 self._mouseX = e.GetX()
671 self._mouseY = e.GetY()
673 def OnMouseWheel(self, e):
674 delta = float(e.GetWheelRotation()) / float(e.GetWheelDelta())
675 delta = max(min(delta,4),-4)
676 self._zoom *= 1.0 - delta / 10.0
679 if self._zoom > numpy.max(self._machineSize) * 3:
680 self._zoom = numpy.max(self._machineSize) * 3
683 def getMouseRay(self, x, y):
684 if self._viewport is None:
685 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
686 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
687 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
688 p0 -= self._viewTarget
689 p1 -= self._viewTarget
692 def _init3DView(self):
693 # set viewing projection
694 size = self.GetSize()
695 glViewport(0, 0, size.GetWidth(), size.GetHeight())
698 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
700 glDisable(GL_RESCALE_NORMAL)
701 glDisable(GL_LIGHTING)
703 glEnable(GL_DEPTH_TEST)
704 glDisable(GL_CULL_FACE)
706 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
708 glClearColor(0.8, 0.8, 0.8, 1.0)
712 glMatrixMode(GL_PROJECTION)
714 aspect = float(size.GetWidth()) / float(size.GetHeight())
715 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
717 glMatrixMode(GL_MODELVIEW)
719 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
722 if machineCom.machineIsConnected():
723 self.printButton._imageID = 6
724 self.printButton._tooltip = 'Print'
725 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
726 self.printButton._imageID = 2
727 self.printButton._tooltip = 'Toolpath to SD'
729 self.printButton._imageID = 3
730 self.printButton._tooltip = 'Save toolpath'
732 if self._animView is not None:
733 self._viewTarget = self._animView.getPosition()
734 if self._animView.isDone():
735 self._animView = None
736 if self._animZoom is not None:
737 self._zoom = self._animZoom.getPosition()
738 if self._animZoom.isDone():
739 self._animZoom = None
740 if self.viewMode == 'gcode' and self._gcode is not None:
742 self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
745 if self._objectShader is None:
746 self._objectShader = opengl.GLShader("""
747 varying float light_amount;
751 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
752 gl_FrontColor = gl_Color;
754 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
758 varying float light_amount;
762 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
765 self._objectOverhangShader = opengl.GLShader("""
766 uniform float cosAngle;
767 uniform mat3 rotMatrix;
768 varying float light_amount;
772 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
773 gl_FrontColor = gl_Color;
775 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
777 if (normalize(rotMatrix * gl_Normal).z < -cosAngle)
779 light_amount = -10.0;
783 varying float light_amount;
787 if (light_amount == -10.0)
789 gl_FragColor = vec4(1.0, 0.0, 0.0, gl_Color[3]);
791 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
795 self._objectLoadShader = opengl.GLShader("""
796 uniform float intensity;
798 varying float light_amount;
802 vec4 tmp = gl_Vertex;
803 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
804 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
805 gl_Position = gl_ModelViewProjectionMatrix * tmp;
806 gl_FrontColor = gl_Color;
808 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
812 uniform float intensity;
813 varying float light_amount;
817 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
821 glTranslate(0,0,-self._zoom)
822 glRotate(-self._pitch, 1,0,0)
823 glRotate(self._yaw, 0,0,1)
824 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
826 self._viewport = glGetIntegerv(GL_VIEWPORT)
827 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
828 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
830 glClearColor(1,1,1,1)
831 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
833 if self.viewMode != 'gcode':
834 for n in xrange(0, len(self._scene.objects())):
835 obj = self._scene.objects()[n]
836 glColor4ub((n >> 16) & 0xFF, (n >> 8) & 0xFF, (n >> 0) & 0xFF, 0xFF)
837 self._renderObject(obj)
839 if self._mouseX > -1:
841 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0] >> 8
842 if n < len(self._scene.objects()):
843 self._focusObj = self._scene.objects()[n]
845 self._focusObj = None
846 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
847 #self.GetTopLevelParent().SetTitle(hex(n) + " " + str(f))
848 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
849 self._mouse3Dpos -= self._viewTarget
852 glTranslate(0,0,-self._zoom)
853 glRotate(-self._pitch, 1,0,0)
854 glRotate(self._yaw, 0,0,1)
855 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
857 if self.viewMode == 'gcode':
858 if self._gcode is not None and self._gcode.layerList is None:
859 self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
860 self._gcodeLoadThread.daemon = True
861 self._gcodeLoadThread.start()
862 if self._gcode is not None and self._gcode.layerList is not None:
864 glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
866 drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
867 for n in xrange(0, drawUpTill):
868 c = 1.0 - float(drawUpTill - n) / 15
870 if len(self._gcodeVBOs) < n + 1:
871 self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
872 if time.time() - t > 0.5:
875 #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
876 if n == drawUpTill - 1:
877 if len(self._gcodeVBOs[n]) < 6:
878 self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
880 self._gcodeVBOs[n][5].render(GL_QUADS)
882 self._gcodeVBOs[n][6].render(GL_QUADS)
883 glColor3f(c/2, c/2, 0.0)
884 self._gcodeVBOs[n][7].render(GL_QUADS)
886 self._gcodeVBOs[n][8].render(GL_QUADS)
887 self._gcodeVBOs[n][9].render(GL_QUADS)
889 self._gcodeVBOs[n][10].render(GL_LINES)
892 self._gcodeVBOs[n][0].render(GL_LINES)
894 self._gcodeVBOs[n][1].render(GL_LINES)
895 glColor3f(c/2, c/2, 0.0)
896 self._gcodeVBOs[n][2].render(GL_LINES)
898 self._gcodeVBOs[n][3].render(GL_LINES)
899 self._gcodeVBOs[n][4].render(GL_LINES)
902 glStencilFunc(GL_ALWAYS, 1, 1)
903 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
905 if self.viewMode == 'overhang':
906 self._objectOverhangShader.bind()
907 self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - 60)))
909 self._objectShader.bind()
910 for obj in self._scene.objects():
911 if obj._loadAnim is not None:
912 if obj._loadAnim.isDone():
917 if self._focusObj == obj:
919 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
922 if self._selectedObj == obj or self._selectedObj is None:
923 #If we want transparent, then first render a solid black model to remove the printer size lines.
924 if self.viewMode == 'transparent':
925 glColor4f(0, 0, 0, 0)
926 self._renderObject(obj)
928 glBlendFunc(GL_ONE, GL_ONE)
929 glDisable(GL_DEPTH_TEST)
931 if self.viewMode == 'xray':
932 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
933 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
934 glEnable(GL_STENCIL_TEST)
936 if self.viewMode == 'overhang':
937 if self._selectedObj == obj and self.tempMatrix is not None:
938 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix() * self.tempMatrix)
940 self._objectOverhangShader.setUniform('rotMatrix', obj.getMatrix())
942 if not self._scene.checkPlatform(obj):
943 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
944 self._renderObject(obj)
946 self._renderObject(obj, brightness)
947 glDisable(GL_STENCIL_TEST)
949 glEnable(GL_DEPTH_TEST)
950 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
952 if self.viewMode == 'xray':
955 glEnable(GL_STENCIL_TEST)
956 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
957 glDisable(GL_DEPTH_TEST)
958 for i in xrange(2, 15, 2):
959 glStencilFunc(GL_EQUAL, i, 0xFF)
960 glColor(float(i)/10, float(i)/10, float(i)/5)
962 glVertex3f(-1000,-1000,-10)
963 glVertex3f( 1000,-1000,-10)
964 glVertex3f( 1000, 1000,-10)
965 glVertex3f(-1000, 1000,-10)
967 for i in xrange(1, 15, 2):
968 glStencilFunc(GL_EQUAL, i, 0xFF)
969 glColor(float(i)/10, 0, 0)
971 glVertex3f(-1000,-1000,-10)
972 glVertex3f( 1000,-1000,-10)
973 glVertex3f( 1000, 1000,-10)
974 glVertex3f(-1000, 1000,-10)
977 glDisable(GL_STENCIL_TEST)
978 glEnable(GL_DEPTH_TEST)
980 self._objectShader.unbind()
982 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
984 self._objectLoadShader.bind()
985 glColor4f(0.2, 0.6, 1.0, 1.0)
986 for obj in self._scene.objects():
987 if obj._loadAnim is None:
989 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
990 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
991 self._renderObject(obj)
992 self._objectLoadShader.unbind()
997 if self.viewMode == 'gcode':
998 if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
999 glDisable(GL_DEPTH_TEST)
1002 glTranslate(0,-4,-10)
1003 glColor4ub(60,60,60,255)
1004 opengl.glDrawStringCenter('Loading toolpath for visualization...')
1007 #Draw the object box-shadow, so you can see where it will collide with other objects.
1008 if self._selectedObj is not None and len(self._scene.objects()) > 1:
1009 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
1011 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
1013 glEnable(GL_CULL_FACE)
1014 glColor4f(0,0,0,0.12)
1016 glVertex3f(-size[0], size[1], 0.1)
1017 glVertex3f(-size[0], -size[1], 0.1)
1018 glVertex3f( size[0], -size[1], 0.1)
1019 glVertex3f( size[0], size[1], 0.1)
1021 glDisable(GL_CULL_FACE)
1024 #Draw the outline of the selected object, on top of everything else except the GUI.
1025 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
1026 glDisable(GL_DEPTH_TEST)
1027 glEnable(GL_CULL_FACE)
1028 glEnable(GL_STENCIL_TEST)
1030 glStencilFunc(GL_EQUAL, 0, 255)
1032 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
1034 glColor4f(1,1,1,0.5)
1035 self._renderObject(self._selectedObj)
1036 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
1038 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
1039 glDisable(GL_STENCIL_TEST)
1040 glDisable(GL_CULL_FACE)
1041 glEnable(GL_DEPTH_TEST)
1043 if self._selectedObj is not None:
1045 pos = self.getObjectCenterPos()
1046 glTranslate(pos[0], pos[1], pos[2])
1050 def _renderObject(self, obj, brightness = False, addSink = True):
1053 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2 - profile.getProfileSettingFloat('object_sink'))
1055 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
1057 if self.tempMatrix is not None and obj == self._selectedObj:
1058 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
1059 glMultMatrixf(tempMatrix)
1061 offset = obj.getDrawOffset()
1062 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
1064 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
1065 glMultMatrixf(tempMatrix)
1068 for m in obj._meshList:
1070 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
1072 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
1077 def _drawMachine(self):
1078 glEnable(GL_CULL_FACE)
1081 if profile.getPreference('machine_type') == 'ultimaker':
1082 glColor4f(1,1,1,0.5)
1083 self._objectShader.bind()
1084 self._renderObject(self._platformMesh, False, False)
1085 self._objectShader.unbind()
1087 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
1088 v0 = [ size[0] / 2, size[1] / 2, size[2]]
1089 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
1090 v2 = [-size[0] / 2, size[1] / 2, size[2]]
1091 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
1092 v4 = [ size[0] / 2, size[1] / 2, 0]
1093 v5 = [ size[0] / 2,-size[1] / 2, 0]
1094 v6 = [-size[0] / 2, size[1] / 2, 0]
1095 v7 = [-size[0] / 2,-size[1] / 2, 0]
1097 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
1098 glEnableClientState(GL_VERTEX_ARRAY)
1099 glVertexPointer(3, GL_FLOAT, 3*4, vList)
1101 glColor4ub(5, 171, 231, 64)
1102 glDrawArrays(GL_QUADS, 0, 4)
1103 glColor4ub(5, 171, 231, 96)
1104 glDrawArrays(GL_QUADS, 4, 8)
1105 glColor4ub(5, 171, 231, 128)
1106 glDrawArrays(GL_QUADS, 12, 8)
1108 sx = self._machineSize[0]
1109 sy = self._machineSize[1]
1110 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
1111 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
1116 x1 = max(min(x1, sx/2), -sx/2)
1117 y1 = max(min(y1, sy/2), -sy/2)
1118 x2 = max(min(x2, sx/2), -sx/2)
1119 y2 = max(min(y2, sy/2), -sy/2)
1120 if (x & 1) == (y & 1):
1121 glColor4ub(5, 171, 231, 127)
1123 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
1125 glVertex3f(x1, y1, -0.02)
1126 glVertex3f(x2, y1, -0.02)
1127 glVertex3f(x2, y2, -0.02)
1128 glVertex3f(x1, y2, -0.02)
1131 glDisableClientState(GL_VERTEX_ARRAY)
1133 glDisable(GL_CULL_FACE)
1135 def _generateGCodeVBOs(self, layer):
1137 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1138 pointList = numpy.zeros((0,3), numpy.float32)
1140 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1142 a = numpy.concatenate((a[:-1], a[1:]), 1)
1143 a = a.reshape((len(a) * 2, 3))
1144 pointList = numpy.concatenate((pointList, a))
1145 ret.append(opengl.GLVBO(pointList))
1148 def _generateGCodeVBOs2(self, layer):
1149 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
1150 filamentArea = math.pi * filamentRadius * filamentRadius
1153 for extrudeType in ['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
1154 pointList = numpy.zeros((0,3), numpy.float32)
1156 if path['type'] == 'extrude' and path['pathType'] == extrudeType:
1158 if extrudeType == 'FILL':
1161 normal = a[1:] - a[:-1]
1162 lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
1163 normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
1166 ePerDist = path['extrusion'][1:] / lens
1167 lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
1169 normal[:,0] *= lineWidth
1170 normal[:,1] *= lineWidth
1172 b = numpy.zeros((len(a)-1, 0), numpy.float32)
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] - normal), 1)
1176 b = numpy.concatenate((b, a[:-1] + normal), 1)
1177 #b = numpy.concatenate((b, a[:-1]), 1)
1178 #b = numpy.concatenate((b, a[:-1]), 1)
1179 b = b.reshape((len(b) * 4, 3))
1182 normal2 = normal[:-1] + normal[1:]
1183 lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
1184 normal2[:,0] /= lens2
1185 normal2[:,1] /= lens2
1186 normal2[:,0] *= lineWidth[:-1]
1187 normal2[:,1] *= lineWidth[:-1]
1189 c = numpy.zeros((len(a)-2, 0), numpy.float32)
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 = numpy.concatenate((c, a[1:-1]), 1)
1196 c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
1197 c = numpy.concatenate((c, a[1:-1]-normal2), 1)
1198 c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
1200 c = c.reshape((len(c) * 8, 3))
1202 pointList = numpy.concatenate((pointList, b, c))
1204 pointList = numpy.concatenate((pointList, b))
1205 ret.append(opengl.GLVBO(pointList))
1207 pointList = numpy.zeros((0,3), numpy.float32)
1209 if path['type'] == 'move':
1210 a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1211 a = numpy.concatenate((a[:-1], a[1:]), 1)
1212 a = a.reshape((len(a) * 2, 3))
1213 pointList = numpy.concatenate((pointList, a))
1214 if path['type'] == 'retract':
1215 a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
1216 a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
1217 a = a.reshape((len(a) * 2, 3))
1218 pointList = numpy.concatenate((pointList, a))
1219 ret.append(opengl.GLVBO(pointList))
1223 def getObjectCenterPos(self):
1224 if self._selectedObj is None:
1225 return [0.0, 0.0, 0.0]
1226 pos = self._selectedObj.getPosition()
1227 size = self._selectedObj.getSize()
1228 return [pos[0], pos[1], size[2]/2 - profile.getProfileSettingFloat('object_sink')]
1230 def getObjectBoundaryCircle(self):
1231 if self._selectedObj is None:
1233 return self._selectedObj.getBoundaryCircle()
1235 def getObjectSize(self):
1236 if self._selectedObj is None:
1237 return [0.0, 0.0, 0.0]
1238 return self._selectedObj.getSize()
1240 def getObjectMatrix(self):
1241 if self._selectedObj is None:
1242 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
1243 return self._selectedObj.getMatrix()
1245 class shaderEditor(wx.Dialog):
1246 def __init__(self, parent, callback, v, f):
1247 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
1248 self._callback = callback
1249 s = wx.BoxSizer(wx.VERTICAL)
1251 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
1252 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
1253 s.Add(self._vertex, 1, flag=wx.EXPAND)
1254 s.Add(self._fragment, 1, flag=wx.EXPAND)
1256 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
1257 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
1259 self.SetPosition(self.GetParent().GetPosition())
1260 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
1263 def OnText(self, e):
1264 self._callback(self._vertex.GetValue(), self._fragment.GetValue())