1 from __future__ import division
\r
10 from wx import glcanvas
\r
14 OpenGL.ERROR_CHECKING = False
\r
15 from OpenGL.GLU import *
\r
16 from OpenGL.GL import *
\r
17 hasOpenGLlibs = True
\r
19 print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
\r
20 hasOpenGLlibs = False
\r
22 from gui import opengl
\r
23 from gui import toolbarUtil
\r
25 from util import profile
\r
26 from util import gcodeInterpreter
\r
27 from util import stl
\r
28 from util import util3d
\r
30 class previewObject():
\r
33 self.filename = None
\r
34 self.displayList = None
\r
37 class previewPanel(wx.Panel):
\r
38 def __init__(self, parent):
\r
39 super(previewPanel, self).__init__(parent,-1)
\r
41 self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW))
\r
42 self.SetMinSize((440,320))
\r
44 self.glCanvas = PreviewGLCanvas(self)
\r
45 self.objectList = []
\r
47 self.objectsMinV = None
\r
48 self.objectsMaxV = None
\r
49 self.loadThread = None
\r
50 self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
\r
51 self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)
\r
53 self.toolbar = toolbarUtil.Toolbar(self)
\r
56 toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick)
\r
57 toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick)
\r
58 self.toolbar.AddSeparator()
\r
61 self.normalViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-normal-on.png', 'view-normal-off.png', 'Normal model view', callback=self.OnViewChange)
\r
62 self.transparentViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-transparent-on.png', 'view-transparent-off.png', 'Transparent model view', callback=self.OnViewChange)
\r
63 self.xrayViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-xray-on.png', 'view-xray-off.png', 'X-Ray view', callback=self.OnViewChange)
\r
64 self.gcodeViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-gcode-on.png', 'view-gcode-off.png', 'GCode view', callback=self.OnViewChange)
\r
65 self.mixedViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-mixed-on.png', 'view-mixed-off.png', 'Mixed model/GCode view', callback=self.OnViewChange)
\r
67 self.toolbar.AddSeparator()
\r
69 self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
\r
70 self.toolbar.AddControl(self.layerSpin)
\r
71 self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin)
\r
73 self.toolbar2 = toolbarUtil.Toolbar(self)
\r
76 self.mirrorX = toolbarUtil.ToggleButton(self.toolbar2, 'flip_x', 'object-mirror-x-on.png', 'object-mirror-x-off.png', 'Mirror X', callback=self.updateModelTransform)
\r
77 self.mirrorY = toolbarUtil.ToggleButton(self.toolbar2, 'flip_y', 'object-mirror-y-on.png', 'object-mirror-y-off.png', 'Mirror Y', callback=self.updateModelTransform)
\r
78 self.mirrorZ = toolbarUtil.ToggleButton(self.toolbar2, 'flip_z', 'object-mirror-z-on.png', 'object-mirror-z-off.png', 'Mirror Z', callback=self.updateModelTransform)
\r
79 self.toolbar2.AddSeparator()
\r
82 self.swapXZ = toolbarUtil.ToggleButton(self.toolbar2, 'swap_xz', 'object-swap-xz-on.png', 'object-swap-xz-off.png', 'Swap XZ', callback=self.updateModelTransform)
\r
83 self.swapYZ = toolbarUtil.ToggleButton(self.toolbar2, 'swap_yz', 'object-swap-yz-on.png', 'object-swap-yz-off.png', 'Swap YZ', callback=self.updateModelTransform)
\r
84 self.toolbar2.AddSeparator()
\r
87 self.scaleReset = toolbarUtil.NormalButton(self.toolbar2, self.OnScaleReset, 'object-scale.png', 'Reset model scale')
\r
88 self.scale = wx.TextCtrl(self.toolbar2, -1, profile.getProfileSetting('model_scale'), size=(21*2,21))
\r
89 self.toolbar2.AddControl(self.scale)
\r
90 self.scale.Bind(wx.EVT_TEXT, self.OnScale)
\r
91 self.scaleMax = toolbarUtil.NormalButton(self.toolbar2, self.OnScaleMax, 'object-max-size.png', 'Scale object to fix machine size')
\r
93 self.toolbar2.AddSeparator()
\r
96 #self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')
\r
97 #self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')
\r
98 #self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')
\r
99 #self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')
\r
100 #self.toolbar2.AddSeparator()
\r
103 self.rotateReset = toolbarUtil.NormalButton(self.toolbar2, self.OnRotateReset, 'object-rotate.png', 'Reset model rotation')
\r
104 self.rotate = wx.SpinCtrl(self.toolbar2, -1, profile.getProfileSetting('model_rotate_base'), size=(21*3,21), style=wx.SP_WRAP|wx.SP_ARROW_KEYS)
\r
105 self.rotate.SetRange(0, 360)
\r
106 self.Bind(wx.EVT_TEXT, self.OnRotate)
\r
107 self.toolbar2.AddControl(self.rotate)
\r
109 self.toolbar2.Realize()
\r
110 self.updateToolbar()
\r
112 sizer = wx.BoxSizer(wx.VERTICAL)
\r
113 sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
\r
114 sizer.Add(self.glCanvas, 1, flag=wx.EXPAND)
\r
115 sizer.Add(self.toolbar2, 0, flag=wx.EXPAND|wx.BOTTOM|wx.LEFT|wx.RIGHT, border=1)
\r
116 self.SetSizer(sizer)
\r
118 def OnMulXAddClick(self, e):
\r
119 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1)))
\r
120 self.glCanvas.Refresh()
\r
122 def OnMulXSubClick(self, e):
\r
123 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))-1)))
\r
124 self.glCanvas.Refresh()
\r
126 def OnMulYAddClick(self, e):
\r
127 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))+1)))
\r
128 self.glCanvas.Refresh()
\r
130 def OnMulYSubClick(self, e):
\r
131 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))-1)))
\r
132 self.glCanvas.Refresh()
\r
134 def OnScaleReset(self, e):
\r
135 self.scale.SetValue('1.0')
\r
138 def OnScale(self, e):
\r
140 if self.scale.GetValue() != '':
\r
141 scale = self.scale.GetValue()
\r
142 profile.putProfileSetting('model_scale', scale)
\r
143 self.glCanvas.Refresh()
\r
145 def OnScaleMax(self, e):
\r
146 if self.objectsMinV == None:
\r
148 vMin = self.objectsMinV
\r
149 vMax = self.objectsMaxV
\r
150 scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
\r
151 scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
\r
152 scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
\r
153 scaleY2 = (self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
\r
154 scaleZ = self.machineSize.z / (vMax.z - vMin.z)
\r
155 scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ)
\r
156 self.scale.SetValue(str(scale))
\r
157 profile.putProfileSetting('model_scale', self.scale.GetValue())
\r
158 self.glCanvas.Refresh()
\r
160 def OnRotateReset(self, e):
\r
161 self.rotate.SetValue(0)
\r
162 self.OnRotate(None)
\r
164 def OnRotate(self, e):
\r
165 profile.putProfileSetting('model_rotate_base', self.rotate.GetValue())
\r
166 self.updateModelTransform()
\r
168 def On3DClick(self):
\r
169 self.glCanvas.yaw = 30
\r
170 self.glCanvas.pitch = 60
\r
171 self.glCanvas.zoom = 300
\r
172 self.glCanvas.view3D = True
\r
173 self.glCanvas.Refresh()
\r
175 def OnTopClick(self):
\r
176 self.glCanvas.view3D = False
\r
177 self.glCanvas.zoom = 100
\r
178 self.glCanvas.offsetX = 0
\r
179 self.glCanvas.offsetY = 0
\r
180 self.glCanvas.Refresh()
\r
182 def OnLayerNrChange(self, e):
\r
183 self.gcodeDirty = True
\r
184 self.glCanvas.Refresh()
\r
186 def updateCenterX(self):
\r
187 self.machineCenter.x = profile.getProfileSettingFloat('machine_center_x')
\r
188 self.glCanvas.Refresh()
\r
190 def updateCenterY(self):
\r
191 self.machineCenter.y = profile.getProfileSettingFloat('machine_center_y')
\r
192 self.glCanvas.Refresh()
\r
194 def setViewMode(self, mode):
\r
195 if mode == "Normal":
\r
196 self.normalViewButton.SetValue(True)
\r
197 if mode == "GCode":
\r
198 self.gcodeViewButton.SetValue(True)
\r
199 self.glCanvas.viewMode = mode
\r
200 wx.CallAfter(self.glCanvas.Refresh)
\r
202 def loadModelFiles(self, filelist):
\r
203 while len(filelist) > len(self.objectList):
\r
204 self.objectList.append(previewObject())
\r
205 for idx in xrange(len(filelist), len(self.objectList)):
\r
206 self.objectList[idx].mesh = None
\r
207 self.objectList[idx].filename = None
\r
208 for idx in xrange(0, len(filelist)):
\r
209 obj = self.objectList[idx]
\r
210 if obj.filename != filelist[idx]:
\r
211 obj.fileTime = None
\r
212 self.gcodeFileTime = None
\r
213 self.logFileTime = None
\r
214 obj.filename = filelist[idx]
\r
216 self.gcodeFilename = filelist[0][: filelist[0].rfind('.')] + "_export.gcode"
\r
217 self.logFilename = filelist[0][: filelist[0].rfind('.')] + "_export.log"
\r
218 #Do the STL file loading in a background thread so we don't block the UI.
\r
219 if self.loadThread != None and self.loadThread.isAlive():
\r
220 self.loadThread.join()
\r
221 self.loadThread = threading.Thread(target=self.doFileLoadThread)
\r
222 self.loadThread.daemon = True
\r
223 self.loadThread.start()
\r
225 def loadReModelFiles(self, filelist):
\r
226 #Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
\r
227 for idx in xrange(0, len(filelist)):
\r
228 if self.objectList[idx].filename != filelist[idx]:
\r
230 self.loadModelFiles(filelist)
\r
233 def doFileLoadThread(self):
\r
234 for obj in self.objectList:
\r
235 if obj.filename != None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:
\r
236 obj.ileTime = os.stat(obj.filename).st_mtime
\r
237 mesh = stl.stlModel()
\r
238 mesh.load(obj.filename)
\r
242 self.updateModelTransform()
\r
243 wx.CallAfter(self.updateToolbar)
\r
244 wx.CallAfter(self.glCanvas.Refresh)
\r
246 if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:
\r
247 self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime
\r
248 gcode = gcodeInterpreter.gcode()
\r
249 gcode.progressCallback = self.loadProgress
\r
250 gcode.load(self.gcodeFilename)
\r
251 self.gcodeDirty = False
\r
252 self.errorList = []
\r
254 self.gcodeDirty = True
\r
255 wx.CallAfter(self.updateToolbar)
\r
256 wx.CallAfter(self.glCanvas.Refresh)
\r
257 elif not os.path.isfile(self.gcodeFilename):
\r
260 if os.path.isfile(self.logFilename):
\r
262 for line in open(self.logFilename, "rt"):
\r
263 res = re.search('Model error\(([a-z ]*)\): \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\) \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\)', line)
\r
265 v1 = util3d.Vector3(float(res.group(2)), float(res.group(3)), float(res.group(4)))
\r
266 v2 = util3d.Vector3(float(res.group(5)), float(res.group(6)), float(res.group(7)))
\r
267 errorList.append([v1, v2])
\r
268 self.errorList = errorList
\r
269 wx.CallAfter(self.glCanvas.Refresh)
\r
271 def loadProgress(self, progress):
\r
274 def updateToolbar(self):
\r
275 self.layerSpin.Show(self.gcode != None)
\r
276 if self.gcode != None:
\r
277 self.layerSpin.SetRange(1, len(self.gcode.layerList))
\r
278 self.toolbar.Realize()
\r
280 def OnViewChange(self):
\r
281 if self.normalViewButton.GetValue():
\r
282 self.glCanvas.viewMode = "Normal"
\r
283 elif self.transparentViewButton.GetValue():
\r
284 self.glCanvas.viewMode = "Transparent"
\r
285 elif self.xrayViewButton.GetValue():
\r
286 self.glCanvas.viewMode = "X-Ray"
\r
287 elif self.gcodeViewButton.GetValue():
\r
288 self.glCanvas.viewMode = "GCode"
\r
289 elif self.mixedViewButton.GetValue():
\r
290 self.glCanvas.viewMode = "Mixed"
\r
291 self.glCanvas.Refresh()
\r
293 def updateModelTransform(self, f=0):
\r
294 rotate = profile.getProfileSettingFloat('model_rotate_base') / 180.0 * math.pi
\r
298 if profile.getProfileSetting('flip_x') == 'True':
\r
300 if profile.getProfileSetting('flip_y') == 'True':
\r
302 if profile.getProfileSetting('flip_z') == 'True':
\r
304 swapXZ = profile.getProfileSetting('swap_xz') == 'True'
\r
305 swapYZ = profile.getProfileSetting('swap_yz') == 'True'
\r
306 mat00 = math.cos(rotate) * scaleX
\r
307 mat01 =-math.sin(rotate) * scaleY
\r
308 mat10 = math.sin(rotate) * scaleX
\r
309 mat11 = math.cos(rotate) * scaleY
\r
311 if len(self.objectList) < 1 or self.objectList[0].mesh == None:
\r
314 for obj in self.objectList:
\r
315 if obj.mesh == None:
\r
318 for i in xrange(0, len(obj.mesh.origonalVertexes)):
\r
319 x = obj.mesh.origonalVertexes[i].x
\r
320 y = obj.mesh.origonalVertexes[i].y
\r
321 z = obj.mesh.origonalVertexes[i].z
\r
326 obj.mesh.vertexes[i].x = x * mat00 + y * mat01
\r
327 obj.mesh.vertexes[i].y = x * mat10 + y * mat11
\r
328 obj.mesh.vertexes[i].z = z * scaleZ
\r
330 for face in obj.mesh.faces:
\r
334 face.normal = (v2 - v1).cross(v3 - v1)
\r
335 face.normal.normalize()
\r
337 minV = self.objectList[0].mesh.getMinimum()
\r
338 maxV = self.objectList[0].mesh.getMaximum()
\r
339 for obj in self.objectList:
\r
340 if obj.mesh == None:
\r
343 obj.mesh.getMinimumZ()
\r
344 minV = minV.min(obj.mesh.getMinimum())
\r
345 maxV = maxV.max(obj.mesh.getMaximum())
\r
347 self.objectsMaxV = maxV
\r
348 self.objectsMinV = minV
\r
349 for obj in self.objectList:
\r
350 if obj.mesh == None:
\r
353 for v in obj.mesh.vertexes:
\r
355 v.x -= minV.x + (maxV.x - minV.x) / 2
\r
356 v.y -= minV.y + (maxV.y - minV.y) / 2
\r
357 obj.mesh.getMinimumZ()
\r
359 self.glCanvas.Refresh()
\r
361 class PreviewGLCanvas(glcanvas.GLCanvas):
\r
362 def __init__(self, parent):
\r
363 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
\r
364 glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)
\r
365 self.parent = parent
\r
366 self.context = glcanvas.GLContext(self)
\r
367 wx.EVT_PAINT(self, self.OnPaint)
\r
368 wx.EVT_SIZE(self, self.OnSize)
\r
369 wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
\r
370 wx.EVT_MOTION(self, self.OnMouseMotion)
\r
371 wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
\r
378 self.gcodeDisplayList = None
\r
379 self.objColor = [[1.0, 0.8, 0.6, 1.0], [0.2, 1.0, 0.1, 1.0], [1.0, 0.2, 0.1, 1.0], [0.1, 0.2, 1.0, 1.0]]
\r
381 def OnMouseMotion(self,e):
\r
382 if e.Dragging() and e.LeftIsDown():
\r
384 self.yaw += e.GetX() - self.oldX
\r
385 self.pitch -= e.GetY() - self.oldY
\r
386 if self.pitch > 170:
\r
388 if self.pitch < 10:
\r
391 self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2
\r
392 self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2
\r
394 if e.Dragging() and e.RightIsDown():
\r
395 self.zoom += e.GetY() - self.oldY
\r
399 self.oldX = e.GetX()
\r
400 self.oldY = e.GetY()
\r
402 def OnMouseWheel(self,e):
\r
403 self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
\r
404 if self.zoom < 1.0:
\r
408 def OnEraseBackground(self,event):
\r
409 #Workaround for windows background redraw flicker.
\r
412 def OnSize(self,event):
\r
415 def OnPaint(self,event):
\r
416 dc = wx.PaintDC(self)
\r
417 if not hasOpenGLlibs:
\r
419 dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
\r
421 self.SetCurrent(self.context)
\r
422 opengl.InitGL(self, self.view3D, self.zoom)
\r
424 glTranslate(0,0,-self.zoom)
\r
425 glRotate(-self.pitch, 1,0,0)
\r
426 glRotate(self.yaw, 0,0,1)
\r
427 if self.parent.objectsMaxV != None:
\r
428 glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)
\r
430 glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
\r
431 glTranslate(self.offsetX, self.offsetY, 0.0)
\r
432 glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
\r
438 machineSize = self.parent.machineSize
\r
439 opengl.DrawMachine(machineSize)
\r
441 if self.parent.gcode != None:
\r
442 if self.gcodeDisplayList == None:
\r
443 self.gcodeDisplayList = glGenLists(1);
\r
444 if self.parent.gcodeDirty:
\r
445 self.parent.gcodeDirty = False
\r
446 glNewList(self.gcodeDisplayList, GL_COMPILE)
\r
450 layerThickness = 0.0
\r
451 filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
\r
452 filamentArea = math.pi * filamentRadius * filamentRadius
\r
453 lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2 / 10
\r
456 for layer in self.parent.gcode.layerList:
\r
457 curLayerZ = layer[0].list[1].z
\r
458 layerThickness = curLayerZ - prevLayerZ
\r
459 prevLayerZ = layer[-1].list[-1].z
\r
462 if curLayerNum != self.parent.layerSpin.GetValue():
\r
463 if curLayerNum < self.parent.layerSpin.GetValue():
\r
464 c = 0.9 - (self.parent.layerSpin.GetValue() - curLayerNum) * 0.1
\r
469 if path.type == 'move':
\r
471 if path.type == 'extrude':
\r
472 if path.pathType == 'FILL':
\r
473 glColor3f(c/2,c/2,0)
\r
474 elif path.pathType == 'WALL-INNER':
\r
476 elif path.pathType == 'SUPPORT':
\r
478 elif path.pathType == 'SKIRT':
\r
479 glColor3f(0,c/2,c/2)
\r
482 if path.type == 'retract':
\r
484 if c > 0.4 and path.type == 'extrude':
\r
485 for i in xrange(0, len(path.list)-1):
\r
487 v1 = path.list[i+1]
\r
489 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
\r
490 dist = (v0 - v1).vsize()
\r
491 if dist > 0 and layerThickness > 0:
\r
492 extrusionMMperDist = (v1.e - v0.e) / dist
\r
493 lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
\r
495 normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
\r
497 v2 = v0 + normal * lineWidth
\r
498 v3 = v1 + normal * lineWidth
\r
499 v0 = v0 - normal * lineWidth
\r
500 v1 = v1 - normal * lineWidth
\r
503 if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
504 glVertex3f(v0.x, v0.y, v0.z - 0.02)
\r
505 glVertex3f(v1.x, v1.y, v1.z - 0.02)
\r
506 glVertex3f(v3.x, v3.y, v3.z - 0.02)
\r
507 glVertex3f(v2.x, v2.y, v2.z - 0.02)
\r
509 glVertex3f(v0.x, v0.y, v0.z - 0.01)
\r
510 glVertex3f(v1.x, v1.y, v1.z - 0.01)
\r
511 glVertex3f(v3.x, v3.y, v3.z - 0.01)
\r
512 glVertex3f(v2.x, v2.y, v2.z - 0.01)
\r
515 #for v in path['list']:
\r
516 # glBegin(GL_TRIANGLE_FAN)
\r
517 # glVertex3f(v.x, v.y, v.z - 0.001)
\r
518 # for i in xrange(0, 16+1):
\r
519 # if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
520 # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.02)
\r
522 # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.01)
\r
525 glBegin(GL_LINE_STRIP)
\r
526 for v in path.list:
\r
527 glVertex3f(v.x, v.y, v.z)
\r
531 if self.viewMode == "GCode" or self.viewMode == "Mixed":
\r
532 glCallList(self.gcodeDisplayList)
\r
534 glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
\r
535 for obj in self.parent.objectList:
\r
536 if obj.mesh == None:
\r
538 if obj.displayList == None:
\r
539 obj.displayList = glGenLists(1);
\r
542 glNewList(obj.displayList, GL_COMPILE)
\r
543 opengl.DrawSTL(obj.mesh)
\r
546 glEnable(GL_NORMALIZE)
\r
547 if self.viewMode == "Transparent" or self.viewMode == "Mixed":
\r
548 glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x / 2, self.objColor[self.parent.objectList.index(obj)]))
\r
549 glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 10, self.objColor[self.parent.objectList.index(obj)]))
\r
550 #If we want transparent, then first render a solid black model to remove the printer size lines.
\r
551 if self.viewMode != "Mixed":
\r
552 glDisable(GL_BLEND)
\r
553 glDisable(GL_LIGHTING)
\r
555 self.drawModel(obj)
\r
557 #After the black model is rendered, render the model again but now with lighting and no depth testing.
\r
558 glDisable(GL_DEPTH_TEST)
\r
559 glEnable(GL_LIGHTING)
\r
561 glBlendFunc(GL_ONE, GL_ONE)
\r
562 glEnable(GL_LIGHTING)
\r
563 self.drawModel(obj)
\r
564 elif self.viewMode == "X-Ray":
\r
565 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
\r
566 glDisable(GL_DEPTH_TEST)
\r
567 glEnable(GL_STENCIL_TEST);
\r
568 glStencilFunc(GL_ALWAYS, 1, 1)
\r
569 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
\r
570 self.drawModel(obj)
\r
571 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
\r
573 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
\r
574 glStencilFunc(GL_EQUAL, 0, 1);
\r
576 self.drawModel(obj)
\r
577 glStencilFunc(GL_EQUAL, 1, 1);
\r
579 self.drawModel(obj)
\r
583 for i in xrange(2, 15, 2):
\r
584 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
585 glColor(float(i)/10, float(i)/10, float(i)/5)
\r
587 glVertex3f(-1000,-1000,-1)
\r
588 glVertex3f( 1000,-1000,-1)
\r
589 glVertex3f( 1000, 1000,-1)
\r
590 glVertex3f(-1000, 1000,-1)
\r
592 for i in xrange(1, 15, 2):
\r
593 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
594 glColor(float(i)/10, 0, 0)
\r
596 glVertex3f(-1000,-1000,-1)
\r
597 glVertex3f( 1000,-1000,-1)
\r
598 glVertex3f( 1000, 1000,-1)
\r
599 glVertex3f(-1000, 1000,-1)
\r
603 glDisable(GL_STENCIL_TEST);
\r
604 glEnable(GL_DEPTH_TEST)
\r
605 elif self.viewMode == "Normal":
\r
606 glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor[self.parent.objectList.index(obj)])
\r
607 glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 5, self.objColor[self.parent.objectList.index(obj)]))
\r
608 glEnable(GL_LIGHTING)
\r
609 self.drawModel(obj)
\r
611 if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":
\r
612 glDisable(GL_LIGHTING)
\r
613 glDisable(GL_DEPTH_TEST)
\r
614 glDisable(GL_BLEND)
\r
617 #for err in self.parent.errorList:
\r
618 # glVertex3f(err[0].x, err[0].y, err[0].z)
\r
619 # glVertex3f(err[1].x, err[1].y, err[1].z)
\r
621 glEnable(GL_DEPTH_TEST)
\r
624 def drawModel(self, obj):
\r
625 multiX = 1 #int(profile.getProfileSetting('model_multiply_x'))
\r
626 multiY = 1 #int(profile.getProfileSetting('model_multiply_y'))
\r
627 modelScale = profile.getProfileSettingFloat('model_scale')
\r
628 modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale
\r
630 glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
\r
631 for mx in xrange(0, multiX):
\r
632 for my in xrange(0, multiY):
\r
634 glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
\r
635 glScalef(modelScale, modelScale, modelScale)
\r
636 glCallList(obj.displayList)
\r