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)
134 defPath = profile.getPreference('lastFile')
135 defPath = defPath[0:defPath.rfind('.')] + '.gcode'
136 dlg=wx.FileDialog(self, 'Save toolpath', defPath, style=wx.FD_SAVE)
137 dlg.SetFilename(defPath)
138 dlg.SetWildcard('Toolpath (*.gcode)|*.gcode;*.g')
139 if dlg.ShowModal() != wx.ID_OK:
142 filename = dlg.GetPath()
145 shutil.copy(self._slicer.getGCodeFilename(), filename)
147 def OnToolSelect(self, button):
148 if self.rotateToolButton.getSelected():
149 self.tool = previewTools.toolRotate(self)
150 elif self.scaleToolButton.getSelected():
151 self.tool = previewTools.toolScale(self)
152 elif self.mirrorToolButton.getSelected():
153 self.tool = previewTools.toolNone(self)
155 self.tool = previewTools.toolNone(self)
156 self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected())
157 self.layFlatButton.setHidden(not self.rotateToolButton.getSelected())
158 self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected())
159 self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected())
160 self.scaleForm.setHidden(not self.scaleToolButton.getSelected())
161 self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected())
162 self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected())
163 self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected())
165 def updateToolButtons(self):
166 if self._selectedObj is None:
170 self.rotateToolButton.setHidden(hidden)
171 self.scaleToolButton.setHidden(hidden)
172 self.mirrorToolButton.setHidden(hidden)
174 self.rotateToolButton.setSelected(False)
175 self.scaleToolButton.setSelected(False)
176 self.mirrorToolButton.setSelected(False)
179 def OnRotateReset(self, button):
180 if self._selectedObj is None:
182 self._selectedObj.resetRotation()
184 def OnLayFlat(self, button):
185 if self._selectedObj is None:
187 self._selectedObj.layFlat()
189 def OnScaleReset(self, button):
190 if self._selectedObj is None:
192 self._selectedObj.resetScale()
194 def OnScaleMax(self, button):
195 if self._selectedObj is None:
197 self._selectedObj.scaleUpTo(self._machineSize - numpy.array(profile.calculateObjectSizeOffsets() + [0.0], numpy.float32) * 2)
199 def OnMirror(self, axis):
200 if self._selectedObj is None:
202 self._selectedObj.mirror(axis)
205 def OnScaleEntry(self, value, axis):
206 if self._selectedObj is None:
212 self._selectedObj.setScale(value, axis, self.scaleUniform.getValue())
213 self.updateProfileToControls()
216 def OnScaleEntryMM(self, value, axis):
217 if self._selectedObj is None:
223 self._selectedObj.setSize(value, axis, self.scaleUniform.getValue())
224 self.updateProfileToControls()
227 def OnDuplicateObject(self, e):
228 if self._selectedObj is None:
230 self._scene.add(self._selectedObj.copy())
231 self._scene.centerAll()
234 def OnSplitObject(self, e):
235 if self._selectedObj is None:
237 self._scene.remove(self._selectedObj)
238 for obj in self._selectedObj.split():
240 self._scene.centerAll()
241 self._selectObject(None)
244 def OnMergeObjects(self, e):
245 if self._selectedObj is None or self._focusObj is None or self._selectedObj == self._focusObj:
247 self._scene.merge(self._selectedObj, self._focusObj)
250 def sceneUpdated(self):
251 self._sceneUpdateTimer.Start(1, True)
252 self._slicer.abortSlicer()
253 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
256 def _updateSliceProgress(self, progressValue, ready):
257 self.printButton.setDisabled(not ready)
258 self.printButton.setProgressBar(progressValue)
261 def loadScene(self, fileList):
262 for filename in fileList:
264 objList = meshLoader.loadMeshes(filename)
266 traceback.print_exc()
269 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
271 self._scene.centerAll()
272 self._selectObject(obj)
275 def _deleteObject(self, obj):
276 if obj == self._selectedObj:
277 self._selectObject(None)
278 if obj == self._focusObj:
279 self._focusObj = None
280 self._scene.remove(obj)
281 for m in obj._meshList:
282 if m.vbo is not None and m.vbo.decRef():
283 self.glReleaseList.append(m.vbo)
284 if self._isSimpleMode:
285 self._scene.arrangeAll()
288 def _selectObject(self, obj, zoom = True):
289 if obj != self._selectedObj:
290 self._selectedObj = obj
291 self.updateProfileToControls()
292 self.updateToolButtons()
293 if zoom and obj is not None:
294 newViewPos = numpy.array([obj.getPosition()[0], obj.getPosition()[1], obj.getMaximum()[2] / 2])
295 self._animView = openglGui.animation(self, self._viewTarget.copy(), newViewPos, 0.5)
296 newZoom = obj.getBoundaryCircle() * 6
297 if newZoom > numpy.max(self._machineSize) * 3:
298 newZoom = numpy.max(self._machineSize) * 3
299 self._animZoom = openglGui.animation(self, self._zoom, newZoom, 0.5)
301 def updateProfileToControls(self):
302 oldSimpleMode = self._isSimpleMode
303 self._isSimpleMode = profile.getPreference('startMode') == 'Simple'
304 if self._isSimpleMode and not oldSimpleMode:
305 self._scene.arrangeAll()
307 self._machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')])
308 self._objColors[0] = profile.getPreferenceColour('model_colour')
309 self._objColors[1] = profile.getPreferenceColour('model_colour2')
310 self._objColors[2] = profile.getPreferenceColour('model_colour3')
311 self._objColors[3] = profile.getPreferenceColour('model_colour4')
312 self._scene.setMachineSize(self._machineSize)
313 self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
314 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'))
316 if self._selectedObj is not None:
317 scale = self._selectedObj.getScale()
318 size = self._selectedObj.getSize()
319 self.scaleXctrl.setValue(round(scale[0], 2))
320 self.scaleYctrl.setValue(round(scale[1], 2))
321 self.scaleZctrl.setValue(round(scale[2], 2))
322 self.scaleXmmctrl.setValue(round(size[0], 2))
323 self.scaleYmmctrl.setValue(round(size[1], 2))
324 self.scaleZmmctrl.setValue(round(size[2], 2))
326 def OnKeyChar(self, keyCode):
327 if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE:
328 if self._selectedObj is not None:
329 self._deleteObject(self._selectedObj)
332 if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
333 shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
335 def ShaderUpdate(self, v, f):
336 s = opengl.GLShader(v, f)
338 self._objectLoadShader.release()
339 self._objectLoadShader = s
340 for obj in self._scene.objects():
341 obj._loadAnim = openglGui.animation(self, 1, 0, 1.5)
344 def OnMouseDown(self,e):
345 self._mouseX = e.GetX()
346 self._mouseY = e.GetY()
347 self._mouseClick3DPos = self._mouse3Dpos
348 self._mouseClickFocus = self._focusObj
350 self._mouseState = 'doubleClick'
352 self._mouseState = 'dragOrClick'
353 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
354 p0 -= self.getObjectCenterPos() - self._viewTarget
355 p1 -= self.getObjectCenterPos() - self._viewTarget
356 if self.tool.OnDragStart(p0, p1):
357 self._mouseState = 'tool'
358 if self._mouseState == 'dragOrClick':
359 if e.GetButton() == 1:
360 if self._focusObj is not None:
361 self._selectObject(self._focusObj, False)
364 def OnMouseUp(self, e):
365 if e.LeftIsDown() or e.MiddleIsDown() or e.RightIsDown():
367 if self._mouseState == 'dragOrClick':
368 if e.GetButton() == 1:
369 self._selectObject(self._focusObj)
370 if e.GetButton() == 3:
371 if self._selectedObj is not None:
373 self.Bind(wx.EVT_MENU, lambda e: self._deleteObject(self._selectedObj), menu.Append(-1, 'Delete'))
374 if self._selectedObj == self._focusObj:
375 self.Bind(wx.EVT_MENU, self.OnDuplicateObject, menu.Append(-1, 'Duplicate'))
376 self.Bind(wx.EVT_MENU, self.OnSplitObject, menu.Append(-1, 'Split'))
377 if self._selectedObj != self._focusObj and self._focusObj is not None:
378 self.Bind(wx.EVT_MENU, self.OnMergeObjects, menu.Append(-1, 'Dual extrusion merge'))
379 if menu.MenuItemCount > 0:
382 elif self._mouseState == 'dragObject' and self._selectedObj is not None:
383 self._scene.pushFree()
385 elif self._mouseState == 'tool':
386 if self.tempMatrix is not None and self._selectedObj is not None:
387 self._selectedObj.applyMatrix(self.tempMatrix)
388 self.tempMatrix = None
389 self.tool.OnDragEnd()
391 self._mouseState = None
393 def OnMouseMotion(self,e):
394 p0, p1 = self.getMouseRay(e.GetX(), e.GetY())
395 p0 -= self.getObjectCenterPos() - self._viewTarget
396 p1 -= self.getObjectCenterPos() - self._viewTarget
398 if e.Dragging() and self._mouseState is not None:
399 if self._mouseState == 'tool':
400 self.tool.OnDrag(p0, p1)
401 elif not e.LeftIsDown() and e.RightIsDown():
402 self._mouseState = 'drag'
403 self._yaw += e.GetX() - self._mouseX
404 self._pitch -= e.GetY() - self._mouseY
405 if self._pitch > 170:
409 elif (e.LeftIsDown() and e.RightIsDown()) or e.MiddleIsDown():
410 self._mouseState = 'drag'
411 self._zoom += e.GetY() - self._mouseY
414 if self._zoom > numpy.max(self._machineSize) * 3:
415 self._zoom = numpy.max(self._machineSize) * 3
416 elif e.LeftIsDown() and self._selectedObj is not None and self._selectedObj == self._mouseClickFocus and not self._isSimpleMode:
417 self._mouseState = 'dragObject'
418 z = max(0, self._mouseClick3DPos[2])
419 p0, p1 = self.getMouseRay(self._mouseX, self._mouseY)
420 p2, p3 = self.getMouseRay(e.GetX(), e.GetY())
425 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
426 cursorZ1 = p2 - (p3 - p2) * (p2[2] / (p3[2] - p2[2]))
427 diff = cursorZ1 - cursorZ0
428 self._selectedObj.setPosition(self._selectedObj.getPosition() + diff[0:2])
429 if not e.Dragging() or self._mouseState != 'tool':
430 self.tool.OnMouseMove(p0, p1)
432 self._mouseX = e.GetX()
433 self._mouseY = e.GetY()
435 def OnMouseWheel(self, e):
436 self._zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
439 if self._zoom > numpy.max(self._machineSize) * 3:
440 self._zoom = numpy.max(self._machineSize) * 3
443 def getMouseRay(self, x, y):
444 if self._viewport is None:
445 return numpy.array([0,0,0],numpy.float32), numpy.array([0,0,1],numpy.float32)
446 p0 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 0, self._modelMatrix, self._projMatrix, self._viewport)
447 p1 = opengl.unproject(x, self._viewport[1] + self._viewport[3] - y, 1, self._modelMatrix, self._projMatrix, self._viewport)
448 p0 -= self._viewTarget
449 p1 -= self._viewTarget
452 def _init3DView(self):
453 # set viewing projection
454 size = self.GetSize()
455 glViewport(0, 0, size.GetWidth(), size.GetHeight())
458 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
460 glDisable(GL_RESCALE_NORMAL)
461 glDisable(GL_LIGHTING)
463 glEnable(GL_DEPTH_TEST)
464 glDisable(GL_CULL_FACE)
466 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
468 glClearColor(0.8, 0.8, 0.8, 1.0)
472 glMatrixMode(GL_PROJECTION)
474 aspect = float(size.GetWidth()) / float(size.GetHeight())
475 gluPerspective(45.0, aspect, 1.0, numpy.max(self._machineSize) * 4)
477 glMatrixMode(GL_MODELVIEW)
479 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
482 if machineCom.machineIsConnected():
483 self.printButton._imageID = 6
484 self.printButton._tooltip = 'Print'
485 elif len(removableStorage.getPossibleSDcardDrives()) > 0:
486 self.printButton._imageID = 2
487 self.printButton._tooltip = 'Toolpath to SD'
489 self.printButton._imageID = 3
490 self.printButton._tooltip = 'Save toolpath'
492 if self._animView is not None:
493 self._viewTarget = self._animView.getPosition()
494 if self._animView.isDone():
495 self._animView = None
496 if self._animZoom is not None:
497 self._zoom = self._animZoom.getPosition()
498 if self._animZoom.isDone():
499 self._animZoom = None
500 if self._objectShader is None:
501 self._objectShader = opengl.GLShader("""
502 varying float light_amount;
506 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
507 gl_FrontColor = gl_Color;
509 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
513 varying float light_amount;
517 gl_FragColor = vec4(gl_Color.xyz * light_amount, gl_Color[3]);
520 self._objectLoadShader = opengl.GLShader("""
521 uniform float intensity;
523 varying float light_amount;
527 vec4 tmp = gl_Vertex;
528 tmp.x += sin(tmp.z/5.0+intensity*30.0) * scale * intensity;
529 tmp.y += sin(tmp.z/3.0+intensity*40.0) * scale * intensity;
530 gl_Position = gl_ModelViewProjectionMatrix * tmp;
531 gl_FrontColor = gl_Color;
533 light_amount = abs(dot(normalize(gl_NormalMatrix * gl_Normal), normalize(gl_LightSource[0].position.xyz)));
537 uniform float intensity;
538 varying float light_amount;
542 gl_FragColor = vec4(gl_Color.xyz * light_amount, 1.0-intensity);
546 glTranslate(0,0,-self._zoom)
547 glRotate(-self._pitch, 1,0,0)
548 glRotate(self._yaw, 0,0,1)
549 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
551 self._viewport = glGetIntegerv(GL_VIEWPORT)
552 self._modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
553 self._projMatrix = glGetDoublev(GL_PROJECTION_MATRIX)
555 glClearColor(1,1,1,1)
556 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
558 for n in xrange(0, len(self._scene.objects())):
559 obj = self._scene.objects()[n]
560 glColor4ub((n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF)
561 self._renderObject(obj)
563 if self._mouseX > -1:
564 n = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)[0][0]
565 if n < len(self._scene.objects()):
566 self._focusObj = self._scene.objects()[n]
568 self._focusObj = None
569 f = glReadPixels(self._mouseX, self.GetSize().GetHeight() - 1 - self._mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)[0][0]
570 self._mouse3Dpos = opengl.unproject(self._mouseX, self._viewport[1] + self._viewport[3] - self._mouseY, f, self._modelMatrix, self._projMatrix, self._viewport)
571 self._mouse3Dpos -= self._viewTarget
574 glTranslate(0,0,-self._zoom)
575 glRotate(-self._pitch, 1,0,0)
576 glRotate(self._yaw, 0,0,1)
577 glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
579 glStencilFunc(GL_ALWAYS, 1, 1)
580 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
581 self._objectShader.bind()
582 for obj in self._scene.objects():
583 if obj._loadAnim is not None:
584 if obj._loadAnim.isDone():
589 glDisable(GL_STENCIL_TEST)
590 if self._selectedObj == obj:
591 glEnable(GL_STENCIL_TEST)
592 if self._focusObj == obj:
594 elif self._focusObj is not None or self._selectedObj is not None and obj != self._selectedObj:
596 if not self._scene.checkPlatform(obj):
597 glColor4f(0.5 * brightness, 0.5 * brightness, 0.5 * brightness, 0.8 * brightness)
598 self._renderObject(obj)
600 self._renderObject(obj, brightness)
601 self._objectShader.unbind()
603 glDisable(GL_STENCIL_TEST)
605 self._objectLoadShader.bind()
606 glColor4f(0.2, 0.6, 1.0, 1.0)
607 for obj in self._scene.objects():
608 if obj._loadAnim is None:
610 self._objectLoadShader.setUniform('intensity', obj._loadAnim.getPosition())
611 self._objectLoadShader.setUniform('scale', obj.getBoundaryCircle() / 10)
612 self._renderObject(obj)
613 self._objectLoadShader.unbind()
618 #Draw the object box-shadow, so you can see where it will collide with other objects.
619 if self._selectedObj is not None and len(self._scene.objects()) > 1:
620 size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
622 glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0.0)
624 glEnable(GL_CULL_FACE)
625 glColor4f(0,0,0,0.12)
627 glVertex3f(-size[0], size[1], 0.1)
628 glVertex3f(-size[0], -size[1], 0.1)
629 glVertex3f( size[0], -size[1], 0.1)
630 glVertex3f( size[0], size[1], 0.1)
632 glDisable(GL_CULL_FACE)
635 #Draw the outline of the selected object, on top of everything else except the GUI.
636 if self._selectedObj is not None and self._selectedObj._loadAnim is None:
637 glDisable(GL_DEPTH_TEST)
638 glEnable(GL_CULL_FACE)
639 glEnable(GL_STENCIL_TEST)
641 glStencilFunc(GL_EQUAL, 0, 255)
643 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
646 self._renderObject(self._selectedObj)
647 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
649 glViewport(0, 0, self.GetSize().GetWidth(), self.GetSize().GetHeight())
650 glDisable(GL_STENCIL_TEST)
651 glDisable(GL_CULL_FACE)
652 glEnable(GL_DEPTH_TEST)
654 if self._selectedObj is not None:
656 pos = self.getObjectCenterPos()
657 glTranslate(pos[0], pos[1], pos[2])
661 def _renderObject(self, obj, brightness = False):
663 glTranslate(obj.getPosition()[0], obj.getPosition()[1], obj.getSize()[2] / 2)
665 if self.tempMatrix is not None and obj == self._selectedObj:
666 tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix)
667 glMultMatrixf(tempMatrix)
669 offset = obj.getDrawOffset()
670 glTranslate(-offset[0], -offset[1], -offset[2] - obj.getSize()[2] / 2)
672 tempMatrix = opengl.convert3x3MatrixTo4x4(obj.getMatrix())
673 glMultMatrixf(tempMatrix)
676 for m in obj._meshList:
678 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
680 glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
685 def _drawMachine(self):
686 glEnable(GL_CULL_FACE)
689 if profile.getPreference('machine_type') == 'ultimaker':
691 self._objectShader.bind()
692 self._renderObject(self._platformMesh)
693 self._objectShader.unbind()
695 size = [profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]
696 v0 = [ size[0] / 2, size[1] / 2, size[2]]
697 v1 = [ size[0] / 2,-size[1] / 2, size[2]]
698 v2 = [-size[0] / 2, size[1] / 2, size[2]]
699 v3 = [-size[0] / 2,-size[1] / 2, size[2]]
700 v4 = [ size[0] / 2, size[1] / 2, 0]
701 v5 = [ size[0] / 2,-size[1] / 2, 0]
702 v6 = [-size[0] / 2, size[1] / 2, 0]
703 v7 = [-size[0] / 2,-size[1] / 2, 0]
705 vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7]
706 glEnableClientState(GL_VERTEX_ARRAY)
707 glVertexPointer(3, GL_FLOAT, 3*4, vList)
709 glColor4ub(5, 171, 231, 64)
710 glDrawArrays(GL_QUADS, 0, 4)
711 glColor4ub(5, 171, 231, 96)
712 glDrawArrays(GL_QUADS, 4, 8)
713 glColor4ub(5, 171, 231, 128)
714 glDrawArrays(GL_QUADS, 12, 8)
716 sx = self._machineSize[0]
717 sy = self._machineSize[1]
718 for x in xrange(-int(sx/20)-1, int(sx / 20) + 1):
719 for y in xrange(-int(sx/20)-1, int(sy / 20) + 1):
724 x1 = max(min(x1, sx/2), -sx/2)
725 y1 = max(min(y1, sy/2), -sy/2)
726 x2 = max(min(x2, sx/2), -sx/2)
727 y2 = max(min(y2, sy/2), -sy/2)
728 if (x & 1) == (y & 1):
729 glColor4ub(5, 171, 231, 127)
731 glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
733 glVertex3f(x1, y1, -0.02)
734 glVertex3f(x2, y1, -0.02)
735 glVertex3f(x2, y2, -0.02)
736 glVertex3f(x1, y2, -0.02)
739 glDisableClientState(GL_VERTEX_ARRAY)
741 glDisable(GL_CULL_FACE)
743 def getObjectCenterPos(self):
744 if self._selectedObj is None:
745 return [0.0, 0.0, 0.0]
746 pos = self._selectedObj.getPosition()
747 size = self._selectedObj.getSize()
748 return [pos[0], pos[1], size[2]/2]
750 def getObjectBoundaryCircle(self):
751 if self._selectedObj is None:
753 return self._selectedObj.getBoundaryCircle()
755 def getObjectSize(self):
756 if self._selectedObj is None:
757 return [0.0, 0.0, 0.0]
758 return self._selectedObj.getSize()
760 def getObjectMatrix(self):
761 if self._selectedObj is None:
762 return numpy.matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
763 return self._selectedObj.getMatrix()
765 class shaderEditor(wx.Dialog):
766 def __init__(self, parent, callback, v, f):
767 super(shaderEditor, self).__init__(parent, title="Shader editor", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
768 self._callback = callback
769 s = wx.BoxSizer(wx.VERTICAL)
771 self._vertex = wx.TextCtrl(self, -1, v, style=wx.TE_MULTILINE)
772 self._fragment = wx.TextCtrl(self, -1, f, style=wx.TE_MULTILINE)
773 s.Add(self._vertex, 1, flag=wx.EXPAND)
774 s.Add(self._fragment, 1, flag=wx.EXPAND)
776 self._vertex.Bind(wx.EVT_TEXT, self.OnText, self._vertex)
777 self._fragment.Bind(wx.EVT_TEXT, self.OnText, self._fragment)
779 self.SetPosition(self.GetParent().GetPosition())
780 self.SetSize((self.GetSize().GetWidth(), self.GetParent().GetSize().GetHeight()))
784 self._callback(self._vertex.GetValue(), self._fragment.GetValue())