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
101 self.toolbar2.AddSeparator()
\r
104 self.rotateReset = toolbarUtil.NormalButton(self.toolbar2, self.OnRotateReset, 'object-rotate.png', 'Reset model rotation')
\r
105 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
106 self.rotate.SetRange(0, 360)
\r
107 self.Bind(wx.EVT_TEXT, self.OnRotate)
\r
108 self.toolbar2.AddControl(self.rotate)
\r
110 self.toolbar2.Realize()
\r
111 self.updateToolbar()
\r
113 sizer = wx.BoxSizer(wx.VERTICAL)
\r
114 sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
\r
115 sizer.Add(self.glCanvas, 1, flag=wx.EXPAND)
\r
116 sizer.Add(self.toolbar2, 0, flag=wx.EXPAND|wx.BOTTOM|wx.LEFT|wx.RIGHT, border=1)
\r
117 self.SetSizer(sizer)
\r
119 def OnMulXAddClick(self, e):
\r
120 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1)))
\r
121 self.glCanvas.Refresh()
\r
123 def OnMulXSubClick(self, e):
\r
124 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))-1)))
\r
125 self.glCanvas.Refresh()
\r
127 def OnMulYAddClick(self, e):
\r
128 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))+1)))
\r
129 self.glCanvas.Refresh()
\r
131 def OnMulYSubClick(self, e):
\r
132 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))-1)))
\r
133 self.glCanvas.Refresh()
\r
135 def OnScaleReset(self, e):
\r
136 self.scale.SetValue('1.0')
\r
139 def OnScale(self, e):
\r
141 if self.scale.GetValue() != '':
\r
142 scale = self.scale.GetValue()
\r
143 profile.putProfileSetting('model_scale', scale)
\r
144 self.glCanvas.Refresh()
\r
146 def OnScaleMax(self, e):
\r
147 if self.objectsMinV == None:
\r
149 vMin = self.objectsMinV
\r
150 vMax = self.objectsMaxV
\r
151 scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
\r
152 scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
\r
153 scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
\r
154 scaleY2 = (self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
\r
155 scaleZ = self.machineSize.z / (vMax.z - vMin.z)
\r
156 scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ)
\r
157 self.scale.SetValue(str(scale))
\r
158 profile.putProfileSetting('model_scale', self.scale.GetValue())
\r
159 self.glCanvas.Refresh()
\r
161 def OnRotateReset(self, e):
\r
162 self.rotate.SetValue(0)
\r
163 self.OnRotate(None)
\r
165 def OnRotate(self, e):
\r
166 profile.putProfileSetting('model_rotate_base', self.rotate.GetValue())
\r
167 self.updateModelTransform()
\r
169 def On3DClick(self):
\r
170 self.glCanvas.yaw = 30
\r
171 self.glCanvas.pitch = 60
\r
172 self.glCanvas.zoom = 300
\r
173 self.glCanvas.view3D = True
\r
174 self.glCanvas.Refresh()
\r
176 def OnTopClick(self):
\r
177 self.glCanvas.view3D = False
\r
178 self.glCanvas.zoom = 100
\r
179 self.glCanvas.offsetX = 0
\r
180 self.glCanvas.offsetY = 0
\r
181 self.glCanvas.Refresh()
\r
183 def OnLayerNrChange(self, e):
\r
184 self.gcodeDirty = True
\r
185 self.glCanvas.Refresh()
\r
187 def updateCenterX(self):
\r
188 self.machineCenter.x = profile.getProfileSettingFloat('machine_center_x')
\r
189 self.glCanvas.Refresh()
\r
191 def updateCenterY(self):
\r
192 self.machineCenter.y = profile.getProfileSettingFloat('machine_center_y')
\r
193 self.glCanvas.Refresh()
\r
195 def setViewMode(self, mode):
\r
196 if mode == "Normal":
\r
197 self.normalViewButton.SetValue(True)
\r
198 if mode == "GCode":
\r
199 self.gcodeViewButton.SetValue(True)
\r
200 self.glCanvas.viewMode = mode
\r
201 wx.CallAfter(self.glCanvas.Refresh)
\r
203 def loadModelFiles(self, filelist):
\r
204 while len(filelist) > len(self.objectList):
\r
205 self.objectList.append(previewObject())
\r
206 for idx in xrange(len(filelist), len(self.objectList)):
\r
207 self.objectList[idx].mesh = None
\r
208 self.objectList[idx].filename = None
\r
209 for idx in xrange(0, len(filelist)):
\r
210 obj = self.objectList[idx]
\r
211 if obj.filename != filelist[idx]:
\r
212 obj.fileTime = None
\r
213 self.gcodeFileTime = None
\r
214 self.logFileTime = None
\r
215 obj.filename = filelist[idx]
\r
217 self.gcodeFilename = filelist[0][: filelist[0].rfind('.')] + "_export.gcode"
\r
218 self.logFilename = filelist[0][: filelist[0].rfind('.')] + "_export.log"
\r
219 #Do the STL file loading in a background thread so we don't block the UI.
\r
220 if self.loadThread != None and self.loadThread.isAlive():
\r
221 self.loadThread.join()
\r
222 self.loadThread = threading.Thread(target=self.doFileLoadThread)
\r
223 self.loadThread.daemon = True
\r
224 self.loadThread.start()
\r
226 def loadReModelFiles(self, filelist):
\r
227 #Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
\r
228 for idx in xrange(0, len(filelist)):
\r
229 if self.objectList[idx].filename != filelist[idx]:
\r
231 self.loadModelFiles(filelist)
\r
234 def doFileLoadThread(self):
\r
235 for obj in self.objectList:
\r
236 if obj.filename != None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:
\r
237 obj.ileTime = os.stat(obj.filename).st_mtime
\r
238 mesh = stl.stlModel()
\r
239 mesh.load(obj.filename)
\r
243 self.updateModelTransform()
\r
244 wx.CallAfter(self.updateToolbar)
\r
245 wx.CallAfter(self.glCanvas.Refresh)
\r
247 if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:
\r
248 self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime
\r
249 gcode = gcodeInterpreter.gcode()
\r
250 gcode.progressCallback = self.loadProgress
\r
251 gcode.load(self.gcodeFilename)
\r
252 self.gcodeDirty = False
\r
253 self.errorList = []
\r
255 self.gcodeDirty = True
\r
256 wx.CallAfter(self.updateToolbar)
\r
257 wx.CallAfter(self.glCanvas.Refresh)
\r
258 elif not os.path.isfile(self.gcodeFilename):
\r
261 if os.path.isfile(self.logFilename):
\r
263 for line in open(self.logFilename, "rt"):
\r
264 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
266 v1 = util3d.Vector3(float(res.group(2)), float(res.group(3)), float(res.group(4)))
\r
267 v2 = util3d.Vector3(float(res.group(5)), float(res.group(6)), float(res.group(7)))
\r
268 errorList.append([v1, v2])
\r
269 self.errorList = errorList
\r
270 wx.CallAfter(self.glCanvas.Refresh)
\r
272 def loadProgress(self, progress):
\r
275 def updateToolbar(self):
\r
276 self.layerSpin.Show(self.gcode != None)
\r
277 if self.gcode != None:
\r
278 self.layerSpin.SetRange(1, len(self.gcode.layerList))
\r
279 self.toolbar.Realize()
\r
281 def OnViewChange(self):
\r
282 if self.normalViewButton.GetValue():
\r
283 self.glCanvas.viewMode = "Normal"
\r
284 elif self.transparentViewButton.GetValue():
\r
285 self.glCanvas.viewMode = "Transparent"
\r
286 elif self.xrayViewButton.GetValue():
\r
287 self.glCanvas.viewMode = "X-Ray"
\r
288 elif self.gcodeViewButton.GetValue():
\r
289 self.glCanvas.viewMode = "GCode"
\r
290 elif self.mixedViewButton.GetValue():
\r
291 self.glCanvas.viewMode = "Mixed"
\r
292 self.glCanvas.Refresh()
\r
294 def updateModelTransform(self, f=0):
\r
295 rotate = profile.getProfileSettingFloat('model_rotate_base') / 180.0 * math.pi
\r
299 if profile.getProfileSetting('flip_x') == 'True':
\r
301 if profile.getProfileSetting('flip_y') == 'True':
\r
303 if profile.getProfileSetting('flip_z') == 'True':
\r
305 swapXZ = profile.getProfileSetting('swap_xz') == 'True'
\r
306 swapYZ = profile.getProfileSetting('swap_yz') == 'True'
\r
307 mat00 = math.cos(rotate) * scaleX
\r
308 mat01 =-math.sin(rotate) * scaleY
\r
309 mat10 = math.sin(rotate) * scaleX
\r
310 mat11 = math.cos(rotate) * scaleY
\r
312 if len(self.objectList) < 1 or self.objectList[0].mesh == None:
\r
315 for obj in self.objectList:
\r
316 if obj.mesh == None:
\r
319 for i in xrange(0, len(obj.mesh.origonalVertexes)):
\r
320 x = obj.mesh.origonalVertexes[i].x
\r
321 y = obj.mesh.origonalVertexes[i].y
\r
322 z = obj.mesh.origonalVertexes[i].z
\r
327 obj.mesh.vertexes[i].x = x * mat00 + y * mat01
\r
328 obj.mesh.vertexes[i].y = x * mat10 + y * mat11
\r
329 obj.mesh.vertexes[i].z = z * scaleZ
\r
331 for face in obj.mesh.faces:
\r
335 face.normal = (v2 - v1).cross(v3 - v1)
\r
336 face.normal.normalize()
\r
338 minV = self.objectList[0].mesh.getMinimum()
\r
339 maxV = self.objectList[0].mesh.getMaximum()
\r
340 for obj in self.objectList:
\r
341 if obj.mesh == None:
\r
344 obj.mesh.getMinimumZ()
\r
345 minV = minV.min(obj.mesh.getMinimum())
\r
346 maxV = maxV.max(obj.mesh.getMaximum())
\r
348 self.objectsMaxV = maxV
\r
349 self.objectsMinV = minV
\r
350 for obj in self.objectList:
\r
351 if obj.mesh == None:
\r
354 for v in obj.mesh.vertexes:
\r
356 v.x -= minV.x + (maxV.x - minV.x) / 2
\r
357 v.y -= minV.y + (maxV.y - minV.y) / 2
\r
358 obj.mesh.getMinimumZ()
\r
360 self.glCanvas.Refresh()
\r
362 class PreviewGLCanvas(glcanvas.GLCanvas):
\r
363 def __init__(self, parent):
\r
364 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
\r
365 glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)
\r
366 self.parent = parent
\r
367 self.context = glcanvas.GLContext(self)
\r
368 wx.EVT_PAINT(self, self.OnPaint)
\r
369 wx.EVT_SIZE(self, self.OnSize)
\r
370 wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
\r
371 wx.EVT_MOTION(self, self.OnMouseMotion)
\r
372 wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
\r
379 self.gcodeDisplayList = None
\r
380 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
382 def OnMouseMotion(self,e):
\r
383 if e.Dragging() and e.LeftIsDown():
\r
385 self.yaw += e.GetX() - self.oldX
\r
386 self.pitch -= e.GetY() - self.oldY
\r
387 if self.pitch > 170:
\r
389 if self.pitch < 10:
\r
392 self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2
\r
393 self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2
\r
395 if e.Dragging() and e.RightIsDown():
\r
396 self.zoom += e.GetY() - self.oldY
\r
400 self.oldX = e.GetX()
\r
401 self.oldY = e.GetY()
\r
403 def OnMouseWheel(self,e):
\r
404 self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
\r
405 if self.zoom < 1.0:
\r
409 def OnEraseBackground(self,event):
\r
410 #Workaround for windows background redraw flicker.
\r
413 def OnSize(self,event):
\r
416 def OnPaint(self,event):
\r
417 dc = wx.PaintDC(self)
\r
418 if not hasOpenGLlibs:
\r
420 dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
\r
422 self.SetCurrent(self.context)
\r
423 opengl.InitGL(self, self.view3D, self.zoom)
\r
425 glTranslate(0,0,-self.zoom)
\r
426 glRotate(-self.pitch, 1,0,0)
\r
427 glRotate(self.yaw, 0,0,1)
\r
428 if self.parent.objectsMaxV != None:
\r
429 glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)
\r
431 glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
\r
432 glTranslate(self.offsetX, self.offsetY, 0.0)
\r
433 glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
\r
439 machineSize = self.parent.machineSize
\r
440 opengl.DrawMachine(machineSize)
\r
442 if self.parent.gcode != None:
\r
443 if self.gcodeDisplayList == None:
\r
444 self.gcodeDisplayList = glGenLists(1);
\r
445 if self.parent.gcodeDirty:
\r
446 self.parent.gcodeDirty = False
\r
447 glNewList(self.gcodeDisplayList, GL_COMPILE)
\r
451 layerThickness = 0.0
\r
452 filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
\r
453 filamentArea = math.pi * filamentRadius * filamentRadius
\r
454 lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2 / 10
\r
457 for layer in self.parent.gcode.layerList:
\r
458 curLayerZ = layer[0].list[1].z
\r
459 layerThickness = curLayerZ - prevLayerZ
\r
460 prevLayerZ = layer[-1].list[-1].z
\r
463 if curLayerNum != self.parent.layerSpin.GetValue():
\r
464 if curLayerNum < self.parent.layerSpin.GetValue():
\r
465 c = 0.9 - (self.parent.layerSpin.GetValue() - curLayerNum) * 0.1
\r
470 if path.type == 'move':
\r
472 if path.type == 'extrude':
\r
473 if path.pathType == 'FILL':
\r
474 glColor3f(c/2,c/2,0)
\r
475 elif path.pathType == 'WALL-INNER':
\r
477 elif path.pathType == 'SUPPORT':
\r
479 elif path.pathType == 'SKIRT':
\r
480 glColor3f(0,c/2,c/2)
\r
483 if path.type == 'retract':
\r
485 if c > 0.4 and path.type == 'extrude':
\r
486 for i in xrange(0, len(path.list)-1):
\r
488 v1 = path.list[i+1]
\r
490 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
\r
491 dist = (v0 - v1).vsize()
\r
492 if dist > 0 and layerThickness > 0:
\r
493 extrusionMMperDist = (v1.e - v0.e) / dist
\r
494 lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
\r
496 normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
\r
498 v2 = v0 + normal * lineWidth
\r
499 v3 = v1 + normal * lineWidth
\r
500 v0 = v0 - normal * lineWidth
\r
501 v1 = v1 - normal * lineWidth
\r
504 if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
505 glVertex3f(v0.x, v0.y, v0.z - 0.02)
\r
506 glVertex3f(v1.x, v1.y, v1.z - 0.02)
\r
507 glVertex3f(v3.x, v3.y, v3.z - 0.02)
\r
508 glVertex3f(v2.x, v2.y, v2.z - 0.02)
\r
510 glVertex3f(v0.x, v0.y, v0.z - 0.01)
\r
511 glVertex3f(v1.x, v1.y, v1.z - 0.01)
\r
512 glVertex3f(v3.x, v3.y, v3.z - 0.01)
\r
513 glVertex3f(v2.x, v2.y, v2.z - 0.01)
\r
516 #for v in path['list']:
\r
517 # glBegin(GL_TRIANGLE_FAN)
\r
518 # glVertex3f(v.x, v.y, v.z - 0.001)
\r
519 # for i in xrange(0, 16+1):
\r
520 # if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
521 # 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
523 # 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
526 glBegin(GL_LINE_STRIP)
\r
527 for v in path.list:
\r
528 glVertex3f(v.x, v.y, v.z)
\r
532 if self.viewMode == "GCode" or self.viewMode == "Mixed":
\r
533 glCallList(self.gcodeDisplayList)
\r
535 glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
\r
536 for obj in self.parent.objectList:
\r
537 if obj.mesh == None:
\r
539 if obj.displayList == None:
\r
540 obj.displayList = glGenLists(1);
\r
543 glNewList(obj.displayList, GL_COMPILE)
\r
544 opengl.DrawSTL(obj.mesh)
\r
547 glEnable(GL_NORMALIZE)
\r
548 if self.viewMode == "Transparent" or self.viewMode == "Mixed":
\r
549 glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x / 2, self.objColor[self.parent.objectList.index(obj)]))
\r
550 glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 10, self.objColor[self.parent.objectList.index(obj)]))
\r
551 #If we want transparent, then first render a solid black model to remove the printer size lines.
\r
552 if self.viewMode != "Mixed":
\r
553 glDisable(GL_BLEND)
\r
554 glDisable(GL_LIGHTING)
\r
556 self.drawModel(obj)
\r
558 #After the black model is rendered, render the model again but now with lighting and no depth testing.
\r
559 glDisable(GL_DEPTH_TEST)
\r
560 glEnable(GL_LIGHTING)
\r
562 glBlendFunc(GL_ONE, GL_ONE)
\r
563 glEnable(GL_LIGHTING)
\r
564 self.drawModel(obj)
\r
565 elif self.viewMode == "X-Ray":
\r
566 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
\r
567 glDisable(GL_DEPTH_TEST)
\r
568 glEnable(GL_STENCIL_TEST);
\r
569 glStencilFunc(GL_ALWAYS, 1, 1)
\r
570 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
\r
571 self.drawModel(obj)
\r
572 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
\r
574 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
\r
575 glStencilFunc(GL_EQUAL, 0, 1);
\r
577 self.drawModel(obj)
\r
578 glStencilFunc(GL_EQUAL, 1, 1);
\r
580 self.drawModel(obj)
\r
584 for i in xrange(2, 15, 2):
\r
585 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
586 glColor(float(i)/10, float(i)/10, float(i)/5)
\r
588 glVertex3f(-1000,-1000,-1)
\r
589 glVertex3f( 1000,-1000,-1)
\r
590 glVertex3f( 1000, 1000,-1)
\r
591 glVertex3f(-1000, 1000,-1)
\r
593 for i in xrange(1, 15, 2):
\r
594 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
595 glColor(float(i)/10, 0, 0)
\r
597 glVertex3f(-1000,-1000,-1)
\r
598 glVertex3f( 1000,-1000,-1)
\r
599 glVertex3f( 1000, 1000,-1)
\r
600 glVertex3f(-1000, 1000,-1)
\r
604 glDisable(GL_STENCIL_TEST);
\r
605 glEnable(GL_DEPTH_TEST)
\r
606 elif self.viewMode == "Normal":
\r
607 glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor[self.parent.objectList.index(obj)])
\r
608 glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 5, self.objColor[self.parent.objectList.index(obj)]))
\r
609 glEnable(GL_LIGHTING)
\r
610 self.drawModel(obj)
\r
612 if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":
\r
613 glDisable(GL_LIGHTING)
\r
614 glDisable(GL_DEPTH_TEST)
\r
615 glDisable(GL_BLEND)
\r
618 #for err in self.parent.errorList:
\r
619 # glVertex3f(err[0].x, err[0].y, err[0].z)
\r
620 # glVertex3f(err[1].x, err[1].y, err[1].z)
\r
622 glEnable(GL_DEPTH_TEST)
\r
625 def drawModel(self, obj):
\r
626 multiX = int(profile.getProfileSetting('model_multiply_x'))
\r
627 multiY = int(profile.getProfileSetting('model_multiply_y'))
\r
628 modelScale = profile.getProfileSettingFloat('model_scale')
\r
629 modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale
\r
631 glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
\r
632 for mx in xrange(0, multiX):
\r
633 for my in xrange(0, multiY):
\r
635 glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
\r
636 glScalef(modelScale, modelScale, modelScale)
\r
637 glCallList(obj.displayList)
\r