1 from __future__ import absolute_import
11 OpenGL.ERROR_CHECKING = False
12 from OpenGL.GLU import *
13 from OpenGL.GL import *
15 from Cura.gui import printWindow
16 from Cura.util import profile
17 from Cura.util import meshLoader
18 from Cura.util import objectScene
19 from Cura.util import resources
20 from Cura.util import sliceEngine
21 from Cura.util import machineCom
22 from Cura.util import removableStorage
23 from Cura.gui.util import previewTools
24 from Cura.gui.util import opengl
25 from Cura.gui.util import openglGui
27 class SceneView(openglGui.glGuiPanel):
28 def __init__(self, parent):
29 super(SceneView, self).__init__(parent)
34 self._scene = objectScene.Scene()
35 self._objectShader = None
37 self._selectedObj = None
38 self._objColors = [None,None,None,None]
41 self._mouseState = None
42 self._viewTarget = numpy.array([0,0,0], numpy.float32)
45 self._platformMesh = meshLoader.loadMeshes(resources.getPathForMesh('ultimaker_platform.stl'))[0]
46 self._platformMesh._drawOffset = numpy.array([0,0,1.5], numpy.float32)
47 self._isSimpleMode = True
50 self._modelMatrix = None
51 self._projMatrix = None
52 self.tempMatrix = None
54 self.openFileButton = openglGui.glButton(self, 4, 'Load', (0,0), self.ShowLoadModel)
55 self.printButton = openglGui.glButton(self, 6, 'Print', (1,0), self.ShowPrintWindow)
56 self.printButton.setDisabled(True)
59 self.rotateToolButton = openglGui.glRadioButton(self, 8, 'Rotate', (0,-1), group, self.OnToolSelect)
60 self.scaleToolButton = openglGui.glRadioButton(self, 9, 'Scale', (1,-1), group, self.OnToolSelect)
61 self.mirrorToolButton = openglGui.glRadioButton(self, 10, 'Mirror', (2,-1), group, self.OnToolSelect)
63 self.resetRotationButton = openglGui.glButton(self, 12, 'Reset', (0,-2), self.OnRotateReset)
64 self.layFlatButton = openglGui.glButton(self, 16, 'Lay flat', (0,-3), self.OnLayFlat)
66 self.resetScaleButton = openglGui.glButton(self, 13, 'Reset', (1,-2), self.OnScaleReset)
67 self.scaleMaxButton = openglGui.glButton(self, 17, 'To max', (1,-3), self.OnScaleMax)
69 self.mirrorXButton = openglGui.glButton(self, 14, 'Mirror X', (2,-2), lambda button: self.OnMirror(0))
70 self.mirrorYButton = openglGui.glButton(self, 18, 'Mirror Y', (2,-3), lambda button: self.OnMirror(1))
71 self.mirrorZButton = openglGui.glButton(self, 22, 'Mirror Z', (2,-4), lambda button: self.OnMirror(2))
73 self.rotateToolButton.setExpandArrow(True)
74 self.scaleToolButton.setExpandArrow(True)
75 self.mirrorToolButton.setExpandArrow(True)
77 self.scaleForm = openglGui.glFrame(self, (2, -2))
78 openglGui.glGuiLayoutGrid(self.scaleForm)
79 openglGui.glLabel(self.scaleForm, 'Scale X', (0,0))
80 self.scaleXctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,0), lambda value: self.OnScaleEntry(value, 0))
81 openglGui.glLabel(self.scaleForm, 'Scale Y', (0,1))
82 self.scaleYctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,1), lambda value: self.OnScaleEntry(value, 1))
83 openglGui.glLabel(self.scaleForm, 'Scale Z', (0,2))
84 self.scaleZctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,2), lambda value: self.OnScaleEntry(value, 2))
85 openglGui.glLabel(self.scaleForm, 'Size X (mm)', (0,4))
86 self.scaleXmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,4), lambda value: self.OnScaleEntryMM(value, 0))
87 openglGui.glLabel(self.scaleForm, 'Size Y (mm)', (0,5))
88 self.scaleYmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,5), lambda value: self.OnScaleEntryMM(value, 1))
89 openglGui.glLabel(self.scaleForm, 'Size Z (mm)', (0,6))
90 self.scaleZmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,6), lambda value: self.OnScaleEntryMM(value, 2))
91 openglGui.glLabel(self.scaleForm, 'Uniform scale', (0,8))
92 self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None)
94 self.notification = openglGui.glNotification(self, (0, 0))
96 self._slicer = sliceEngine.Slicer(self._updateSliceProgress)
97 self._sceneUpdateTimer = wx.Timer(self)
98 self.Bind(wx.EVT_TIMER, lambda e : self._slicer.runSlicer(self._scene), self._sceneUpdateTimer)
99 self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
102 self.updateToolButtons()
103 self.updateProfileToControls()
105 def ShowLoadModel(self, button):
107 dlg=wx.FileDialog(self, 'Open 3D model', os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
108 dlg.SetWildcard(meshLoader.wildcardFilter())
109 if dlg.ShowModal() != wx.ID_OK:
112 filename = dlg.GetPath()
114 if not(os.path.exists(filename)):
116 profile.putPreference('lastFile', filename)
117 self.GetParent().GetParent().GetParent().addToModelMRU(filename)
118 self.loadScene([filename])
120 def ShowPrintWindow(self, button):
122 if machineCom.machineIsConnected():
123 printWindow.printFile(self._slicer.getGCodeFilename())
124 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
125 drives = removableStorage.getPossibleSDcardDrives()
130 filename = os.path.basename(profile.getPreference('lastFile'))
131 filename = filename[0:filename.rfind('.')] + '.gcode'
132 shutil.copy(self._slicer.getGCodeFilename(), drive[1] + filename)
133 self.notification.message("Saved as %s" % (drive[1] + filename))
135 defPath = profile.getPreference('lastFile')
136 defPath = defPath[0:defPath.rfind('.')] + '.gcode'
137 dlg=wx.FileDialog(self, 'Save toolpath', defPath, style=wx.FD_SAVE)
138 dlg.SetFilename(defPath)
139 dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
140 if dlg.ShowModal() != wx.ID_OK:
143 filename = dlg.GetPath()
146 shutil.copy(self._slicer.getGCodeFilename(), filename)
147 self.notification.message("Saved as %s" % (filename))
149 def OnToolSelect(self, button):
150 if self.rotateToolButton.getSelected():
151 self.tool = previewTools.toolRotate(self)
152 elif self.scaleToolButton.getSelected():
153 self.tool = previewTools.toolScale(self)
154 elif self.mirrorToolButton.getSelected():
155 self.tool = previewTools.toolNone(self)
157 self.tool = previewTools.toolNone(self)
158 self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected())
159 self.layFlatButton.setHidden(not self.rotateToolButton.getSelected())
160 self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected())
161 self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected())
162 self.scaleForm.setHidden(not self.scaleToolButton.getSelected())
163 self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected())
164 self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected())
165 self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected())
167 def updateToolButtons(self):
168 if self._selectedObj is None:
172 self.rotateToolButton.setHidden(hidden)
173 self.scaleToolButton.setHidden(hidden)
174 self.mirrorToolButton.setHidden(hidden)
176 self.rotateToolButton.setSelected(False)
177 self.scaleToolButton.setSelected(False)
178 self.mirrorToolButton.setSelected(False)
181 def OnRotateReset(self, button):
182 if self._selectedObj is None:
184 self._selectedObj.resetRotation()
185 self._scene.pushFree()
186 self._selectObject(self._selectedObj)
188 def OnLayFlat(self, button):
189 if self._selectedObj is None:
191 self._selectedObj.layFlat()
192 self._scene.pushFree()
193 self._selectObject(self._selectedObj)
195 def OnScaleReset(self, button):
196 if self._selectedObj is None:
198 self._selectedObj.resetScale()
200 def OnScaleMax(self, button):
201 if self._selectedObj is None:
203 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2)
204 self._scene.pushFree()
205 self._selectObject(self._selectedObj)
207 def OnMirror(self, axis):
208 if self._selectedObj is None:
210 self._selectedObj.mirror(axis)
213 def OnScaleEntry(self, value, axis):
214 if self._selectedObj is None:
220 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
221 self.updateProfileToControls()
222 self._scene.pushFree()
223 self._selectObject(self._selectedObj)
226 def OnScaleEntryMM(self, value, axis):
227 if self._selectedObj is None:
233 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
234 self.updateProfileToControls()
235 self._scene.pushFree()
236 self._selectObject(self._selectedObj)
239 def OnDeleteAll(self, e):
240 while len(self._scene.objects()) > 0:
241 self._deleteObject(self._scene.objects()[0])
242 self._animView = openglGui.animation(self, self._viewTarget.copy(), numpy.array([0,0,0], numpy.float32), 0.5)
244 def OnMultiply(self, e):
245 if self._focusObj is None:
248 dlg = wx.NumberEntryDialog(self, "How many copies need to be made?", "Copies", "Multiply", 1, 1, 100)
249 if dlg.ShowModal() != wx.ID_OK:
258 self._scene.add(newObj)
259 self._scene.centerAll()
260 if not self._scene.checkPlatform(newObj):
264 self._scene.remove(newObj)
265 self._scene.centerAll()
268 def OnSplitObject(self, e):
269 if self._focusObj is None:
271 self._scene.remove(self._focusObj)
272 for obj in self._focusObj.split():
274 self._scene.centerAll()
275 self._selectObject(None)
278 def OnMergeObjects(self, e):
279 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
281 self._scene.merge(self._selectedObj, self._focusObj)
284 def sceneUpdated(self):
285 self._sceneUpdateTimer.Start(1, True)
286 self._slicer.abortSlicer()
287 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
290 def _updateSliceProgress(self, progressValue, ready):
291 self.printButton.setDisabled(not ready)
292 self.printButton.setProgressBar(progressValue)
295 def loadScene(self, fileList):
296 for filename in fileList:
298 objList = meshLoader.loadMeshes(filename)
300 traceback.print_exc()
303 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
305 self._scene.centerAll()
306 self._selectObject(obj)
309 def _deleteObject(self, obj):
310 if obj == self._selectedObj:
311 self._selectObject(None)
312 if obj == self._focusObj:
313 self._focusObj = None
314 self._scene.remove(obj)
315 for m in obj._meshList:
316 if m.vbo is not None and m.vbo.decRef():
317 self.glReleaseList.append(m.vbo)
318 if self._isSimpleMode:
319 self._scene.arrangeAll()
322 def _selectObject(self, obj, zoom = True):
323 if obj != self._selectedObj:
324 self._selectedObj = obj
325 self.updateProfileToControls()
326 self.updateToolButtons()
327 if zoom and obj is not None:
328 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
329 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
330 newZoom = obj.getBoundaryCircle() * 6
331 if newZoom > numpy.max(self._machineSize) * 3:
332 newZoom = numpy.max(self._machineSize) * 3
333 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
335 def updateProfileToControls(self):
336 oldSimpleMode = self._isSimpleMode
337 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
338 if self._isSimpleMode and not oldSimpleMode:
339 self._scene.arrangeAll()
341 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
342 self._objColors[0] = profile.getPreferenceColour('model_colour')
343 self._objColors[1] = profile.getPreferenceColour('model_colour2')
344 self._objColors[2] = profile.getPreferenceColour('model_colour3')
345 self._objColors[3] = profile.getPreferenceColour('model_colour4')
346 self._scene.setMachineSize(self._machineSize)
347 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
348 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'))
350 if self._selectedObj is not None:
351 scale = self._selectedObj.getScale()
352 size = self._selectedObj.getSize()
353 self.scaleXctrl.setValue(round(scale[0], 2))
354 self.scaleYctrl.setValue(round(scale[1], 2))
355 self.scaleZctrl.setValue(round(scale[2], 2))
356 self.scaleXmmctrl.setValue(round(size[0], 2))
357 self.scaleYmmctrl.setValue(round(size[1], 2))
358 self.scaleZmmctrl.setValue(round(size[2], 2))
360 def OnKeyChar(self, keyCode):
361 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
362 if self._selectedObj is not None:
363 self._deleteObject(self._selectedObj)
366 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
367 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
369 def ShaderUpdate(self, v, f):
370 s = opengl.GLShader(v, f)
372 self._objectLoadShader.release()
373 self._objectLoadShader = s
374 for obj in self._scene.objects():
375 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
378 def OnMouseDown(self,e):
379 self._mouseX = e.GetX()
380 self._mouseY = e.GetY()
381 self._mouseClick3DPos = self._mouse3Dpos
382 self._mouseClickFocus = self._focusObj
384 self._mouseState = 'doubleClick'
386 self._mouseState = 'dragOrClick'
387 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
388 p0 -= self.getObjectCenterPos() - self._viewTarget
389 p1 -= self.getObjectCenterPos() - self._viewTarget
390 if self.tool.OnDragStart(p0, p1):
391 self._mouseState = 'tool'
392 if self._mouseState == 'dragOrClick':
393 if e.GetButton() == 1:
394 if self._focusObj is not None:
395 self._selectObject(self._focusObj, False)
398 def OnMouseUp(self, e):
399 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
401 if self._mouseState == 'dragOrClick':
402 if e.GetButton() == 1:
403 self._selectObject(self._focusObj)
404 if e.GetButton() == 3:
406 if self._focusObj is not None:
407 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
408 self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
409 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
410 if self._selectedObj != self._focusObj and self._focusObj is not None:
411 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
412 if len(self._scene.objects()) > 0:
413 self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
414 if menu.MenuItemCount > 0:
417 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
418 self._scene.pushFree()
420 elif self._mouseState == 'tool':
421 if self.tempMatrix is not None and self._selectedObj is not None:
422 self._selectedObj.applyMatrix(self.tempMatrix)
423 self._scene.pushFree()
424 self._selectObject(self._selectedObj)
425 self.tempMatrix = None
426 self.tool.OnDragEnd()
428 self._mouseState = None
430 def OnMouseMotion(self,e):
431 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
432 p0 -= self.getObjectCenterPos() - self._viewTarget
433 p1 -= self.getObjectCenterPos() - self._viewTarget
435 if e.Dragging() and self._mouseState is not None:
436 if self._mouseState == 'tool':
437 self.tool.OnDrag(p0, p1)
438 elif not e.LeftIsDown() and e.RightIsDown():
439 self._mouseState = 'drag'
440 self._yaw += e.GetX() - self._mouseX
441 self._pitch -= e.GetY() - self._mouseY
442 if self._pitch > 170:
446 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
447 self._mouseState = 'drag'
448 self._zoom += e.GetY() - self._mouseY
451 if self._zoom > numpy.max(self._machineSize) * 3:
452 self._zoom = numpy.max(self._machineSize) * 3
453 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus and not self._isSimpleMode:
454 self._mouseState = 'dragObject'
455 z = max(0, self._mouseClick3DPos[2])
456 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
457 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
462 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
463 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
464 diff = cursorZ1 - cursorZ0
465 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
466 if not e.Dragging() or self._mouseState != 'tool':
467 self.tool.OnMouseMove(p0, p1)
469 self._mouseX = e.GetX()
470 self._mouseY = e.GetY()
472 def OnMouseWheel(self, e):
473 delta = float(e.GetWheelRotation()) / float(e.GetWheelDelta())
474 delta = max(min(delta,4),-4)
475 self._zoom *= 1.0 - delta / 10.0
478 if self._zoom > numpy.max(self._machineSize) * 3:
479 self._zoom = numpy.max(self._machineSize) * 3
482 def getMouseRay(self, x, y):
483 if self._viewport is None:
484 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
485 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
486 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
487 p0 -= self._viewTarget
488 p1 -= self._viewTarget
491 def _init3DView(self):
492 # set viewing projection
493 size = self.GetSize()
494 glViewport(0, 0, size.GetWidth(), size.GetHeight())
497 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
499 glDisable(GL_RESCALE_NORMAL)
500 glDisable(GL_LIGHTING)
502 glEnable(GL_DEPTH_TEST)
503 glDisable(GL_CULL_FACE)
505 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
507 glClearColor(0.8, 0.8, 0.8, 1.0)
511 glMatrixMode(GL_PROJECTION)
513 aspect = float(size.GetWidth()) / float(size.GetHeight())
514 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
516 glMatrixMode(GL_MODELVIEW)
518 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
521 if machineCom.machineIsConnected():
522 self.printButton._imageID = 6
523 self.printButton._tooltip = 'Print'
524 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
525 self.printButton._imageID = 2
526 self.printButton._tooltip = 'Toolpath to SD'
528 self.printButton._imageID = 3
529 self.printButton._tooltip = 'Save toolpath'
531 if self._animView is not None:
532 self._viewTarget = self._animView.getPosition()
533 if self._animView.isDone():
534 self._animView = None
535 if self._animZoom is not None:
536 self._zoom = self._animZoom.getPosition()
537 if self._animZoom.isDone():
538 self._animZoom = None
539 if self._objectShader is None:
540 self._objectShader = opengl.GLShader("""
541 varying float light_amount;
545 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
546 gl_FrontColor = gl_Color;
548 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
552 varying float light_amount;
556 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
559 self._objectLoadShader = opengl.GLShader("""
560 uniform float intensity;
562 varying float light_amount;
566 vec4 tmp = gl_Vertex;
567 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
568 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
569 gl_Position = gl_ModelViewProjectionMatrix * tmp;
570 gl_FrontColor = gl_Color;
572 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
576 uniform float intensity;
577 varying float light_amount;
581 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
585 glTranslate(0,0,-self._zoom)
586 glRotate(-self._pitch, 1,0,0)
587 glRotate(self._yaw, 0,0,1)
588 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
590 self._viewport = glGetIntegerv(GL_VIEWPORT)
591 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
592 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
594 glClearColor(1,1,1,1)
595 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
597 for n in xrange(0, len(self._scene.objects())):
598 obj = self._scene.objects()[n]
599 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
600 self._renderObject(obj)
602 if self._mouseX > -1:
603 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
604 if n < len(self._scene.objects()):
605 self._focusObj = self._scene.objects()[n]
607 self._focusObj = None
608 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
609 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
610 self._mouse3Dpos -= self._viewTarget
613 glTranslate(0,0,-self._zoom)
614 glRotate(-self._pitch, 1,0,0)
615 glRotate(self._yaw, 0,0,1)
616 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
618 glStencilFunc(GL_ALWAYS, 1, 1)
619 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
620 self._objectShader.bind()
621 for obj in self._scene.objects():
622 if obj._loadAnim is not None:
623 if obj._loadAnim.isDone():
628 glDisable(GL_STENCIL_TEST)
629 if self._selectedObj == obj:
630 glEnable(GL_STENCIL_TEST)
631 if self._focusObj == obj:
633 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
635 if not self._scene.checkPlatform(obj):
636 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
637 self._renderObject(obj)
639 self._renderObject(obj, brightness)
640 self._objectShader.unbind()
642 glDisable(GL_STENCIL_TEST)
644 self._objectLoadShader.bind()
645 glColor4f(0.2, 0.6, 1.0, 1.0)
646 for obj in self._scene.objects():
647 if obj._loadAnim is None:
649 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
650 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
651 self._renderObject(obj)
652 self._objectLoadShader.unbind()
657 #Draw the object box-shadow, so you can see where it will collide with other objects.
658 if self._selectedObj is not None and len(self._scene.objects()) > 1:
659 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
661 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0.0)
663 glEnable(GL_CULL_FACE)
664 glColor4f(0,0,0,0.12)
666 glVertex3f(-size[0], size[1], 0.1)
667 glVertex3f(-size[0], -size[1], 0.1)
668 glVertex3f( size[0], -size[1], 0.1)
669 glVertex3f( size[0], size[1], 0.1)
671 glDisable(GL_CULL_FACE)
674 #Draw the outline of the selected object, on top of everything else except the GUI.
675 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
676 glDisable(GL_DEPTH_TEST)
677 glEnable(GL_CULL_FACE)
678 glEnable(GL_STENCIL_TEST)
680 glStencilFunc(GL_EQUAL, 0, 255)
682 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
685 self._renderObject(self._selectedObj)
686 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
688 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
689 glDisable(GL_STENCIL_TEST)
690 glDisable(GL_CULL_FACE)
691 glEnable(GL_DEPTH_TEST)
693 if self._selectedObj is not None:
695 pos = self.getObjectCenterPos()
696 glTranslate(pos[0], pos[1], pos[2])
700 def _renderObject(self, obj, brightness = False):
702 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
704 if self.tempMatrix is not None and obj == self._selectedObj:
705 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
706 glMultMatrixf(tempMatrix)
708 offset = obj.getDrawOffset()
709 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
711 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
712 glMultMatrixf(tempMatrix)
715 for m in obj._meshList:
717 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
719 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
724 def _drawMachine(self):
725 glEnable(GL_CULL_FACE)
728 if profile.getPreference('machine_type') == 'ultimaker':
730 self._objectShader.bind()
731 self._renderObject(self._platformMesh)
732 self._objectShader.unbind()
734 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
735 v0 = [ size[0] / 2, size[1] / 2, size[2]]
736 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
737 v2 = [-size[0] / 2, size[1] / 2, size[2]]
738 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
739 v4 = [ size[0] / 2, size[1] / 2, 0]
740 v5 = [ size[0] / 2,-size[1] / 2, 0]
741 v6 = [-size[0] / 2, size[1] / 2, 0]
742 v7 = [-size[0] / 2,-size[1] / 2, 0]
744 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
745 glEnableClientState(GL_VERTEX_ARRAY)
746 glVertexPointer(3, GL_FLOAT, 3*4, vList)
748 glColor4ub(5, 171, 231, 64)
749 glDrawArrays(GL_QUADS, 0, 4)
750 glColor4ub(5, 171, 231, 96)
751 glDrawArrays(GL_QUADS, 4, 8)
752 glColor4ub(5, 171, 231, 128)
753 glDrawArrays(GL_QUADS, 12, 8)
755 sx = self._machineSize[0]
756 sy = self._machineSize[1]
757 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
758 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
763 x1 = max(min(x1, sx/2), -sx/2)
764 y1 = max(min(y1, sy/2), -sy/2)
765 x2 = max(min(x2, sx/2), -sx/2)
766 y2 = max(min(y2, sy/2), -sy/2)
767 if (x & 1) == (y & 1):
768 glColor4ub(5, 171, 231, 127)
770 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
772 glVertex3f(x1, y1, -0.02)
773 glVertex3f(x2, y1, -0.02)
774 glVertex3f(x2, y2, -0.02)
775 glVertex3f(x1, y2, -0.02)
778 glDisableClientState(GL_VERTEX_ARRAY)
780 glDisable(GL_CULL_FACE)
782 def getObjectCenterPos(self):
783 if self._selectedObj is None:
784 return [0.0, 0.0, 0.0]
785 pos = self._selectedObj.getPosition()
786 size = self._selectedObj.getSize()
787 return [pos[0], pos[1], size[2]/2]
789 def getObjectBoundaryCircle(self):
790 if self._selectedObj is None:
792 return self._selectedObj.getBoundaryCircle()
794 def getObjectSize(self):
795 if self._selectedObj is None:
796 return [0.0, 0.0, 0.0]
797 return self._selectedObj.getSize()
799 def getObjectMatrix(self):
800 if self._selectedObj is None:
801 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
802 return self._selectedObj.getMatrix()
804 class shaderEditor(wx.Dialog):
805 def __init__(self, parent, callback, v, f):
806 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
807 self._callback = callback
808 s = wx.BoxSizer(wx.VERTICAL)
810 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
811 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
812 s.Add(self._vertex, 1, flag=wx.EXPAND)
813 s.Add(self._fragment, 1, flag=wx.EXPAND)
815 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
816 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
818 self.SetPosition(self.GetParent().GetPosition())
819 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
823 self._callback(self._vertex.GetValue(), self._fragment.GetValue())