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()
186 def OnLayFlat(self, button):
187 if self._selectedObj is None:
189 self._selectedObj.layFlat()
191 def OnScaleReset(self, button):
192 if self._selectedObj is None:
194 self._selectedObj.resetScale()
196 def OnScaleMax(self, button):
197 if self._selectedObj is None:
199 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2)
201 def OnMirror(self, axis):
202 if self._selectedObj is None:
204 self._selectedObj.mirror(axis)
207 def OnScaleEntry(self, value, axis):
208 if self._selectedObj is None:
214 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
215 self.updateProfileToControls()
218 def OnScaleEntryMM(self, value, axis):
219 if self._selectedObj is None:
225 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
226 self.updateProfileToControls()
229 def OnDeleteAll(self, e):
230 while len(self._scene.objects()) > 0:
231 self._deleteObject(self._scene.objects()[0])
233 def OnMultiply(self, e):
234 if self._focusObj is None:
237 dlg = wx.NumberEntryDialog(self, "How many copies need to be made?", "Copies", "Multiply", 1, 1, 100)
238 if dlg.ShowModal() != wx.ID_OK:
247 self._scene.add(newObj)
248 self._scene.centerAll()
249 if not self._scene.checkPlatform(newObj):
253 self._scene.remove(newObj)
254 self._scene.centerAll()
257 def OnSplitObject(self, e):
258 if self._focusObj is None:
260 self._scene.remove(self._focusObj)
261 for obj in self._focusObj.split():
263 self._scene.centerAll()
264 self._selectObject(None)
267 def OnMergeObjects(self, e):
268 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
270 self._scene.merge(self._selectedObj, self._focusObj)
273 def sceneUpdated(self):
274 self._sceneUpdateTimer.Start(1, True)
275 self._slicer.abortSlicer()
276 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
279 def _updateSliceProgress(self, progressValue, ready):
280 self.printButton.setDisabled(not ready)
281 self.printButton.setProgressBar(progressValue)
284 def loadScene(self, fileList):
285 for filename in fileList:
287 objList = meshLoader.loadMeshes(filename)
289 traceback.print_exc()
292 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
294 self._scene.centerAll()
295 self._selectObject(obj)
298 def _deleteObject(self, obj):
299 if obj == self._selectedObj:
300 self._selectObject(None)
301 if obj == self._focusObj:
302 self._focusObj = None
303 self._scene.remove(obj)
304 for m in obj._meshList:
305 if m.vbo is not None and m.vbo.decRef():
306 self.glReleaseList.append(m.vbo)
307 if self._isSimpleMode:
308 self._scene.arrangeAll()
311 def _selectObject(self, obj, zoom = True):
312 if obj != self._selectedObj:
313 self._selectedObj = obj
314 self.updateProfileToControls()
315 self.updateToolButtons()
316 if zoom and obj is not None:
317 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
318 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
319 newZoom = obj.getBoundaryCircle() * 6
320 if newZoom > numpy.max(self._machineSize) * 3:
321 newZoom = numpy.max(self._machineSize) * 3
322 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
324 def updateProfileToControls(self):
325 oldSimpleMode = self._isSimpleMode
326 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
327 if self._isSimpleMode and not oldSimpleMode:
328 self._scene.arrangeAll()
330 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
331 self._objColors[0] = profile.getPreferenceColour('model_colour')
332 self._objColors[1] = profile.getPreferenceColour('model_colour2')
333 self._objColors[2] = profile.getPreferenceColour('model_colour3')
334 self._objColors[3] = profile.getPreferenceColour('model_colour4')
335 self._scene.setMachineSize(self._machineSize)
336 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
337 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'))
339 if self._selectedObj is not None:
340 scale = self._selectedObj.getScale()
341 size = self._selectedObj.getSize()
342 self.scaleXctrl.setValue(round(scale[0], 2))
343 self.scaleYctrl.setValue(round(scale[1], 2))
344 self.scaleZctrl.setValue(round(scale[2], 2))
345 self.scaleXmmctrl.setValue(round(size[0], 2))
346 self.scaleYmmctrl.setValue(round(size[1], 2))
347 self.scaleZmmctrl.setValue(round(size[2], 2))
349 def OnKeyChar(self, keyCode):
350 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
351 if self._selectedObj is not None:
352 self._deleteObject(self._selectedObj)
355 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
356 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
358 def ShaderUpdate(self, v, f):
359 s = opengl.GLShader(v, f)
361 self._objectLoadShader.release()
362 self._objectLoadShader = s
363 for obj in self._scene.objects():
364 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
367 def OnMouseDown(self,e):
368 self._mouseX = e.GetX()
369 self._mouseY = e.GetY()
370 self._mouseClick3DPos = self._mouse3Dpos
371 self._mouseClickFocus = self._focusObj
373 self._mouseState = 'doubleClick'
375 self._mouseState = 'dragOrClick'
376 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
377 p0 -= self.getObjectCenterPos() - self._viewTarget
378 p1 -= self.getObjectCenterPos() - self._viewTarget
379 if self.tool.OnDragStart(p0, p1):
380 self._mouseState = 'tool'
381 if self._mouseState == 'dragOrClick':
382 if e.GetButton() == 1:
383 if self._focusObj is not None:
384 self._selectObject(self._focusObj, False)
387 def OnMouseUp(self, e):
388 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
390 if self._mouseState == 'dragOrClick':
391 if e.GetButton() == 1:
392 self._selectObject(self._focusObj)
393 if e.GetButton() == 3:
395 if self._focusObj is not None:
396 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._focusObj), menu.Append(-1, 'Delete'))
397 self.Bind(wx.EVT_MENU, self.OnMultiply, menu.Append(-1, 'Multiply'))
398 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
399 if self._selectedObj != self._focusObj and self._focusObj is not None:
400 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
401 if len(self._scene.objects()) > 0:
402 self.Bind(wx.EVT_MENU, self.OnDeleteAll, menu.Append(-1, 'Delete all'))
403 if menu.MenuItemCount > 0:
406 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
407 self._scene.pushFree()
409 elif self._mouseState == 'tool':
410 if self.tempMatrix is not None and self._selectedObj is not None:
411 self._selectedObj.applyMatrix(self.tempMatrix)
412 self.tempMatrix = None
413 self.tool.OnDragEnd()
415 self._mouseState = None
417 def OnMouseMotion(self,e):
418 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
419 p0 -= self.getObjectCenterPos() - self._viewTarget
420 p1 -= self.getObjectCenterPos() - self._viewTarget
422 if e.Dragging() and self._mouseState is not None:
423 if self._mouseState == 'tool':
424 self.tool.OnDrag(p0, p1)
425 elif not e.LeftIsDown() and e.RightIsDown():
426 self._mouseState = 'drag'
427 self._yaw += e.GetX() - self._mouseX
428 self._pitch -= e.GetY() - self._mouseY
429 if self._pitch > 170:
433 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
434 self._mouseState = 'drag'
435 self._zoom += e.GetY() - self._mouseY
438 if self._zoom > numpy.max(self._machineSize) * 3:
439 self._zoom = numpy.max(self._machineSize) * 3
440 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus and not self._isSimpleMode:
441 self._mouseState = 'dragObject'
442 z = max(0, self._mouseClick3DPos[2])
443 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
444 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
449 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
450 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
451 diff = cursorZ1 - cursorZ0
452 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
453 if not e.Dragging() or self._mouseState != 'tool':
454 self.tool.OnMouseMove(p0, p1)
456 self._mouseX = e.GetX()
457 self._mouseY = e.GetY()
459 def OnMouseWheel(self, e):
460 delta = float(e.GetWheelRotation()) / float(e.GetWheelDelta())
461 delta = max(min(delta,4),-4)
462 self._zoom *= 1.0 - delta / 10.0
465 if self._zoom > numpy.max(self._machineSize) * 3:
466 self._zoom = numpy.max(self._machineSize) * 3
469 def getMouseRay(self, x, y):
470 if self._viewport is None:
471 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
472 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
473 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
474 p0 -= self._viewTarget
475 p1 -= self._viewTarget
478 def _init3DView(self):
479 # set viewing projection
480 size = self.GetSize()
481 glViewport(0, 0, size.GetWidth(), size.GetHeight())
484 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
486 glDisable(GL_RESCALE_NORMAL)
487 glDisable(GL_LIGHTING)
489 glEnable(GL_DEPTH_TEST)
490 glDisable(GL_CULL_FACE)
492 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
494 glClearColor(0.8, 0.8, 0.8, 1.0)
498 glMatrixMode(GL_PROJECTION)
500 aspect = float(size.GetWidth()) / float(size.GetHeight())
501 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
503 glMatrixMode(GL_MODELVIEW)
505 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
508 if machineCom.machineIsConnected():
509 self.printButton._imageID = 6
510 self.printButton._tooltip = 'Print'
511 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
512 self.printButton._imageID = 2
513 self.printButton._tooltip = 'Toolpath to SD'
515 self.printButton._imageID = 3
516 self.printButton._tooltip = 'Save toolpath'
518 if self._animView is not None:
519 self._viewTarget = self._animView.getPosition()
520 if self._animView.isDone():
521 self._animView = None
522 if self._animZoom is not None:
523 self._zoom = self._animZoom.getPosition()
524 if self._animZoom.isDone():
525 self._animZoom = None
526 if self._objectShader is None:
527 self._objectShader = opengl.GLShader("""
528 varying float light_amount;
532 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
533 gl_FrontColor = gl_Color;
535 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
539 varying float light_amount;
543 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
546 self._objectLoadShader = opengl.GLShader("""
547 uniform float intensity;
549 varying float light_amount;
553 vec4 tmp = gl_Vertex;
554 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
555 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
556 gl_Position = gl_ModelViewProjectionMatrix * tmp;
557 gl_FrontColor = gl_Color;
559 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
563 uniform float intensity;
564 varying float light_amount;
568 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
572 glTranslate(0,0,-self._zoom)
573 glRotate(-self._pitch, 1,0,0)
574 glRotate(self._yaw, 0,0,1)
575 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
577 self._viewport = glGetIntegerv(GL_VIEWPORT)
578 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
579 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
581 glClearColor(1,1,1,1)
582 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
584 for n in xrange(0, len(self._scene.objects())):
585 obj = self._scene.objects()[n]
586 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
587 self._renderObject(obj)
589 if self._mouseX > -1:
590 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
591 if n < len(self._scene.objects()):
592 self._focusObj = self._scene.objects()[n]
594 self._focusObj = None
595 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
596 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
597 self._mouse3Dpos -= self._viewTarget
600 glTranslate(0,0,-self._zoom)
601 glRotate(-self._pitch, 1,0,0)
602 glRotate(self._yaw, 0,0,1)
603 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
605 glStencilFunc(GL_ALWAYS, 1, 1)
606 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
607 self._objectShader.bind()
608 for obj in self._scene.objects():
609 if obj._loadAnim is not None:
610 if obj._loadAnim.isDone():
615 glDisable(GL_STENCIL_TEST)
616 if self._selectedObj == obj:
617 glEnable(GL_STENCIL_TEST)
618 if self._focusObj == obj:
620 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
622 if not self._scene.checkPlatform(obj):
623 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
624 self._renderObject(obj)
626 self._renderObject(obj, brightness)
627 self._objectShader.unbind()
629 glDisable(GL_STENCIL_TEST)
631 self._objectLoadShader.bind()
632 glColor4f(0.2, 0.6, 1.0, 1.0)
633 for obj in self._scene.objects():
634 if obj._loadAnim is None:
636 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
637 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
638 self._renderObject(obj)
639 self._objectLoadShader.unbind()
644 #Draw the object box-shadow, so you can see where it will collide with other objects.
645 if self._selectedObj is not None and len(self._scene.objects()) > 1:
646 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
648 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0.0)
650 glEnable(GL_CULL_FACE)
651 glColor4f(0,0,0,0.12)
653 glVertex3f(-size[0], size[1], 0.1)
654 glVertex3f(-size[0], -size[1], 0.1)
655 glVertex3f( size[0], -size[1], 0.1)
656 glVertex3f( size[0], size[1], 0.1)
658 glDisable(GL_CULL_FACE)
661 #Draw the outline of the selected object, on top of everything else except the GUI.
662 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
663 glDisable(GL_DEPTH_TEST)
664 glEnable(GL_CULL_FACE)
665 glEnable(GL_STENCIL_TEST)
667 glStencilFunc(GL_EQUAL, 0, 255)
669 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
672 self._renderObject(self._selectedObj)
673 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
675 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
676 glDisable(GL_STENCIL_TEST)
677 glDisable(GL_CULL_FACE)
678 glEnable(GL_DEPTH_TEST)
680 if self._selectedObj is not None:
682 pos = self.getObjectCenterPos()
683 glTranslate(pos[0], pos[1], pos[2])
687 def _renderObject(self, obj, brightness = False):
689 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
691 if self.tempMatrix is not None and obj == self._selectedObj:
692 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
693 glMultMatrixf(tempMatrix)
695 offset = obj.getDrawOffset()
696 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
698 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
699 glMultMatrixf(tempMatrix)
702 for m in obj._meshList:
704 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
706 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
711 def _drawMachine(self):
712 glEnable(GL_CULL_FACE)
715 if profile.getPreference('machine_type') == 'ultimaker':
717 self._objectShader.bind()
718 self._renderObject(self._platformMesh)
719 self._objectShader.unbind()
721 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
722 v0 = [ size[0] / 2, size[1] / 2, size[2]]
723 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
724 v2 = [-size[0] / 2, size[1] / 2, size[2]]
725 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
726 v4 = [ size[0] / 2, size[1] / 2, 0]
727 v5 = [ size[0] / 2,-size[1] / 2, 0]
728 v6 = [-size[0] / 2, size[1] / 2, 0]
729 v7 = [-size[0] / 2,-size[1] / 2, 0]
731 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
732 glEnableClientState(GL_VERTEX_ARRAY)
733 glVertexPointer(3, GL_FLOAT, 3*4, vList)
735 glColor4ub(5, 171, 231, 64)
736 glDrawArrays(GL_QUADS, 0, 4)
737 glColor4ub(5, 171, 231, 96)
738 glDrawArrays(GL_QUADS, 4, 8)
739 glColor4ub(5, 171, 231, 128)
740 glDrawArrays(GL_QUADS, 12, 8)
742 sx = self._machineSize[0]
743 sy = self._machineSize[1]
744 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
745 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
750 x1 = max(min(x1, sx/2), -sx/2)
751 y1 = max(min(y1, sy/2), -sy/2)
752 x2 = max(min(x2, sx/2), -sx/2)
753 y2 = max(min(y2, sy/2), -sy/2)
754 if (x & 1) == (y & 1):
755 glColor4ub(5, 171, 231, 127)
757 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
759 glVertex3f(x1, y1, -0.02)
760 glVertex3f(x2, y1, -0.02)
761 glVertex3f(x2, y2, -0.02)
762 glVertex3f(x1, y2, -0.02)
765 glDisableClientState(GL_VERTEX_ARRAY)
767 glDisable(GL_CULL_FACE)
769 def getObjectCenterPos(self):
770 if self._selectedObj is None:
771 return [0.0, 0.0, 0.0]
772 pos = self._selectedObj.getPosition()
773 size = self._selectedObj.getSize()
774 return [pos[0], pos[1], size[2]/2]
776 def getObjectBoundaryCircle(self):
777 if self._selectedObj is None:
779 return self._selectedObj.getBoundaryCircle()
781 def getObjectSize(self):
782 if self._selectedObj is None:
783 return [0.0, 0.0, 0.0]
784 return self._selectedObj.getSize()
786 def getObjectMatrix(self):
787 if self._selectedObj is None:
788 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
789 return self._selectedObj.getMatrix()
791 class shaderEditor(wx.Dialog):
792 def __init__(self, parent, callback, v, f):
793 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
794 self._callback = callback
795 s = wx.BoxSizer(wx.VERTICAL)
797 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
798 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
799 s.Add(self._vertex, 1, flag=wx.EXPAND)
800 s.Add(self._fragment, 1, flag=wx.EXPAND)
802 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
803 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
805 self.SetPosition(self.GetParent().GetPosition())
806 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
810 self._callback(self._vertex.GetValue(), self._fragment.GetValue())