summaryrefslogtreecommitdiff
path: root/cad/src/exprs/scratch/rendering.py
blob: c88cd67679d58e10b67a734763a1346f0e9d93b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Copyright 2007 Nanorex, Inc.  See LICENSE file for details.
"""
rendering.py -- rendering loop control, etc

$Id$

"""

    IorE drawkid def should be sort of like:

    def drawkid(self, kid):
        warpfuncs = getattr(self.env.glpane, '_exprs__drawkid_funcs', None) #070218 or so new feature
        while warpfuncs:
            func, warpfuncs = warpfuncs
            try:
                color0 = '?' # for error message in case of exception
                color0 = func(color) # don't alter color itself until we're sure we had no exception in this try clause
                color = normalize_color(color0)
            except:
                print_compact_traceback("exception in %r.fix_color(%r) warping color %r with func %r (color0 = %r): " % \
                                        ( self, color_orig, color, func, color0 ) )
                pass
            continue
        return color

    and is now: (except it doesn't really contain that _exprs__whatever line):

    def drawkid(self, kid): # note: supersedes nim _e_decorate_draw [070210]
        #e plans: protect from exceptions, debug_pref for no-coord-change enforcement (for testing),
        # and most importantly, make possible a drawing pass which draws only a specified subset of drawables
        # but in their coord- or glstate- transforming containers, e.g. for a highlight-drawing pass.
        # (that last is what we're doing now, with _exprs__whatever 070218)
        oldfunc = getattr(glpane, '_exprs__whatever', None) #e rename attr
        if kid is not None:
            kid.draw()
        return


class _drawkid_oldfunc: # use this to replace glpane drawkid func called inside IorE drawkid ###implem
    "One of these becomes the temporary drawkid func ... " # other code is WRONG, oldfunc(parent, kid) is what we need to be able to call
    def __init__(self, drawkid_contrib_func, oldfunc):
        self.drawkid_contrib_func = drawkid_contrib_func # public for set? if not, need a set method too
        self.oldfunc = oldfunc or noop # oldfunc might be None
    def parent_draw_kid(self, parent, kid):
        "when self is active in dynenv, a bound method made from this method is what gets called in place of (or by?) usual drawkid (in oldfunc)"
        func = self.drawkid_contrib_func # what someone contributed... #doc better
        oldfunc = self.oldfunc
        func(oldfunc, parent, kid)
    def set_drawkid_contrib_func(self, func): # (a rare case where I think a set method is better (clearer) than a public settable attr)
        self.drawkid_contrib_func = func
    pass

class SelectiveRedrawer(InstanceOrExpr): #070217 to make highlighting work in displists, someday [replaces "draw decorators"]
    """
    """
    def draw(self):
        self._parents_lists = {} # maps obj (drawn during us) to list of all its draw-parents (highest possible parent being self)
        self._later = {} # maps obj to list of funcs to call later in same GL state & coords as used to draw obj
        #e put self in dynenv if needed, to permit registration of selective redraw or point-finding (x,y,depth)
            #### QUESTION: (when is that done? for make of delegate?? or right now, in glpane? (if so, restore prior, or reg with all???)
        # begin having drawkid track parents in us
        # (as well as in whatever objs it did before, in glpane linked list like for fix_color)
            ###### WAIT, what about displists it calls? they'll need to have tracked parents ahead of time, i think... ####e
        glpane = self.env.glpane
        oldfunc = getattr(glpane, '_exprs__whatever', None) #e rename attr
        newfunc = _drawkid_oldfunc( self._drawkid_collect_parents, oldfunc) #e rename _drawkid_oldfunc and maybe the args passed
        setattr(glpane, '_exprs__whatever', newfunc) # this means IorE.drawkid will call it ###IMPLEM
        try:
            self.drawkid(self.delegate) # has try/except, so we don't need our own around just this call
                ###k make sure what it has is not try/finally
            # end having drawkid track that (see below)
            # some of those kids/grandkids also entered things into our list of things needing redraw
            # figure out transclose of parents of things we need to redraw (or run code in their coords anyway -- redraw in modified way)
            objdict = dict([(obj,obj) for obj in self._later])
            junk, self._proper_parents = self._transclose_parents(objdict)
            # begin modifying drawkid to filter... the method of mod is really to wrap it with our own code...
            newfunc.set_drawkid_contrib_func( self._drawkid_selective )
            #
            self.drawkid(self.delegate)
        except:
            msg = "bug: exception somewhere in %r.draw(), delegate %r; len(parents_lists) = %d, len(_later) = %d" % \
                      (self, self.delegate, len(self._parents_lists), len(self._later))
            print_compact_traceback( msg + ": ")
            pass
        # end
        setattr(glpane, '_exprs__whatever', oldfunc)
        #e and repeat, if we have more than one redraw-pass
        return
    def _drawkid_collect_parents(self, oldfunc, parent, kid):
        """This intercepts (a func called by) parent.drawkid(kid) when we're collecting parents,
        with oldfunc being (a func called inside) parent.drawkid as if we were not active in dynenv.
        """
        if 0:
            # this would be equiv to behavior we replace:
            oldfunc(parent, kid)
            return
        # parent is a draw-parent of kid
        self._parents_lists.setdefault(kid, []).append(parent) #e could optim
        oldfunc(parent, kid)
        return
    def redraw_later(self, obj, func): ### PUT SELF in env so i can be called
        """This should be called during self.draw (by something we're drawing). obj should be that something, or anything else
        we might draw during self.draw. This registers func to be called (in our later special selective-redrawing pass)
        once for each time obj was drawn in the main pass, in the same local coords and OpenGL state obj was drawn in at the time
        (but not inside any display lists being called or compiled, whether or not obj was drawn into one).
           Typical values for func are obj.draw(), modified(obj).draw(), a lambda that calls gluProject or so....
        [#e we might add ways to ask for more args to be passed to func (none are now), like the draw-parent, self, etc.]
        """
        self._later.setdefault(obj, []).append(func) #e could optim
        return
    def _transclose_parents(self, objdict):
        """Given a dict from obj to obj, for some objs to redraw-modifiedly,
        return two things: a dict including them & all their parents (recursively),
        and a dict including only the ones that were parents.
        """
        proper_parents = {} # proper parents (objdict objs not in there unless they are also parents)
        def collect_parents(obj, dict1):
            for parent in self._parents_lists[obj]:
                dict1[parent] = parent
                proper_parents[parent] = parent
            return
        res1 = transclose(objdict, collect_parents)
        return res1, proper_parents #k no need to return res1?
    def _drawkid_selective(self, oldfunc, parent, obj):
        """Called using same interface as _drawkid_collect_parents.
        What we do:
        - for objs registered in _later, call their func (or funcs). GL state and coords will be same as when obj.draw was called.
        - for objs which are draw-parents of other objs, call their .draw (so as to get called for their kids, in GL state they set up).
          (If they also do direct drawing, this should not hurt; they can also check a flag and not do it, someday. #e)
        - for other objs, do nothing.
        """
        for func in self._later.get(obj, ()):
            try:
                func()
            except:
                msg = "bug: %r._drawkid_selective() ignoring exception in func %r for %r (parent %r)" % \
                      (self, func, obj, parent)
                print_compact_traceback( msg + ": ")
            continue
        if obj in self._proper_parents:
            oldfunc(parent, obj) ##k
        return
    pass