8 from wx import glcanvas
\r
12 OpenGL.ERROR_CHECKING = False
\r
13 from OpenGL.GLU import *
\r
14 from OpenGL.GL import *
\r
15 hasOpenGLlibs = True
\r
17 print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
\r
18 hasOpenGLlibs = False
\r
20 from newui import profile
\r
21 from newui import gcodeInterpreter
\r
22 from newui import util3d
\r
24 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
\r
25 from fabmetheus_utilities.vector3 import Vector3
\r
27 class previewPanel(wx.Panel):
\r
28 def __init__(self, parent):
\r
29 wx.Panel.__init__(self, parent,-1)
\r
31 self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW))
\r
32 self.SetMinSize((440,320))
\r
34 self.glCanvas = PreviewGLCanvas(self)
\r
36 self.triangleMesh = None
\r
38 self.modelFilename = None
\r
39 self.loadingProgressAmount = 0
\r
40 self.loadThread = None
\r
41 self.machineSize = Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
\r
42 self.machineCenter = Vector3(0, 0, 0)
\r
44 self.toolbar = wx.ToolBar( self, -1 )
\r
45 self.toolbar.SetToolBitmapSize( ( 21, 21 ) )
\r
47 button = wx.Button(self.toolbar, -1, "3D", size=(21*2,21))
\r
48 self.toolbar.AddControl(button)
\r
49 self.Bind(wx.EVT_BUTTON, self.On3DClick, button)
\r
51 button = wx.Button(self.toolbar, -1, "Top", size=(21*2,21))
\r
52 self.toolbar.AddControl(button)
\r
53 self.Bind(wx.EVT_BUTTON, self.OnTopClick, button)
\r
55 self.viewSelect = wx.ComboBox(self.toolbar, -1, 'Model - Normal', choices=['Model - Normal', 'Model - Transparent', 'Model - X-Ray', 'GCode', 'Mixed'], style=wx.CB_DROPDOWN|wx.CB_READONLY)
\r
56 self.toolbar.AddControl(self.viewSelect)
\r
57 self.viewSelect.Bind(wx.EVT_COMBOBOX, self.OnViewChange)
\r
58 self.glCanvas.viewMode = self.viewSelect.GetValue()
\r
60 self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
\r
61 self.toolbar.AddControl(self.layerSpin)
\r
62 self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin)
\r
64 self.toolbar2 = wx.ToolBar( self, -1 )
\r
65 self.toolbar2.SetToolBitmapSize( ( 21, 21 ) )
\r
66 self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Flip'))
\r
68 self.flipX = wx.CheckBox(self.toolbar2, -1, "X")
\r
69 self.flipX.SetValue(profile.getProfileSetting('flip_x') == 'True')
\r
70 self.toolbar2.AddControl(self.flipX)
\r
71 self.Bind(wx.EVT_CHECKBOX, self.OnFlipXClick, self.flipX)
\r
72 self.flipY = wx.CheckBox(self.toolbar2, -1, "Y")
\r
73 self.flipY.SetValue(profile.getProfileSetting('flip_y') == 'True')
\r
74 self.toolbar2.AddControl(self.flipY)
\r
75 self.Bind(wx.EVT_CHECKBOX, self.OnFlipYClick, self.flipY)
\r
76 self.flipZ = wx.CheckBox(self.toolbar2, -1, "Z")
\r
77 self.flipZ.SetValue(profile.getProfileSetting('flip_z') == 'True')
\r
78 self.toolbar2.AddControl(self.flipZ)
\r
79 self.Bind(wx.EVT_CHECKBOX, self.OnFlipZClick, self.flipZ)
\r
81 self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount())
\r
82 self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Scale'))
\r
83 self.scale = wx.TextCtrl(self.toolbar2, -1, profile.getProfileSetting('model_scale'), size=(21*2,21))
\r
84 self.toolbar2.AddControl(self.scale)
\r
85 self.Bind(wx.EVT_TEXT, self.OnScale, self.scale)
\r
87 self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount())
\r
88 self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Copy'))
\r
89 self.mulXsub = wx.Button(self.toolbar2, -1, '-', size=(21,21))
\r
90 self.toolbar2.AddControl(self.mulXsub)
\r
91 self.Bind(wx.EVT_BUTTON, self.OnMulXSubClick, self.mulXsub)
\r
92 self.mulXadd = wx.Button(self.toolbar2, -1, '+', size=(21,21))
\r
93 self.toolbar2.AddControl(self.mulXadd)
\r
94 self.Bind(wx.EVT_BUTTON, self.OnMulXAddClick, self.mulXadd)
\r
96 self.mulYsub = wx.Button(self.toolbar2, -1, '-', size=(21,21))
\r
97 self.toolbar2.AddControl(self.mulYsub)
\r
98 self.Bind(wx.EVT_BUTTON, self.OnMulYSubClick, self.mulYsub)
\r
99 self.mulYadd = wx.Button(self.toolbar2, -1, '+', size=(21,21))
\r
100 self.toolbar2.AddControl(self.mulYadd)
\r
101 self.Bind(wx.EVT_BUTTON, self.OnMulYAddClick, self.mulYadd)
\r
103 self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount())
\r
104 self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Rot'))
\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.toolbar2.AddControl(self.rotate)
\r
108 self.Bind(wx.EVT_SPINCTRL, self.OnRotate, 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 OnFlipXClick(self, e):
\r
120 profile.putProfileSetting('flip_x', str(self.flipX.GetValue()))
\r
121 self.updateModelTransform()
\r
123 def OnFlipYClick(self, e):
\r
124 profile.putProfileSetting('flip_y', str(self.flipY.GetValue()))
\r
125 self.updateModelTransform()
\r
127 def OnFlipZClick(self, e):
\r
128 profile.putProfileSetting('flip_z', str(self.flipZ.GetValue()))
\r
129 self.updateModelTransform()
\r
131 def OnMulXAddClick(self, e):
\r
132 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1)))
\r
133 self.updateModelTransform()
\r
135 def OnMulXSubClick(self, e):
\r
136 profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))-1)))
\r
137 self.updateModelTransform()
\r
139 def OnMulYAddClick(self, e):
\r
140 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))+1)))
\r
141 self.updateModelTransform()
\r
143 def OnMulYSubClick(self, e):
\r
144 profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))-1)))
\r
145 self.updateModelTransform()
\r
147 def OnScale(self, e):
\r
149 scale = float(self.scale.GetValue())
\r
152 profile.putProfileSetting('model_scale', str(scale))
\r
153 self.updateModelTransform()
\r
155 def OnRotate(self, e):
\r
156 profile.putProfileSetting('model_rotate_base', self.rotate.GetValue())
\r
157 self.updateModelTransform()
\r
159 def On3DClick(self, e):
\r
160 self.glCanvas.yaw = 30
\r
161 self.glCanvas.pitch = 60
\r
162 self.glCanvas.zoom = 150
\r
163 self.glCanvas.view3D = True
\r
164 self.glCanvas.Refresh()
\r
166 def OnTopClick(self, e):
\r
167 self.glCanvas.view3D = False
\r
168 self.glCanvas.zoom = 100
\r
169 self.glCanvas.offsetX = 0
\r
170 self.glCanvas.offsetY = 0
\r
171 self.glCanvas.Refresh()
\r
173 def OnLayerNrChange(self, e):
\r
174 self.gcodeDirty = True
\r
175 self.glCanvas.Refresh()
\r
177 def updateCenterX(self, x):
\r
178 self.machineCenter.x = x
\r
180 self.glCanvas.Refresh()
\r
182 def updateCenterY(self, y):
\r
183 self.machineCenter.y = y
\r
185 self.glCanvas.Refresh()
\r
187 def setViewMode(self, mode):
\r
188 self.viewSelect.SetValue(mode)
\r
189 self.glCanvas.viewMode = self.viewSelect.GetValue()
\r
190 wx.CallAfter(self.glCanvas.Refresh)
\r
192 def loadModelFile(self, filename):
\r
193 if self.modelFilename != filename:
\r
194 self.modelFileTime = None
\r
195 self.gcodeFileTime = None
\r
196 self.logFileTime = None
\r
198 self.modelFilename = filename
\r
199 self.gcodeFilename = filename[: filename.rfind('.')] + "_export.gcode"
\r
200 self.logFilename = filename[: filename.rfind('.')] + "_export.log"
\r
201 #Do the STL file loading in a background thread so we don't block the UI.
\r
202 if self.loadThread != None and self.loadThread.isAlive():
\r
203 self.loadThread.join()
\r
204 self.loadThread = threading.Thread(target=self.doFileLoadThread)
\r
205 self.loadThread.daemon = True
\r
206 self.loadThread.start()
\r
208 def loadReModelFile(self, filename):
\r
209 #Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
\r
210 if self.modelFilename != filename:
\r
212 self.loadModelFile(filename)
\r
215 def doFileLoadThread(self):
\r
216 if os.path.isfile(self.modelFilename) and self.modelFileTime != os.stat(self.modelFilename).st_mtime:
\r
217 self.modelFileTime = os.stat(self.modelFilename).st_mtime
\r
218 triangleMesh = fabmetheus_interpret.getCarving(self.modelFilename)
\r
219 triangleMesh.origonalVertexes = list(triangleMesh.vertexes)
\r
220 for i in xrange(0, len(triangleMesh.origonalVertexes)):
\r
221 triangleMesh.origonalVertexes[i] = triangleMesh.origonalVertexes[i].copy()
\r
222 triangleMesh.getMinimumZ()
\r
223 self.modelDirty = False
\r
224 self.errorList = []
\r
225 self.triangleMesh = triangleMesh
\r
226 self.updateModelTransform()
\r
227 wx.CallAfter(self.updateToolbar)
\r
228 wx.CallAfter(self.glCanvas.Refresh)
\r
230 if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:
\r
231 self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime
\r
232 gcode = gcodeInterpreter.gcode()
\r
233 gcode.progressCallback = self.loadProgress
\r
234 gcode.load(self.gcodeFilename)
\r
235 self.loadingProgressAmount = 0
\r
236 self.gcodeDirty = False
\r
237 self.errorList = []
\r
239 self.gcodeDirty = True
\r
240 wx.CallAfter(self.updateToolbar)
\r
241 wx.CallAfter(self.glCanvas.Refresh)
\r
242 elif not os.path.isfile(self.gcodeFilename):
\r
245 if os.path.isfile(self.logFilename):
\r
247 for line in open(self.logFilename, "rt"):
\r
248 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
250 v1 = util3d.Vector3(float(res.group(2)), float(res.group(3)), float(res.group(4)))
\r
251 v2 = util3d.Vector3(float(res.group(5)), float(res.group(6)), float(res.group(7)))
\r
252 errorList.append([v1, v2])
\r
253 self.errorList = errorList
\r
254 wx.CallAfter(self.glCanvas.Refresh)
\r
256 def loadProgress(self, progress):
\r
257 self.loadingProgressAmount = progress
\r
258 wx.CallAfter(self.glCanvas.Refresh)
\r
260 def updateToolbar(self):
\r
261 self.layerSpin.Show(self.gcode != None)
\r
262 if self.gcode != None:
\r
263 self.layerSpin.SetRange(1, self.gcode.layerCount)
\r
264 self.toolbar.Realize()
\r
266 def OnViewChange(self, e):
\r
267 self.glCanvas.viewMode = self.viewSelect.GetValue()
\r
268 self.glCanvas.Refresh()
\r
270 def updateModelTransform(self, f=0):
\r
271 if self.triangleMesh == None:
\r
276 scale = float(profile.getProfileSetting('model_scale'))
\r
277 rotate = float(profile.getProfileSetting('model_rotate_base')) / 180 * math.pi
\r
283 if profile.getProfileSetting('flip_x') == 'True':
\r
285 if profile.getProfileSetting('flip_y') == 'True':
\r
287 if profile.getProfileSetting('flip_z') == 'True':
\r
289 mat00 = math.cos(rotate) * scaleX
\r
290 mat01 =-math.sin(rotate) * scaleY
\r
291 mat10 = math.sin(rotate) * scaleX
\r
292 mat11 = math.cos(rotate) * scaleY
\r
294 for i in xrange(0, len(self.triangleMesh.origonalVertexes)):
\r
295 self.triangleMesh.vertexes[i].x = self.triangleMesh.origonalVertexes[i].x * mat00 + self.triangleMesh.origonalVertexes[i].y * mat01
\r
296 self.triangleMesh.vertexes[i].y = self.triangleMesh.origonalVertexes[i].x * mat10 + self.triangleMesh.origonalVertexes[i].y * mat11
\r
297 self.triangleMesh.vertexes[i].z = self.triangleMesh.origonalVertexes[i].z * scaleZ
\r
299 for face in self.triangleMesh.faces:
\r
300 v1 = self.triangleMesh.vertexes[face.vertexIndexes[0]]
\r
301 v2 = self.triangleMesh.vertexes[face.vertexIndexes[1]]
\r
302 v3 = self.triangleMesh.vertexes[face.vertexIndexes[2]]
\r
303 face.normal = (v2 - v1).cross(v3 - v1)
\r
304 face.normal.normalize()
\r
308 def moveModel(self):
\r
309 if self.triangleMesh == None:
\r
311 minZ = self.triangleMesh.getMinimumZ()
\r
312 min = self.triangleMesh.getCarveCornerMinimum()
\r
313 max = self.triangleMesh.getCarveCornerMaximum()
\r
314 for v in self.triangleMesh.vertexes:
\r
316 v.x -= min.x + (max.x - min.x) / 2
\r
317 v.y -= min.y + (max.y - min.y) / 2
\r
318 v.x += self.machineCenter.x
\r
319 v.y += self.machineCenter.y
\r
320 self.triangleMesh.getMinimumZ()
\r
321 self.modelDirty = True
\r
322 self.glCanvas.Refresh()
\r
324 class PreviewGLCanvas(glcanvas.GLCanvas):
\r
325 def __init__(self, parent):
\r
326 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
\r
327 glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)
\r
328 self.parent = parent
\r
329 self.context = glcanvas.GLContext(self)
\r
330 wx.EVT_PAINT(self, self.OnPaint)
\r
331 wx.EVT_SIZE(self, self.OnSize)
\r
332 wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
\r
333 wx.EVT_MOTION(self, self.OnMouseMotion)
\r
334 wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
\r
341 self.modelDisplayList = None
\r
342 self.gcodeDisplayList = None
\r
344 def OnMouseMotion(self,e):
\r
345 if e.Dragging() and e.LeftIsDown():
\r
347 self.yaw += e.GetX() - self.oldX
\r
348 self.pitch -= e.GetY() - self.oldY
\r
349 if self.pitch > 170:
\r
351 if self.pitch < 10:
\r
354 self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2
\r
355 self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2
\r
357 if e.Dragging() and e.RightIsDown():
\r
358 self.zoom += e.GetY() - self.oldY
\r
362 self.oldX = e.GetX()
\r
363 self.oldY = e.GetY()
\r
365 def OnMouseWheel(self,e):
\r
366 self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
\r
367 if self.zoom < 1.0:
\r
371 def OnEraseBackground(self,event):
\r
372 #Workaround for windows background redraw flicker.
\r
375 def OnSize(self,event):
\r
378 def OnPaint(self,event):
\r
379 dc = wx.PaintDC(self)
\r
380 if not hasOpenGLlibs:
\r
382 dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
\r
384 self.SetCurrent(self.context)
\r
390 machineSize = self.parent.machineSize
\r
391 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
\r
393 glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
\r
397 glDisable(GL_LIGHTING)
\r
398 glBegin(GL_LINE_LOOP)
\r
399 glVertex3f(0, 0, 0)
\r
400 glVertex3f(machineSize.x, 0, 0)
\r
401 glVertex3f(machineSize.x, machineSize.y, 0)
\r
402 glVertex3f(0, machineSize.y, 0)
\r
406 for i in xrange(0, int(machineSize.x), 10):
\r
407 glVertex3f(i, 0, 0)
\r
408 glVertex3f(i, machineSize.y, 0)
\r
409 for i in xrange(0, int(machineSize.y), 10):
\r
410 glVertex3f(0, i, 0)
\r
411 glVertex3f(machineSize.x, i, 0)
\r
414 glBegin(GL_LINE_LOOP)
\r
415 glVertex3f(0, 0, machineSize.z)
\r
416 glVertex3f(machineSize.x, 0, machineSize.z)
\r
417 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
\r
418 glVertex3f(0, machineSize.y, machineSize.z)
\r
421 glVertex3f(0, 0, 0)
\r
422 glVertex3f(0, 0, machineSize.z)
\r
423 glVertex3f(machineSize.x, 0, 0)
\r
424 glVertex3f(machineSize.x, 0, machineSize.z)
\r
425 glVertex3f(machineSize.x, machineSize.y, 0)
\r
426 glVertex3f(machineSize.x, machineSize.y, machineSize.z)
\r
427 glVertex3f(0, machineSize.y, 0)
\r
428 glVertex3f(0, machineSize.y, machineSize.z)
\r
431 if self.parent.gcode != None:
\r
432 if self.gcodeDisplayList == None:
\r
433 self.gcodeDisplayList = glGenLists(1);
\r
434 if self.parent.gcodeDirty:
\r
435 self.parent.gcodeDirty = False
\r
436 glNewList(self.gcodeDisplayList, GL_COMPILE)
\r
440 layerThickness = 0.0
\r
441 filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
\r
442 filamentArea = math.pi * filamentRadius * filamentRadius
\r
443 lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2
\r
446 for path in self.parent.gcode.pathList:
\r
447 if path.layerNr != curLayerNum:
\r
448 prevLayerZ = curLayerZ
\r
449 curLayerZ = path.list[1].z
\r
450 curLayerNum = path.layerNr
\r
451 layerThickness = curLayerZ - prevLayerZ
\r
454 if path.layerNr != self.parent.layerSpin.GetValue():
\r
455 if path.layerNr < self.parent.layerSpin.GetValue():
\r
456 c = 0.9 - (self.parent.layerSpin.GetValue() - path.layerNr) * 0.1
\r
461 if path.type == 'move':
\r
463 if path.type == 'extrude':
\r
464 if path.pathType == 'FILL':
\r
465 glColor3f(c/2,c/2,0)
\r
466 elif path.pathType == 'WALL-INNER':
\r
470 if path.type == 'retract':
\r
472 if c > 0.4 and path.type == 'extrude':
\r
473 for i in xrange(0, len(path.list)-1):
\r
475 v1 = path.list[i+1]
\r
477 # Calculate line width from ePerDistance (needs layer thickness and filament diameter)
\r
478 dist = (v0 - v1).vsize()
\r
479 if dist > 0 and layerThickness > 0:
\r
480 extrusionMMperDist = (v1.e - v0.e) / (v0 - v1).vsize()
\r
481 lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
\r
483 normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
\r
485 v2 = v0 + normal * lineWidth
\r
486 v3 = v1 + normal * lineWidth
\r
487 v0 = v0 - normal * lineWidth
\r
488 v1 = v1 - normal * lineWidth
\r
491 if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
492 glVertex3f(v0.x, v0.y, v0.z - 0.02)
\r
493 glVertex3f(v1.x, v1.y, v1.z - 0.02)
\r
494 glVertex3f(v3.x, v3.y, v3.z - 0.02)
\r
495 glVertex3f(v2.x, v2.y, v2.z - 0.02)
\r
497 glVertex3f(v0.x, v0.y, v0.z - 0.01)
\r
498 glVertex3f(v1.x, v1.y, v1.z - 0.01)
\r
499 glVertex3f(v3.x, v3.y, v3.z - 0.01)
\r
500 glVertex3f(v2.x, v2.y, v2.z - 0.01)
\r
503 #for v in path['list']:
\r
504 # glBegin(GL_TRIANGLE_FAN)
\r
505 # glVertex3f(v.x, v.y, v.z - 0.001)
\r
506 # for i in xrange(0, 16+1):
\r
507 # if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
\r
508 # 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
510 # 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
513 glBegin(GL_LINE_STRIP)
\r
514 for v in path.list:
\r
515 glVertex3f(v.x, v.y, v.z)
\r
518 if self.viewMode == "GCode" or self.viewMode == "Mixed":
\r
519 glCallList(self.gcodeDisplayList)
\r
521 if self.parent.triangleMesh != None:
\r
522 if self.modelDisplayList == None:
\r
523 self.modelDisplayList = glGenLists(1);
\r
524 if self.parent.modelDirty:
\r
525 self.parent.modelDirty = False
\r
526 multiX = int(profile.getProfileSetting('model_multiply_x'))
\r
527 multiY = int(profile.getProfileSetting('model_multiply_y'))
\r
528 modelSize = self.parent.triangleMesh.getCarveCornerMaximum() - self.parent.triangleMesh.getCarveCornerMinimum()
\r
529 glNewList(self.modelDisplayList, GL_COMPILE)
\r
531 glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
\r
532 for mx in xrange(0, multiX):
\r
533 for my in xrange(0, multiY):
\r
534 for face in self.parent.triangleMesh.faces:
\r
536 glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
\r
537 glBegin(GL_TRIANGLES)
\r
538 v1 = self.parent.triangleMesh.vertexes[face.vertexIndexes[0]]
\r
539 v2 = self.parent.triangleMesh.vertexes[face.vertexIndexes[1]]
\r
540 v3 = self.parent.triangleMesh.vertexes[face.vertexIndexes[2]]
\r
541 glNormal3f(face.normal.x, face.normal.y, face.normal.z)
\r
542 glVertex3f(v1.x, v1.y, v1.z)
\r
543 glVertex3f(v2.x, v2.y, v2.z)
\r
544 glVertex3f(v3.x, v3.y, v3.z)
\r
545 glNormal3f(-face.normal.x, -face.normal.y, -face.normal.z)
\r
546 glVertex3f(v1.x, v1.y, v1.z)
\r
547 glVertex3f(v3.x, v3.y, v3.z)
\r
548 glVertex3f(v2.x, v2.y, v2.z)
\r
553 if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed":
\r
554 #If we want transparent, then first render a solid black model to remove the printer size lines.
\r
555 if self.viewMode != "Mixed":
\r
556 glDisable(GL_BLEND)
\r
557 glDisable(GL_LIGHTING)
\r
559 glCallList(self.modelDisplayList)
\r
561 #After the black model is rendered, render the model again but now with lighting and no depth testing.
\r
562 glDisable(GL_DEPTH_TEST)
\r
563 glEnable(GL_LIGHTING)
\r
565 glBlendFunc(GL_ONE, GL_ONE)
\r
566 glEnable(GL_LIGHTING)
\r
567 glCallList(self.modelDisplayList)
\r
568 elif self.viewMode == "Model - X-Ray":
\r
569 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
\r
570 glDisable(GL_DEPTH_TEST)
\r
571 glEnable(GL_STENCIL_TEST);
\r
572 glStencilFunc(GL_ALWAYS, 1, 1)
\r
573 glStencilOp(GL_INCR, GL_INCR, GL_INCR)
\r
574 glCallList(self.modelDisplayList)
\r
575 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
\r
577 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
\r
578 glStencilFunc(GL_EQUAL, 0, 1);
\r
580 glCallList(self.modelDisplayList)
\r
581 glStencilFunc(GL_EQUAL, 1, 1);
\r
583 glCallList(self.modelDisplayList)
\r
587 for i in xrange(2, 15, 2):
\r
588 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
589 glColor(float(i)/10, float(i)/10, float(i)/5)
\r
591 glVertex3f(-1000,-1000,-1)
\r
592 glVertex3f( 1000,-1000,-1)
\r
593 glVertex3f( 1000, 1000,-1)
\r
594 glVertex3f(-1000, 1000,-1)
\r
596 for i in xrange(1, 15, 2):
\r
597 glStencilFunc(GL_EQUAL, i, 0xFF);
\r
598 glColor(float(i)/10, 0, 0)
\r
600 glVertex3f(-1000,-1000,-1)
\r
601 glVertex3f( 1000,-1000,-1)
\r
602 glVertex3f( 1000, 1000,-1)
\r
603 glVertex3f(-1000, 1000,-1)
\r
607 glDisable(GL_STENCIL_TEST);
\r
608 glEnable(GL_DEPTH_TEST)
\r
609 elif self.viewMode == "Model - Normal":
\r
610 glEnable(GL_LIGHTING)
\r
611 glCallList(self.modelDisplayList)
\r
613 if self.viewMode == "Model - Normal" or self.viewMode == "Model - Transparent" or self.viewMode == "Model - X-Ray":
\r
614 glDisable(GL_LIGHTING)
\r
615 glDisable(GL_DEPTH_TEST)
\r
616 glDisable(GL_BLEND)
\r
618 glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
\r
620 for err in self.parent.errorList:
\r
621 glVertex3f(err[0].x, err[0].y, err[0].z)
\r
622 glVertex3f(err[1].x, err[1].y, err[1].z)
\r
628 # set viewing projection
\r
629 glMatrixMode(GL_MODELVIEW)
\r
631 size = self.GetSize()
\r
632 glViewport(0,0, size.GetWidth(), size.GetHeight())
\r
634 if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed":
\r
635 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0])
\r
636 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0])
\r
638 glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])
\r
639 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0])
\r
640 glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
\r
642 glEnable(GL_LIGHTING)
\r
643 glEnable(GL_LIGHT0)
\r
644 glEnable(GL_DEPTH_TEST)
\r
645 glEnable(GL_CULL_FACE)
\r
646 glDisable(GL_BLEND)
\r
648 glClearColor(0.0, 0.0, 0.0, 1.0)
\r
652 glMatrixMode(GL_PROJECTION)
\r
654 aspect = float(self.GetSize().GetWidth()) / float(self.GetSize().GetHeight())
\r
656 gluPerspective(90.0, aspect, 1.0, 1000.0)
\r
658 glOrtho(-self.zoom * aspect, self.zoom * aspect, -self.zoom, self.zoom, -1000.0, 1000.0)
\r
660 glMatrixMode(GL_MODELVIEW)
\r
663 glTranslate(0,0,-self.zoom)
\r
664 glRotate(-self.pitch, 1,0,0)
\r
665 glRotate(self.yaw, 0,0,1)
\r
666 if self.parent.triangleMesh != None:
\r
667 glTranslate(0,0,-self.parent.triangleMesh.getCarveCornerMaximum().z / 2)
\r
669 glTranslate(self.offsetX, self.offsetY, 0)
\r