def stencilPush(): '''Create a new stack in stencil stack. All the next draw will be done in stencil buffer until stencilUse() will be called.''' global __stencil_stack glPushAttrib(GL_STENCIL_BUFFER_BIT | GL_STENCIL_TEST) # enable stencil test if not yet enabled if not glIsEnabled(GL_STENCIL_TEST): glClearStencil(0) glClear(GL_STENCIL_BUFFER_BIT) glEnable(GL_STENCIL_TEST) # increment the draw buffer glStencilFunc(GL_NEVER, 0x0, 0x0) glStencilOp(GL_INCR, GL_INCR, GL_INCR) glColorMask(0, 0, 0, 0) # save model view m = glGetFloatv(GL_MODELVIEW_MATRIX) __stencil_stack_view.append(m) # start recording GL operation dl = GlDisplayList() dl.start() __stencil_stack_dl.append(dl) __stencil_stack += 1
def _endHighlight(self): """ Restore OpenGL settings changed by _preHighlight to standard values. """ glDepthMask(GL_TRUE) ## glEnable(GL_DEPTH_TEST) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) glDisable(GL_STENCIL_TEST) self.setDepthRange_Normal() glMatrixMode(GL_MODELVIEW) return
def stencilUse(): '''Switch from stencil draw to color draw. Now, all drawing will be done on color buffer, using latest stencil stack. ''' # stop recording gl operation __stencil_stack_dl[__stencil_stack - 1].stop() __stencil_stack_dl[__stencil_stack - 1].draw() # draw inner content only when stencil match the buffer glColorMask(1, 1, 1, 1) glStencilFunc(GL_EQUAL, __stencil_stack, __stencil_stack) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
def stencilUse(): '''Switch from stencil draw to color draw. Now, all drawing will be done on color buffer, using latest stencil stack. ''' # stop recording gl operation __stencil_stack_dl[__stencil_stack-1].stop() __stencil_stack_dl[__stencil_stack-1].draw() # draw inner content only when stencil match the buffer glColorMask(1, 1, 1, 1) glStencilFunc(GL_EQUAL, __stencil_stack, __stencil_stack) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
def _preHighlight(self): ### TODO: rename; move into GLPane_minimal, use in GLPane.py """ Change OpenGL settings to prepare for highlighting. """ self.makeCurrent() glClear(GL_STENCIL_BUFFER_BIT) glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) ## glDisable(GL_DEPTH_TEST) glStencilFunc(GL_ALWAYS, 1, 1) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) glEnable(GL_STENCIL_TEST) self.setDepthRange_Highlighting() glMatrixMode(GL_MODELVIEW) return
def _preHighlight( self ): ### TODO: rename; move into GLPane_minimal, use in GLPane.py """ Change OpenGL settings to prepare for highlighting. """ self.makeCurrent() glClear(GL_STENCIL_BUFFER_BIT) glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) ## glDisable(GL_DEPTH_TEST) glStencilFunc(GL_ALWAYS, 1, 1) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) glEnable(GL_STENCIL_TEST) self.setDepthRange_Highlighting() glMatrixMode(GL_MODELVIEW) return
def stencilPop(): '''Pop out the last stack from stencil stack''' global __stencil_stack glPopAttrib() __stencil_stack -= 1 # remove current stencil stack __stencil_stack_dl.pop() __stencil_stack_view.pop() # replay stencil stack from the start # only if it's enabled if not glIsEnabled(GL_STENCIL_TEST): return # clear stencil glClearStencil(0) glClear(GL_STENCIL_BUFFER_BIT) # increment the draw buffer glStencilFunc(GL_NEVER, 0x0, 0x0) glStencilOp(GL_INCR, GL_INCR, GL_INCR) glColorMask(0, 0, 0, 0) # replay all gl operation for idx in xrange(__stencil_stack): dl = __stencil_stack_dl[idx] view = __stencil_stack_view[idx] with gx_matrix_identity: glMultMatrixf(view) dl.draw() # draw inner content only when stencil match the buffer glColorMask(1, 1, 1, 1) glStencilFunc(GL_EQUAL, __stencil_stack, __stencil_stack) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
def _draw_highlighted_selobj(self, selobj, hicolor): #bruce 070920 split this out; 090311 renamed it """ Draw selobj in highlighted form, using its "selobj drawing interface" (not yet a formal interface; we use several methods including draw_in_abs_coords). Record the drawn pixels in the OpenGL stencil buffer to optimize future detection of the mouse remaining over the same selobj (to avoid redraws then). Assume we have standard modelview and projection matrices on entry, and restore that state on exit (copying or recreating it as we prefer). Note: Current implementation uses an extra level on the projection matrix stack by default (selobj can override this). This could be easily revised if desired. """ # draw the selobj as highlighted, and make provisions for fast test # (by external code) of mouse still being over it (using stencil buffer) # note: if selobj highlight is partly translucent or transparent (neither yet supported), # we might need to draw it depth-sorted with other translucent objects # (now drawn by some modes using Draw_after_highlighting, not depth-sorted or modularly); # but our use of the stencil buffer assumes it's drawn at the end (except for objects which # don't obscure it for purposes of highlighting hit-test). This will need to be thought through # carefully if there can be several translucent objects (meant to be opaque re hit-tests), # and traslucent highlighting. See also the comment about highlight_into_depth, below. [bruce 060724 comment] # first gather info needed to know what to do -- highlight color (and whether to draw that at all) # and whether object might be bigger when highlighted (affects whether depth write is needed now). assert hicolor is not None #bruce 070919 highlight_might_be_bigger = True # True is always ok; someday we might let some objects tell us this can be False # color-writing is needed here, iff the mode asked for it, for this selobj. # # Note: in current code this is always True (as assertion above implies), # but it's possible we'll decide to retain self.selobj even if its # hicolor is None, but just not draw it in that case, or even to draw it # in some ways and not others -- so just in case, keep this test for now. # [bruce 070919 comment] highlight_into_color = (hicolor is not None) if highlight_into_color: # depth-writing is needed here, if highlight might be drawn in front of not-yet-drawn transparent surfaces # (like Build mode water surface) -- otherwise they will look like they're in front of some of the highlighting # even though they're not. (In principle, the preDraw_glselect_dict call above needs to know whether this depth # writing occurred ###doc why. Probably we should store it into the object itself... ###@@@ review, then doit ) highlight_into_depth = highlight_might_be_bigger else: highlight_into_depth = False ###@@@ might also need to store 0 into obj...see discussion above if not highlight_into_depth: glDepthMask( GL_FALSE) # turn off depth writing (but not depth test) if not highlight_into_color: glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) # don't draw color pixels # Note: stencil buffer was cleared earlier in this paintGL call. glStencilFunc(GL_ALWAYS, 1, 1) # These args make sure stencil test always passes, so color is drawn if we want it to be, # and so we can tell whether depth test passes in glStencilOp (even if depth *writing* is disabled ###untested); # this also sets reference value of 1 for use by GL_REPLACE. # (Args are: func to say when drawing-test passes; ref value; comparison mask. # Warning: Passing -1 for reference value, to get all 1's, does not work -- it makes ref value 0!) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) # turn on stencil-buffer writing based on depth test # (args are: what to do on fail, zfail, zpass (see OpenGL "red book" p. 468)) glEnable(GL_STENCIL_TEST) # this enables both aspects of the test: effect on drawing, and use of stencil op (I think #k); # apparently they can't be enabled separately ##print glGetIntegerv( GL_STENCIL_REF) # Now "translate the world" slightly closer to the screen, # to ensure depth test passes for appropriate parts of highlight-drawing # even if roundoff errors would make it unreliable to just let equal depths pass the test. # As of 070921 we use glDepthRange for this. self.setDepthRange_Highlighting() try: colorsorter_safe = getattr(selobj, '_selobj_colorsorter_safe', False) # colorsorter_safe being False (in two places in this file) # is a bugfix for the breaking of expr handle highlighting # by the debug_pref('GLPane: highlight atoms in CSDLs?') # (but bug's cause is not understood) [bruce 090311] self.set_drawing_phase('selobj') #bruce 070124 #bruce 070329 moved set of drawing_phase from just after selobj.draw_in_abs_coords to just before it. # [This should fix the Qt4 transition issue which is the subject of reminder bug 2300, # though it can't be tested yet since it has no known effect on current code, only on future code.] def func(): self.graphicsMode.Draw_highlighted_selobj( self, selobj, hicolor) # TEST someday: test having color writing disabled here -- does stencil write still happen?? # (not urgent, since we definitely need color writing here.) return self._call_func_that_draws_objects( func, self.part, bare_primitives=colorsorter_safe) except: # try/except added for GL-state safety, bruce 061218 print_compact_traceback( "bug: exception in %r.Draw_highlighted_selobj for %r ignored: " % \ (self.graphicsMode, selobj) ) pass self.set_drawing_phase('?') self.setDepthRange_Normal() # restore other gl state # (but don't do unneeded OpenGL ops # in case that speeds up OpenGL drawing) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) # no need to undo glStencilFunc state, I think -- whoever cares will set it up again # when they reenable stenciling. if not highlight_into_color: glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) if not highlight_into_depth: glDepthMask(GL_TRUE) if debug_pref("GLPane: draw stencil buffer?", Choice_boolean_False, prefs_key=True): # draw stencil buffer in orange [bruce 090105] glStencilFunc(GL_EQUAL, 1, 1) # only draw where stencil is set glDepthMask(GL_FALSE) glDisable(GL_DEPTH_TEST) # Note: according to some web forum (not confirmed in red book or by test), # glDisable(GL_DEPTH_TEST) also disables depth writing, # so the above glDepthMask(GL_FALSE) is redundant. # This differs from my recollection, so should be checked if it matters. # [bruce 090105] self.draw_solid_color_everywhere(orange) # note: we already drew highlighting selobj above, so that won't obscure this glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) pass glDisable(GL_STENCIL_TEST) return # from _draw_highlighted_selobj
def _draw_highlighted_selobj(self, selobj, hicolor): # bruce 070920 split this out; 090311 renamed it """ Draw selobj in highlighted form, using its "selobj drawing interface" (not yet a formal interface; we use several methods including draw_in_abs_coords). Record the drawn pixels in the OpenGL stencil buffer to optimize future detection of the mouse remaining over the same selobj (to avoid redraws then). Assume we have standard modelview and projection matrices on entry, and restore that state on exit (copying or recreating it as we prefer). Note: Current implementation uses an extra level on the projection matrix stack by default (selobj can override this). This could be easily revised if desired. """ # draw the selobj as highlighted, and make provisions for fast test # (by external code) of mouse still being over it (using stencil buffer) # note: if selobj highlight is partly translucent or transparent (neither yet supported), # we might need to draw it depth-sorted with other translucent objects # (now drawn by some modes using Draw_after_highlighting, not depth-sorted or modularly); # but our use of the stencil buffer assumes it's drawn at the end (except for objects which # don't obscure it for purposes of highlighting hit-test). This will need to be thought through # carefully if there can be several translucent objects (meant to be opaque re hit-tests), # and traslucent highlighting. See also the comment about highlight_into_depth, below. [bruce 060724 comment] # first gather info needed to know what to do -- highlight color (and whether to draw that at all) # and whether object might be bigger when highlighted (affects whether depth write is needed now). assert hicolor is not None # bruce 070919 highlight_might_be_bigger = ( True ) # True is always ok; someday we might let some objects tell us this can be False # color-writing is needed here, iff the mode asked for it, for this selobj. # # Note: in current code this is always True (as assertion above implies), # but it's possible we'll decide to retain self.selobj even if its # hicolor is None, but just not draw it in that case, or even to draw it # in some ways and not others -- so just in case, keep this test for now. # [bruce 070919 comment] highlight_into_color = hicolor is not None if highlight_into_color: # depth-writing is needed here, if highlight might be drawn in front of not-yet-drawn transparent surfaces # (like Build mode water surface) -- otherwise they will look like they're in front of some of the highlighting # even though they're not. (In principle, the preDraw_glselect_dict call above needs to know whether this depth # writing occurred ###doc why. Probably we should store it into the object itself... ###@@@ review, then doit ) highlight_into_depth = highlight_might_be_bigger else: highlight_into_depth = False ###@@@ might also need to store 0 into obj...see discussion above if not highlight_into_depth: glDepthMask(GL_FALSE) # turn off depth writing (but not depth test) if not highlight_into_color: glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) # don't draw color pixels # Note: stencil buffer was cleared earlier in this paintGL call. glStencilFunc(GL_ALWAYS, 1, 1) # These args make sure stencil test always passes, so color is drawn if we want it to be, # and so we can tell whether depth test passes in glStencilOp (even if depth *writing* is disabled ###untested); # this also sets reference value of 1 for use by GL_REPLACE. # (Args are: func to say when drawing-test passes; ref value; comparison mask. # Warning: Passing -1 for reference value, to get all 1's, does not work -- it makes ref value 0!) glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE) # turn on stencil-buffer writing based on depth test # (args are: what to do on fail, zfail, zpass (see OpenGL "red book" p. 468)) glEnable(GL_STENCIL_TEST) # this enables both aspects of the test: effect on drawing, and use of stencil op (I think #k); # apparently they can't be enabled separately ##print glGetIntegerv( GL_STENCIL_REF) # Now "translate the world" slightly closer to the screen, # to ensure depth test passes for appropriate parts of highlight-drawing # even if roundoff errors would make it unreliable to just let equal depths pass the test. # As of 070921 we use glDepthRange for this. self.setDepthRange_Highlighting() try: colorsorter_safe = getattr(selobj, "_selobj_colorsorter_safe", False) # colorsorter_safe being False (in two places in this file) # is a bugfix for the breaking of expr handle highlighting # by the debug_pref('GLPane: highlight atoms in CSDLs?') # (but bug's cause is not understood) [bruce 090311] self.set_drawing_phase("selobj") # bruce 070124 # bruce 070329 moved set of drawing_phase from just after selobj.draw_in_abs_coords to just before it. # [This should fix the Qt4 transition issue which is the subject of reminder bug 2300, # though it can't be tested yet since it has no known effect on current code, only on future code.] def func(): self.graphicsMode.Draw_highlighted_selobj(self, selobj, hicolor) # TEST someday: test having color writing disabled here -- does stencil write still happen?? # (not urgent, since we definitely need color writing here.) return self._call_func_that_draws_objects(func, self.part, bare_primitives=colorsorter_safe) except: # try/except added for GL-state safety, bruce 061218 print_compact_traceback( "bug: exception in %r.Draw_highlighted_selobj for %r ignored: " % (self.graphicsMode, selobj) ) pass self.set_drawing_phase("?") self.setDepthRange_Normal() # restore other gl state # (but don't do unneeded OpenGL ops # in case that speeds up OpenGL drawing) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) # no need to undo glStencilFunc state, I think -- whoever cares will set it up again # when they reenable stenciling. if not highlight_into_color: glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) if not highlight_into_depth: glDepthMask(GL_TRUE) if debug_pref("GLPane: draw stencil buffer?", Choice_boolean_False, prefs_key=True): # draw stencil buffer in orange [bruce 090105] glStencilFunc(GL_EQUAL, 1, 1) # only draw where stencil is set glDepthMask(GL_FALSE) glDisable(GL_DEPTH_TEST) # Note: according to some web forum (not confirmed in red book or by test), # glDisable(GL_DEPTH_TEST) also disables depth writing, # so the above glDepthMask(GL_FALSE) is redundant. # This differs from my recollection, so should be checked if it matters. # [bruce 090105] self.draw_solid_color_everywhere(orange) # note: we already drew highlighting selobj above, so that won't obscure this glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) pass glDisable(GL_STENCIL_TEST) return # from _draw_highlighted_selobj