def draw(self): planes = self.planes assert len(planes) <= len(GL_CLIP_PLANE_table), \ "no more than %d clipping planes are permitted" % \ len(GL_CLIP_PLANE_table) # even if your OpenGL driver supports more -- no sense writing an expr that not everyone can draw! # WARNING: this ignores the issue of nested Clipped constructs! # In fact, it assumes nothing in thing or above self uses any clipping planes. # (Not merely "assumes no more than 6 in all", because we hardcode which specific planes to use!) # Worse, we don't even detect the error. Fixing the behavior is just as easy # (let graphical dynenv (self.env) know which planes are still available to any drawing-kid), so do that instead. ##e # Note that we might need to work inside a display list, and therefore we'd need to get the "next plane to use" # from an env which stays fixed (or from an env var which is changedtracked), not just from each draw call's caller # (i.e. a glpane attr). # enable the planes for i, plane in zip(range(len(planes)), planes): assert len(plane) == 4 glEnable( GL_CLIP_PLANE_table[i] ) glClipPlane( GL_CLIP_PLANE_table[i], plane) # draw thing self.drawkid( self.thing) # disable the planes for i in range(len(planes)): glDisable( GL_CLIP_PLANE_table[i] ) return
def draw(self): planes = self.planes assert len(planes) <= len(GL_CLIP_PLANE_table), \ "no more than %d clipping planes are permitted" % \ len(GL_CLIP_PLANE_table) # even if your OpenGL driver supports more -- no sense writing an expr that not everyone can draw! # WARNING: this ignores the issue of nested Clipped constructs! # In fact, it assumes nothing in thing or above self uses any clipping planes. # (Not merely "assumes no more than 6 in all", because we hardcode which specific planes to use!) # Worse, we don't even detect the error. Fixing the behavior is just as easy # (let graphical dynenv (self.env) know which planes are still available to any drawing-kid), so do that instead. ##e # Note that we might need to work inside a display list, and therefore we'd need to get the "next plane to use" # from an env which stays fixed (or from an env var which is changedtracked), not just from each draw call's caller # (i.e. a glpane attr). # enable the planes for i, plane in zip(range(len(planes)), planes): assert len(plane) == 4 glEnable(GL_CLIP_PLANE_table[i]) glClipPlane(GL_CLIP_PLANE_table[i], plane) # draw thing self.drawkid(self.thing) # disable the planes for i in range(len(planes)): glDisable(GL_CLIP_PLANE_table[i]) return
def select(self, wX, wY): """ Use the OpenGL picking/selection to select any object. Return the selected object, otherwise, return None. Restore projection and modelview matrices before returning. """ ### NOTE: this code is similar to (and was copied and modified from) # GLPane_highlighting_methods.do_glselect_if_wanted, but also differs # in significant ways (too much to make it worth merging, unless we # decide to merge the differing algorithms as well). It's one of # several instances of hit-test code that calls glRenderMode. # [bruce 060721/080917 comment] wZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT) gz = wZ[0][0] if gz >= GL_FAR_Z: # Empty space was clicked return None pxyz = A(gluUnProject(wX, wY, gz)) pn = self.out pxyz -= 0.0002 * pn # Note: if this runs before the model is drawn, this can have an # exception "OverflowError: math range error", presumably because # appropriate state for gluUnProject was not set up. That doesn't # normally happen but can happen due to bugs (no known open bugs # of that kind). # Sometimes our drawing area can become "stuck at gray", # and when that happens, the same exception can occur from this line. # Could it be that too many accidental mousewheel scrolls occurred # and made the scale unreasonable? (To mitigate, we should prevent # those from doing anything unless we have a valid model, and also # reset that scale when loading a new model (latter is probably # already done, but I didn't check). See also the comments # in def wheelEvent.) [bruce 080220 comment] dp = -dot(pxyz, pn) # Save projection matrix before it's changed. glMatrixMode(GL_PROJECTION) glPushMatrix() current_glselect = (wX, wY, 1, 1) self._setup_projection(glselect=current_glselect) glSelectBuffer(self.SIZE_FOR_glSelectBuffer) glRenderMode(GL_SELECT) glInitNames() glMatrixMode(GL_MODELVIEW) # Save model view matrix before it's changed. glPushMatrix() # Draw model using glRenderMode(GL_SELECT) as set up above try: glClipPlane(GL_CLIP_PLANE0, (pn[0], pn[1], pn[2], dp)) glEnable(GL_CLIP_PLANE0) self._drawModel_using_DrawingSets() except: #bruce 080917 fixed predicted bugs in this except clause (untested) print_compact_traceback( "exception in ThumbView._drawModel_using_DrawingSets() during GL_SELECT; ignored; restoring matrices: " ) glDisable(GL_CLIP_PLANE0) glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glPopMatrix() glRenderMode(GL_RENDER) return None else: glDisable(GL_CLIP_PLANE0) # Restore model/view matrix glPopMatrix() # Restore projection matrix and set matrix mode to Model/View glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glFlush() hit_records = list(glRenderMode(GL_RENDER)) ## print "%d hits" % len(hit_records) for (near, far, names) in hit_records: ## print "hit record: near, far, names:", near, far, names # note from testing: near/far are too far apart to give actual depth, # in spite of the 1-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). ### REVIEW: this just returns the first candidate object found. # The clip plane may restrict the set of candidates well enough to # make sure that's the right one, but this is untested and unreviewed. # (And it's just my guess that that was Huaicai's intention in # setting up clipping, since it's not documented. I'm guessing that # the plane is just behind the hitpoint, but haven't confirmed this.) # [bruce 080917 comment] if names: name = names[-1] assy = self.assy obj = assy and assy.object_for_glselect_name(name) #k should always return an obj return obj return None # from ThumbView.select
def drawSiCGrid(color, line_type, w, h, up, right): """ Draw SiC grid. """ if line_type == NO_LINE: return XLen = sic_uLen * 3.0 YLen = sic_yU * 2.0 hw = w/2.0; hh = h/2.0 i1 = int(floor(-hw/XLen)) i2 = int(ceil(hw/XLen)) j1 = int(floor(-hh/YLen)) j2 = int(ceil(hh/YLen)) glDisable(GL_LIGHTING) glColor3fv(color) if line_type > 1: glEnable(GL_LINE_STIPPLE) if line_type == DASHED_LINE: glLineStipple (1, 0x00FF) # dashed elif line_type == DOTTED_LINE: glLineStipple (1, 0x0101) # dotted else: print "drawer.drawSiCGrid(): line_type '", line_type, \ "' is not valid. Drawing dashed grid line." glLineStipple (1, 0x00FF) # dashed glClipPlane(GL_CLIP_PLANE0, (1.0, 0.0, 0.0, hw)) glClipPlane(GL_CLIP_PLANE1, (-1.0, 0.0, 0.0, hw)) glClipPlane(GL_CLIP_PLANE2, (0.0, 1.0, 0.0, hh)) glClipPlane(GL_CLIP_PLANE3, (0.0, -1.0, 0.0, hh)) glEnable(GL_CLIP_PLANE0) glEnable(GL_CLIP_PLANE1) glEnable(GL_CLIP_PLANE2) glEnable(GL_CLIP_PLANE3) glPushMatrix() glTranslate(i1*XLen, j1*YLen, 0.0) for i in range(i1, i2): glPushMatrix() for j in range(j1, j2): glCallList(SiCGridList) glTranslate(0.0, YLen, 0.0) glPopMatrix() glTranslate(XLen, 0.0, 0.0) glPopMatrix() glDisable(GL_CLIP_PLANE0) glDisable(GL_CLIP_PLANE1) glDisable(GL_CLIP_PLANE2) glDisable(GL_CLIP_PLANE3) if line_type > 1: glDisable (GL_LINE_STIPPLE) xpos, ypos = hw, 0.0 f3d = Font3D(xpos=xpos, ypos=ypos, right=right, up=up, rot90=False, glBegin=False) for j in range(j1, j2): yoff = j * YLen if -hh < yoff + ypos < hh: f3d.drawString("%-.4g" % yoff, color=color, yoff=yoff) xpos, ypos = 0.0, hh f3d = Font3D(xpos=xpos, ypos=ypos, right=right, up=up, rot90=True, glBegin=False) for i in range(2*i1, 2*i2): yoff = i * (XLen/2) if -hw < yoff + xpos < hw: f3d.drawString("%-.4g" % yoff, color=color, yoff=yoff) glEnable(GL_LIGHTING) return
def set_clip_plane(self, index, coefficients): glEnable(self.clip_constants[index]) glClipPlane(self.clip_constants[index], coefficients)
def select(self, wX, wY): """ Use the OpenGL picking/selection to select any object. Return the selected object, otherwise, return None. Restore projection and modelview matrices before returning. """ ### NOTE: this code is similar to (and was copied and modified from) # GLPane_highlighting_methods.do_glselect_if_wanted, but also differs # in significant ways (too much to make it worth merging, unless we # decide to merge the differing algorithms as well). It's one of # several instances of hit-test code that calls glRenderMode. # [bruce 060721/080917 comment] wZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT) gz = wZ[0][0] if gz >= GL_FAR_Z: # Empty space was clicked return None pxyz = A(gluUnProject(wX, wY, gz)) pn = self.out pxyz -= 0.0002 * pn # Note: if this runs before the model is drawn, this can have an # exception "OverflowError: math range error", presumably because # appropriate state for gluUnProject was not set up. That doesn't # normally happen but can happen due to bugs (no known open bugs # of that kind). # Sometimes our drawing area can become "stuck at gray", # and when that happens, the same exception can occur from this line. # Could it be that too many accidental mousewheel scrolls occurred # and made the scale unreasonable? (To mitigate, we should prevent # those from doing anything unless we have a valid model, and also # reset that scale when loading a new model (latter is probably # already done, but I didn't check). See also the comments # in def wheelEvent.) [bruce 080220 comment] dp = - dot(pxyz, pn) # Save projection matrix before it's changed. glMatrixMode(GL_PROJECTION) glPushMatrix() current_glselect = (wX, wY, 1, 1) self._setup_projection(glselect = current_glselect) glSelectBuffer(self.SIZE_FOR_glSelectBuffer) glRenderMode(GL_SELECT) glInitNames() glMatrixMode(GL_MODELVIEW) # Save model view matrix before it's changed. glPushMatrix() # Draw model using glRenderMode(GL_SELECT) as set up above try: glClipPlane(GL_CLIP_PLANE0, (pn[0], pn[1], pn[2], dp)) glEnable(GL_CLIP_PLANE0) self._drawModel_using_DrawingSets() except: #bruce 080917 fixed predicted bugs in this except clause (untested) print_compact_traceback("exception in ThumbView._drawModel_using_DrawingSets() during GL_SELECT; ignored; restoring matrices: ") glDisable(GL_CLIP_PLANE0) glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glPopMatrix() glRenderMode(GL_RENDER) return None else: glDisable(GL_CLIP_PLANE0) # Restore model/view matrix glPopMatrix() # Restore projection matrix and set matrix mode to Model/View glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glFlush() hit_records = list(glRenderMode(GL_RENDER)) ## print "%d hits" % len(hit_records) for (near, far, names) in hit_records: ## print "hit record: near, far, names:", near, far, names # note from testing: near/far are too far apart to give actual depth, # in spite of the 1-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). ### REVIEW: this just returns the first candidate object found. # The clip plane may restrict the set of candidates well enough to # make sure that's the right one, but this is untested and unreviewed. # (And it's just my guess that that was Huaicai's intention in # setting up clipping, since it's not documented. I'm guessing that # the plane is just behind the hitpoint, but haven't confirmed this.) # [bruce 080917 comment] if names: name = names[-1] assy = self.assy obj = assy and assy.object_for_glselect_name(name) #k should always return an obj return obj return None # from ThumbView.select
def drawSiCGrid(color, line_type, w, h, up, right): """ Draw SiC grid. """ if line_type == NO_LINE: return XLen = sic_uLen * 3.0 YLen = sic_yU * 2.0 hw = w / 2.0 hh = h / 2.0 i1 = int(floor(-hw / XLen)) i2 = int(ceil(hw / XLen)) j1 = int(floor(-hh / YLen)) j2 = int(ceil(hh / YLen)) glDisable(GL_LIGHTING) glColor3fv(color) if line_type > 1: glEnable(GL_LINE_STIPPLE) if line_type == DASHED_LINE: glLineStipple(1, 0x00FF) # dashed elif line_type == DOTTED_LINE: glLineStipple(1, 0x0101) # dotted else: print "drawer.drawSiCGrid(): line_type '", line_type, \ "' is not valid. Drawing dashed grid line." glLineStipple(1, 0x00FF) # dashed glClipPlane(GL_CLIP_PLANE0, (1.0, 0.0, 0.0, hw)) glClipPlane(GL_CLIP_PLANE1, (-1.0, 0.0, 0.0, hw)) glClipPlane(GL_CLIP_PLANE2, (0.0, 1.0, 0.0, hh)) glClipPlane(GL_CLIP_PLANE3, (0.0, -1.0, 0.0, hh)) glEnable(GL_CLIP_PLANE0) glEnable(GL_CLIP_PLANE1) glEnable(GL_CLIP_PLANE2) glEnable(GL_CLIP_PLANE3) glPushMatrix() glTranslate(i1 * XLen, j1 * YLen, 0.0) for i in range(i1, i2): glPushMatrix() for j in range(j1, j2): glCallList(SiCGridList) glTranslate(0.0, YLen, 0.0) glPopMatrix() glTranslate(XLen, 0.0, 0.0) glPopMatrix() glDisable(GL_CLIP_PLANE0) glDisable(GL_CLIP_PLANE1) glDisable(GL_CLIP_PLANE2) glDisable(GL_CLIP_PLANE3) if line_type > 1: glDisable(GL_LINE_STIPPLE) xpos, ypos = hw, 0.0 f3d = Font3D(xpos=xpos, ypos=ypos, right=right, up=up, rot90=False, glBegin=False) for j in range(j1, j2): yoff = j * YLen if -hh < yoff + ypos < hh: f3d.drawString("%-.4g" % yoff, color=color, yoff=yoff) xpos, ypos = 0.0, hh f3d = Font3D(xpos=xpos, ypos=ypos, right=right, up=up, rot90=True, glBegin=False) for i in range(2 * i1, 2 * i2): yoff = i * (XLen / 2) if -hw < yoff + xpos < hw: f3d.drawString("%-.4g" % yoff, color=color, yoff=yoff) glEnable(GL_LIGHTING) return
def _enable_stereo(self, stereo_image, preserve_colors=False, no_clipping=False): """ Enables stereo rendering. This should be called before entering a drawing phase and should be accompanied by a self._disable_stereo call after the drawing for that phase. These methods push a modelview matrix on the matrix stack and modify the matrix. @param stereo_image: Indicates which stereo image is being drawn (-1 == left, 1 == right, 0 == stereo is disabled) @param preserve_colors: Disable color mask manipulations, which normally occur in anaglyph mode. (Also disable depth buffer clearing for 2nd image, which occurs then.) @param no_clipping: Disable clipping, which normally occurs in side-by-side mode. """ if not self.stereo_enabled: return glPushAttrib(GL_TRANSFORM_BIT) stereo_mode = self.stereo_mode stereo_separation = self.stereo_separation stereo_angle = self.stereo_angle # push the modelview matrix on the stack glMatrixMode(GL_MODELVIEW) glPushMatrix() separation = stereo_separation * self.scale angle = stereo_angle # might be modified below if stereo_mode <= 2: # side-by-side stereo mode # clip left or right image # reset the modelview matrix if not no_clipping: glPushMatrix() # Note: this might look redundant with the # glPushMatrix above, but removing it (and its glPopMatrix # 10 lines below) causes a bug (no image visible). # Guess: it's needed so the glLoadIdentity needed to set up # the clipping plane just below has only a temporary effect. # [bruce 080911 comment] glLoadIdentity() if stereo_image == -1: clip_eq = (-1.0, 0.0, 0.0, 0.0) else: clip_eq = (1.0, 0.0, 0.0, 0.0) # using GL_CLIP_PLANE5 for stereo clipping glClipPlane(GL_CLIP_PLANE5, clip_eq) glEnable(GL_CLIP_PLANE5) glPopMatrix() # for cross-eyed mode, exchange left and right views if stereo_mode == 2: angle *= -1 # translate images for side-by-side stereo glTranslatef(separation * stereo_image * self.right[0], separation * stereo_image * self.right[1], separation * stereo_image * self.right[2]) # rotate the stereo image ("toe-in" method) glRotatef(angle * stereo_image, self.up[0], self.up[1], self.up[2]) else: # Anaglyphs stereo mode - Red plus Blue, Cyan, or Green image. angle *= 0.5 if not preserve_colors: if stereo_image == -1: # red image glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE) else: # clear depth buffer to combine red/blue images # REVIEW: this would cause bugs in the predraw_glselectdict code # used for depth-testing selobj candidates. Maybe it does # not happen then? The name of the flag 'preserve_colors' # does not say anything about preserving depths. # Anyway, it *does* happen then, so I think there is a bug. # Also, remind me, what's the 4th arg to glColorMask? # [bruce 080911 comment] # # piotr 080911 response: You are right. This technically # causes a bug: the red image is not highlightable, # but actually when using anaglyph glasses, the bug is not # noticeable, as both red and blue images converge. # The bug becomes noticeable if user tries to highlight an # object without wearing the anaglyph glasses. # At this point, I think we can either leave it as it is, # or consider implementing anaglyph stereo by using # OpenGL alpha blending. # Also, I am not sure if highlighting problem is the only bug # that is caused by clearing the GL_DEPTH_BUFFER_BIT. glClear(GL_DEPTH_BUFFER_BIT) if stereo_mode == 3: # blue image glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE) elif stereo_mode == 4: # cyan image glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE) elif stereo_mode == 5: # green image glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE) # rotate the stereo image ("toe-in" method) glRotatef(angle * stereo_image, self.up[0], self.up[1], self.up[2]) return
def select(self, wX, wY): """ Use the OpenGL picking/selection to select any object. Return the selected object, otherwise, return None. Restore projection and model/view matrices before returning. """ ####@@@@ WARNING: The original code for this, in GLPane, has been duplicated and slightly modified # in at least three other places (search for glRenderMode to find them). This is bad; common code # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame; # that should be fixed too. [bruce 060721 comment] wZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT) gz = wZ[0][0] if gz >= GL_FAR_Z: ##Empty space was clicked return None pxyz = A(gluUnProject(wX, wY, gz)) pn = self.out pxyz -= 0.0002 * pn # Note: if this runs before the model is drawn, this can have an # exception "OverflowError: math range error", presumably because # appropriate state for gluUnProject was not set up. That doesn't # normally happen but can happen due to bugs (no known open bugs # of that kind). # Sometimes our drawing area can become "stuck at gray", # and when that happens, the same exception can occur from this line. # Could it be that too many accidental mousewheel scrolls occurred # and made the scale unreasonable? (To mitigate, we should prevent # those from doing anything unless we have a valid model, and also # reset that scale when loading a new model (latter is probably # already done, but I didn't check).) [bruce 080220 comment] dp = -dot(pxyz, pn) # Save projection matrix before it's changed. glMatrixMode(GL_PROJECTION) glPushMatrix() current_glselect = (wX, wY, 1, 1) self._setup_projection(glselect=current_glselect) glSelectBuffer(self.glselectBufferSize) glRenderMode(GL_SELECT) glInitNames() glMatrixMode(GL_MODELVIEW) # Save model view matrix before it's changed. glPushMatrix() try: glClipPlane(GL_CLIP_PLANE0, (pn[0], pn[1], pn[2], dp)) glEnable(GL_CLIP_PLANE0) self.drawModel() glDisable(GL_CLIP_PLANE0) except: print_compact_traceback("exception in mode.Draw() during GL_SELECT; ignored; restoring modelview matrix: ") glPopMatrix() glRenderMode(GL_RENDER) return None else: # Restore model/view matrix glPopMatrix() # Restore project matrix and set matrix mode to Model/View glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glFlush() hit_records = list(glRenderMode(GL_RENDER)) if debug_flags.atom_debug and 0: print "%d hits" % len(hit_records) for (near, far, names) in hit_records: # see example code, renderpass.py if debug_flags.atom_debug and 0: print "hit record: near, far, names:", near, far, names # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,) # which proves that near/far are too far apart to give actual depth, # in spite of the 1-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). if names: name = names[-1] assy = self.assy obj = assy and assy.object_for_glselect_name(name) # k should always return an obj return obj return None # from ThumbView.select
def _enable_stereo(self, stereo_image, preserve_colors = False, no_clipping = False): """ Enables stereo rendering. This should be called before entering a drawing phase and should be accompanied by a self._disable_stereo call after the drawing for that phase. These methods push a modelview matrix on the matrix stack and modify the matrix. @param stereo_image: Indicates which stereo image is being drawn (-1 == left, 1 == right, 0 == stereo is disabled) @param preserve_colors: Disable color mask manipulations, which normally occur in anaglyph mode. (Also disable depth buffer clearing for 2nd image, which occurs then.) @param no_clipping: Disable clipping, which normally occurs in side-by-side mode. """ if not self.stereo_enabled: return glPushAttrib(GL_TRANSFORM_BIT) stereo_mode = self.stereo_mode stereo_separation = self.stereo_separation stereo_angle = self.stereo_angle # push the modelview matrix on the stack glMatrixMode(GL_MODELVIEW) glPushMatrix() separation = stereo_separation * self.scale angle = stereo_angle # might be modified below if stereo_mode <= 2: # side-by-side stereo mode # clip left or right image # reset the modelview matrix if not no_clipping: glPushMatrix() # Note: this might look redundant with the # glPushMatrix above, but removing it (and its glPopMatrix # 10 lines below) causes a bug (no image visible). # Guess: it's needed so the glLoadIdentity needed to set up # the clipping plane just below has only a temporary effect. # [bruce 080911 comment] glLoadIdentity() if stereo_image == -1: clip_eq = (-1.0, 0.0, 0.0, 0.0) else: clip_eq = ( 1.0, 0.0, 0.0, 0.0) # using GL_CLIP_PLANE5 for stereo clipping glClipPlane(GL_CLIP_PLANE5, clip_eq) glEnable(GL_CLIP_PLANE5) glPopMatrix() # for cross-eyed mode, exchange left and right views if stereo_mode == 2: angle *= -1 # translate images for side-by-side stereo glTranslatef(separation * stereo_image * self.right[0], separation * stereo_image * self.right[1], separation * stereo_image * self.right[2]) # rotate the stereo image ("toe-in" method) glRotatef(angle * stereo_image, self.up[0], self.up[1], self.up[2]) else: # Anaglyphs stereo mode - Red plus Blue, Cyan, or Green image. angle *= 0.5 if not preserve_colors: if stereo_image == -1: # red image glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE) else: # clear depth buffer to combine red/blue images # REVIEW: this would cause bugs in the predraw_glselectdict code # used for depth-testing selobj candidates. Maybe it does # not happen then? The name of the flag 'preserve_colors' # does not say anything about preserving depths. # Anyway, it *does* happen then, so I think there is a bug. # Also, remind me, what's the 4th arg to glColorMask? # [bruce 080911 comment] # # piotr 080911 response: You are right. This technically # causes a bug: the red image is not highlightable, # but actually when using anaglyph glasses, the bug is not # noticeable, as both red and blue images converge. # The bug becomes noticeable if user tries to highlight an # object without wearing the anaglyph glasses. # At this point, I think we can either leave it as it is, # or consider implementing anaglyph stereo by using # OpenGL alpha blending. # Also, I am not sure if highlighting problem is the only bug # that is caused by clearing the GL_DEPTH_BUFFER_BIT. glClear(GL_DEPTH_BUFFER_BIT) if stereo_mode == 3: # blue image glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE) elif stereo_mode == 4: # cyan image glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE) elif stereo_mode == 5: # green image glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE) # rotate the stereo image ("toe-in" method) glRotatef(angle * stereo_image, self.up[0], self.up[1], self.up[2]) return
def select(self, wX, wY): """ Use the OpenGL picking/selection to select any object. Return the selected object, otherwise, return None. Restore projection and model/view matrices before returning. """ ####@@@@ WARNING: The original code for this, in GLPane, has been duplicated and slightly modified # in at least three other places (search for glRenderMode to find them). This is bad; common code # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame; # that should be fixed too. [bruce 060721 comment] wZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT) gz = wZ[0][0] if gz >= GL_FAR_Z: ##Empty space was clicked return None pxyz = A(gluUnProject(wX, wY, gz)) pn = self.out pxyz -= 0.0002 * pn # Note: if this runs before the model is drawn, this can have an # exception "OverflowError: math range error", presumably because # appropriate state for gluUnProject was not set up. That doesn't # normally happen but can happen due to bugs (no known open bugs # of that kind). # Sometimes our drawing area can become "stuck at gray", # and when that happens, the same exception can occur from this line. # Could it be that too many accidental mousewheel scrolls occurred # and made the scale unreasonable? (To mitigate, we should prevent # those from doing anything unless we have a valid model, and also # reset that scale when loading a new model (latter is probably # already done, but I didn't check).) [bruce 080220 comment] dp = -dot(pxyz, pn) #Save projection matrix before it's changed. glMatrixMode(GL_PROJECTION) glPushMatrix() current_glselect = (wX, wY, 1, 1) self._setup_projection(glselect=current_glselect) glSelectBuffer(self.glselectBufferSize) glRenderMode(GL_SELECT) glInitNames() glMatrixMode(GL_MODELVIEW) # Save model view matrix before it's changed. glPushMatrix() try: glClipPlane(GL_CLIP_PLANE0, (pn[0], pn[1], pn[2], dp)) glEnable(GL_CLIP_PLANE0) self.drawModel() glDisable(GL_CLIP_PLANE0) except: print_compact_traceback( "exception in mode.Draw() during GL_SELECT; ignored; restoring modelview matrix: " ) glPopMatrix() glRenderMode(GL_RENDER) return None else: # Restore model/view matrix glPopMatrix() #Restore project matrix and set matrix mode to Model/View glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glFlush() hit_records = list(glRenderMode(GL_RENDER)) if debug_flags.atom_debug and 0: print "%d hits" % len(hit_records) for (near, far, names) in hit_records: # see example code, renderpass.py if debug_flags.atom_debug and 0: print "hit record: near, far, names:", near, far, names # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,) # which proves that near/far are too far apart to give actual depth, # in spite of the 1-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). if names: name = names[-1] assy = self.assy obj = assy and assy.object_for_glselect_name(name) #k should always return an obj return obj return None # from ThumbView.select