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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
|
# Copyright 2009 Nanorex, Inc. See LICENSE file for details.
"""
GLPane_drawingset_methods.py -- DrawingSet/CSDL helpers for GLPane_minimal
@author: Bruce
@version: $Id$
@copyright: 2009 Nanorex, Inc. See LICENSE file for details.
History:
Bruce 090219 refactored this out of yesterday's additions to
Part.after_drawing_model.
"""
from utilities.debug_prefs import debug_pref
from utilities.debug_prefs import Choice_boolean_False, Choice_boolean_True
from utilities.debug import print_compact_traceback
import foundation.env as env
from graphics.drawing.DrawingSetCache import DrawingSetCache
from graphics.widgets.GLPane_csdl_collector import GLPane_csdl_collector
from graphics.widgets.GLPane_csdl_collector import fake_GLPane_csdl_collector
_DEBUG_DSETS = False
# ==
class GLPane_drawingset_methods(object):
"""
DrawingSet/CSDL helpers for GLPane_minimal, as a mixin class
"""
# todo, someday: split our intended mixin-target, GLPane_minimal,
# into a base class GLPane_minimal_base which doesn't inherit us,
# which we can inherit to explain to pylint that we *do* have a
# drawing_phase attribute, and the rest. These need to be in
# separate modules to avoid an import cycle. We can't inherit
# GLPane_minimal itself -- that is not only an import cycle
# but a superclass-cycle! [bruce 090227 comment]
_csdl_collector = None # allocated on demand
_csdl_collector_class = fake_GLPane_csdl_collector
# Note: this attribute is modified dynamically.
# This default value is appropriate for drawing which does not
# occur between matched calls of _before/_after_drawing_csdls, since
# drawing then is deprecated but needs to work,
# so this class will work, but warn when created.
# Its "normal" value is used between matched calls
# of _before/_after_drawing_csdls.
_always_remake_during_movies = False # True in some subclasses
_remake_display_lists = True # might change at start and end of each frame
def __get_csdl_collector(self):
"""
get method for self.csdl_collector property:
Initialize self._csdl_collector if necessary, and return it.
"""
try:
## print "__get_csdl_collector", self
if not self._csdl_collector:
## print "alloc in __get_csdl_collector", self
self._csdl_collector = self._csdl_collector_class( self)
# note: self._csdl_collector_class changes dynamically
return self._csdl_collector
except:
# without this try/except, python will report any exception in here
# (or at least any AttributeError) as if it was an AttributeError
# on self.csdl_collector, discarding all info about the nature
# and code location of the actual error! [bruce 090220]
### TODO: flush all output streams in print_compact_traceback;
# in current code, the following prints before we finish printing
# whatever print statement had the exception partway through, if one did
print_compact_traceback("\nfollowing exception is *really* this one, inside __get_csdl_collector: ")
print
raise
pass
def __set_csdl_collector(self):
"""
set method for self.csdl_collector property; should never be called
"""
assert 0
def __del_csdl_collector(self):
"""
del method for self.csdl_collector property
"""
## print "\ndel csdl_collector", self
self._csdl_collector = None
csdl_collector = property(__get_csdl_collector, __set_csdl_collector, __del_csdl_collector)
# accessed only in this class (as of 090317)
def _has_csdl_collector(self): # not used as of 090317
"""
@return: whether we presently have an allocated csdl_collector
(which would be returned by self.csdl_collector).
@rtype: boolean
"""
return self._csdl_collector is not None
_current_drawingset_cache_policy = None # or a tuple of (temporary, cachename)
def _before_drawing_csdls(self,
bare_primitives = False,
dset_change_indicator = None ):
"""
[private submethod of _call_func_that_draws_model]
Whenever some CSDLs are going to be drawn (or more precisely,
collected for drawing, since they might be redrawn again later
due to reuse_cached_drawingsets) by self.draw_csdl,
call this first, draw them (I mean pass them to self.draw_csdl),
and then call self._after_drawing_csdls.
@param bare_primitives: when True, also open up a new CSDL
and collect all "bare primitives" (not drawn into other CSDLs)
into it, and draw it at the end. The new CSDL will be marked to
permit reentrancy of ColorSorter.start, and will not be allowed
to open up a "catchall display list" (an nfr for CSDL) since that
might lead to nested display list compiles, not allowed by OpenGL.
@param dset_change_indicator: if provided and not false,
and if a certain debug_pref is enabled, then if _after_drawing_csdls
would use a drawingset_cache and one already
exists and has the same value of dset_change_indicator
saved from our last use of that cache, we assume there
is no need for the caller to remake the drawingsets in
that cache, which we tell it (the caller) by returning True.
(This is never fully correct -- for details see caller docstring.
Soon [090313] we intend to add usage_tracking to make it much
closer to being correct.)
@return: usually False; True in special cases explained in the
docstring for our dset_change_indicator parameter. WARNING:
when we return true, our caller is REQUIRED (not just permitted)
to immediately call _after_drawing_csdls (with certain options,
see current calling code) without doing anything to its cached
drawingsets/csdls -- i.e. to skip its usual "drawing".
"""
# as of 090317, defined and used only in this class; will be refactored;
# some other files have comments about it which will need revision then
# someday we might take other args, e.g. an "intent map"
del self.csdl_collector
self._csdl_collector_class = GLPane_csdl_collector
# instantiated the first time self.csdl_collector is accessed
# (which might be just below, depending on prefs and options)
self._remake_display_lists = self._compute_remake_display_lists_now()
# note: this affects how we use both debug_prefs, below.
res = False # return value, modified below
cache = None # set to actual DrawingSetCache if we find or make one
cache_began_usage_tracking = False # modified if it did that
# [not yet fully implemented or used as of 090317, but should cause no harm]
if debug_pref("GLPane: use DrawingSets to draw model?",
Choice_boolean_True, #bruce 090225 revised
non_debug = True,
prefs_key = "v1.2/GLPane: use DrawingSets?" ):
if self._remake_display_lists:
self.csdl_collector.setup_for_drawingsets()
# sets self.csdl_collector.use_drawingsets, and more
# (note: this is independent of self.permit_shaders,
# since DrawingSets can be used even if shaders are not)
self._current_drawingset_cache_policy = self._choose_drawingset_cache_policy()
if debug_pref("GLPane: reuse cached DrawingSets? (has bugs)",
Choice_boolean_False,
non_debug = True,
prefs_key = True
):
if dset_change_indicator:
policy = self._current_drawingset_cache_policy
# policy is None or a tuple of (temporary, cachename) [misnamed?]
cache = self._find_or_make_dset_cache_to_use(policy, make = False)
if cache:
if cache.saved_change_indicator == dset_change_indicator:
res = True
# NOTE: the following debug_pref is not yet implemented,
# and this method plus a few others will be heavily refactored
# before it is, since keeping track of (planned) usage tracking
# is getting too messy without that.
# So I if 0'd it (sort of) but left it in for illustration.
# [bruce 090317 comment]
if 0 and debug_pref("GLPane: usage-track cached DrawingSets?", #bruce 090313
Choice_boolean_False, #####True,
non_debug = True, # for now -- remove when works
prefs_key = True
):
if not res:
# if we're reusing dset_cache, i.e. not remaking it,
# then no need to track usage "while remaking it";
# this must be synchronized with _after_drawing_csdls
# calling end_tracking_usage -- thus the requirements
# (new as of 090313) about caller honoring return value res
# (see our docstring); for robustness (since _after can't
# deduce this perfectly, at least not clearly) we also
# set a flag about whether we're doing this in the cache.
cache = self._find_or_make_dset_cache_to_use(policy, make = True)
# (note make = True, different than earlier call)
cache.begin_tracking_usage() #### args?
#}
cache_began_usage_tracking = True
#} # fix word order (or just refactor this mess)
cache.track_use() ###### WRONG, do this when we draw it! (in _after I think)
#}
pass
pass
pass
pass
pass
pass
# following will be done in a better way when we refactor [bruce 090317 comment]:
## if cache:
## cache.is_usage_tracking = cache_began_usage_tracking ####### how do we know it's false if it's not?
## #}
## pass
if debug_pref("GLPane: highlight atoms in CSDLs?",
Choice_boolean_True, #bruce 090225 revised
# maybe: scrap the pref or make it not non_debug
non_debug = True,
prefs_key = "v1.2/GLPane: highlight atoms in CSDLs?" ):
if bare_primitives and self._remake_display_lists:
self.csdl_collector.setup_for_bare_primitives()
return res
def _compute_remake_display_lists_now(self): #bruce 090224
"""
[can be overridden in subclasses, but isn't so far]
"""
# as of 090317, defined and used only in this class
remake_during_movies = debug_pref(
"GLPane: remake display lists during movies?",
Choice_boolean_True,
# Historically this was hardcoded to False;
# but I don't know whether it's still a speedup
# to avoid remaking them (on modern graphics cards),
# or perhaps a slowdown, so I'm making it optional.
# Also, when active it will disable shader primitives,
# forcing use of polygonal primitives instead;
#### REVIEW whether it makes sense at all in that case.
# [bruce 090224]
# update: I'll make it default True, since that's more reliable,
# and we might not have time to test it.
# [bruce 090225]
non_debug = True,
prefs_key = "v1.2/GLPane: remake display lists during movies?" )
# whether to actually remake is more complicated -- it depends on self
# (thumbviews always remake) and on movie_is_playing flag (external).
remake_during_movies = remake_during_movies or \
self._always_remake_during_movies
remake_now = remake_during_movies or not self._movie_is_playing()
if remake_now != self._remake_display_lists:
# (kluge: knows how calling code uses value)
# leave this in until we've tested the performance of movie playing
# for both prefs values; it's not verbose
print "fyi: setting _remake_display_lists = %r" % remake_now
return remake_now
def _movie_is_playing(self): #bruce 090224 split this out of ChunkDrawer
"""
[can be overridden in subclasses, but isn't so far]
"""
# as of 090317, defined and used only in this class
return env.mainwindow().movie_is_playing #bruce 051209
# warning: use of env.mainwindow is a KLUGE;
# could probably be fixed, but needs review for thumbviews
def draw_csdl(self, csdl, selected = False, highlight_color = None):
"""
Depending on prefs, either draw csdl now (with the given draw options),
or make sure it will be in a DrawingSet which will be drawn later
with those options.
"""
# as of 090317, called in many drawing methods elsewhere (and one here),
# defined only here; calls and API won't change in planned upcoming
# refactoring, but implem might.
# future: to optimize rigid drag, options (aka "drawing intent")
# will also include which dynamic transform (if any) to draw it inside.
csdl_collector = self.csdl_collector
intent = (bool(selected), highlight_color)
# note: intent must match the "inverse code" in
# self._draw_options(), and must be a suitable
# dict key.
# someday: include symbolic "dynamic transform" in intent,
# to optimize rigid drag. (see scratch/TransformNode.py)
if csdl_collector.use_drawingsets:
csdl_collector.collect_csdl(csdl, intent)
else:
options = self._draw_options(intent)
csdl.draw(**options)
return
def _draw_options(self, intent): #bruce 090226
"""
Given a drawing intent (as created inside self.draw_csdl),
return suitable options (as a dict) to be passed to either
CSDL.draw or DrawingSet.draw.
"""
# as of 090317, defined and used only in this class,
# but logically, could be overridden in subclasses;
# will probably not be changed during planned upcoming refactoring
selected, highlight_color = intent # must match the code in draw_csdl
if highlight_color is None:
return dict(selected = selected)
else:
return dict(selected = selected,
highlighted = True,
highlight_color = highlight_color )
pass
def _after_drawing_csdls(self,
error = False,
reuse_cached_dsets_unchanged = False,
dset_change_indicator = None ):
"""
[private submethod of _call_func_that_draws_model]
@see: _before_drawing_csdls
@param error: if the caller knows, it can pass an error flag
to indicate whether drawing succeeded or failed.
If it's known to have failed, we might not do some
things we normally do. Default value is False
since most calls don't pass anything. (#REVIEW: good? true?)
@param reuse_cached_dsets_unchanged: whether to do what it says.
Typically equal to the return value of the preceding call
of _before_drawing_csdls.
@param dset_change_indicator: if true, store in the dset cache
(whether found or made, modified or not) as .saved_change_indicator.
"""
# as of 090317, defined and used only in this class; will be refactored
self._remake_display_lists = self._compute_remake_display_lists_now()
if not error:
if self.csdl_collector.bare_primitives:
# this must come before the _draw_drawingsets below
csdl = self.csdl_collector.finish_bare_primitives()
self.draw_csdl(csdl)
pass
if self.csdl_collector.use_drawingsets:
self._draw_drawingsets(
reuse_cached_dsets_unchanged = reuse_cached_dsets_unchanged,
dset_change_indicator = dset_change_indicator
)
# note, the DrawingSets themselves last between draw calls,
# and are stored elsewhere in self. self.csdl_collector has
# attributes used to collect necessary info during a
# draw call for updating the DrawingSets before drawing them.
pass
pass
del self.csdl_collector
del self._csdl_collector_class # expose class default value
return
def _whole_model_drawingset_change_indicator(self):
"""
[should be overridden in subclasses which want to cache drawingsets]
"""
# as of 090317, overridden in one subclass, called only in this class
# (in _call_func_that_draws_model); might remain unchanged after
# planned upcoming refactoring
return None # disable this optim by default
def _call_func_that_draws_model(self,
func,
prefunc = None,
postfunc = None,
bare_primitives = None,
drawing_phase = None,
whole_model = True
):
"""
If whole_model is False (*not* the default):
Call func() between calls of self._before_drawing_csdls(**kws)
and self._after_drawing_csdls(). Return whatever func() returns
(or raise whatever exception it raises, but call
_after_drawing_csdls even when raising an exception).
func should usually be something which calls before/after_drawing_model
inside it, e.g. one of the standard functions for drawing the
entire model (e.g. part.draw or graphicsMode.Draw),
or self._call_func_that_draws_objects which draws a portion of
the model between those methods.
If whole_model is True (default):
Sometimes act as above, but other times do the same drawing
that func would have done, without actually calling it,
by reusing cached DrawingSets whenever nothing changed
to make them out of date.
Either way, always call prefunc (if provided) before, and
postfunc (if provided) after, calling or not calling func.
Those calls participate in the effect of our exception-protection
and drawing_phase behaviors, but they stay out of the whole_model-
related optimizations (so they are called even if func is not).
@warning: prefunc and postfunc are not called between
_before_drawing_csdls and _after_drawing_csdls, so they
should not use csdls for drawing. (If we need to revise this,
we might want to pass a list of funcs rather than a single func,
with each one optimized separately for sometimes not being
called; or more likely, refactor this entirely to make each
func and its redraw-vs-reuse conditions a GraphicsRule object.)
@param bare_primitives: passed to _before_drawing_csdls.
@param drawing_phase: if provided, drawing_phase must be '?'
on entry; we'll set it as specified only during this call.
If not provided, we don't check it or change it
(typically, in that case, caller ought to do something
to set it properly itself). The value of drawing_phase
matters and needs to correspond to what's drawn by func,
because it determines the "drawingset_cache" (see that
term in the code for details).
@param whole_model: whether func draws the whole model.
Default True. Permits optimizations when the model appearance
doesn't change since it was last drawn.
"""
# as of 090317, defined only here, called here and elsewhere
# (in many places); likely to remain unchanged in our API for other
# methods and client objects, even after planned upcoming refactoring,
# though we may replace *some* of its calls with something modified,
# as if inlining the refactored form.
# todo: convert some older callers to pass drawing_phase
# rather than implementing their own similar behavior.
if drawing_phase is not None:
assert self.drawing_phase == '?'
self.set_drawing_phase(drawing_phase)
if prefunc:
try:
prefunc()
except:
msg = "bug: exception in %r calling prefunc %r: skipping it" % (self, prefunc)
print_compact_traceback(msg + ": ")
pass
pass
if whole_model:
dset_change_indicator = self._whole_model_drawingset_change_indicator()
# note: if this is not false, then if a certain debug_pref is enabled,
# then if we'd use a drawingset_cache and one already
# exists and has the same value of dset_change_indicator
# saved from our last use of that cache, we assume there
# is no need to remake the drawingsets and therefore
# no need to call func at all; instead we just redraw
# the saved drawingsets. This is never correct -- in practice
# some faster but nonnull alternative to func would need
# to be called -- but is useful for testing the maximum
# speedup possible from an "incremental remake of drawing"
# optimization, and is a prototype for correct versions
# of similar optimizations. [bruce 090309]
else:
dset_change_indicator = None
skip_dset_remake = self._before_drawing_csdls(
bare_primitives = bare_primitives,
dset_change_indicator = dset_change_indicator
)
# WARNING: if skip_dset_remake, we are REQUIRED (as of 090313)
# (not just permitted, as before)
# [or at least we would have been if I had finished implementing
# usage tracking -- see comment elsewhere for status -- bruce 090317]
# to do nothing to any of our cached dsets or csdl collectors
# (i.e. to do no drawing) before calling _after_drawing_csdls.
# Fortunately we call it just below, so it's easy to verify
# this requirement -- just don't forget to think about this
# if you modify the following code. (### Todo: refactor this to
# make it more failsafe, e.g. pass func to a single method
# which encapsulates _before_drawing_csdls and _after_drawing_csdls...
# but wait, isn't *this* method that single method? Ok, just make
# them private [done] and document them as only for use by this
# method [done]. Or maybe a smaller part of this really *should* be
# a single method.... [yes, or worse -- 090317])
error = True
res = None
try:
if not skip_dset_remake:
res = func()
error = False
finally:
# (note: this is usually what does much of the actual drawing
# requested by func())
self._after_drawing_csdls(
error,
reuse_cached_dsets_unchanged = skip_dset_remake,
dset_change_indicator = dset_change_indicator
)
if postfunc:
try:
postfunc()
except:
msg = "bug: exception in %r calling postfunc %r: skipping it" % (self, postfunc)
print_compact_traceback(msg + ": ")
pass
pass
if drawing_phase is not None:
self.set_drawing_phase('?')
return res
def set_drawing_phase(self, drawing_phase):
"""
[overridden in subclasses of the class we mix into;
see those for doc]
"""
# as of 090317, called in many places, overridden in some;
# this will remain true after planned upcoming refactoring
return
def _call_func_that_draws_objects(self, func, part, bare_primitives = None):
"""
Like _call_func_that_draws_model,
but also wraps func with the part methods
before/after_drawing_model, necessary when drawing
some portion of a Part (or when drawing all of it,
but typical methods to draw all of it already do this
themselves, e.g. part.draw or graphicsMode.Draw).
This method's name is meant to indicate that you can pass us a func
which draws one or more model objects, or even all of them,
as long as it doesn't already bracket its individual object .draw calls
with the Part methods before/after_drawing_model,
like the standard functions for drawing the entire model do.
"""
# as of 090317, defined only here, called only elsewhere;
# likely to remain unchanged in our API for other methods,
# even after planned upcoming refactoring
def func2():
part.before_drawing_model()
error = True
try:
func()
error = False
finally:
part.after_drawing_model(error)
return
self._call_func_that_draws_model( func2,
bare_primitives = bare_primitives,
whole_model = False )
return
_dset_caches = None # or map from cachename to persistent DrawingSetCache
### review: make _dset_caches per-Part? Probably not -- might be a big
# user of memory or VRAM, and the CSDLs persist so it might not matter
# too much. OTOH, Part-switching will be slower without doing this.
# Consider doing it only for the last two Parts, or so.
# Be sure to delete it for destroyed Parts.
#
# todo: delete this when deleting an assy, or next using a new one
# (not very important -- could reduce VRAM in some cases,
# but won't matter after loading a new similar file)
def _draw_drawingsets(self,
reuse_cached_dsets_unchanged = False,
dset_change_indicator = None ):
"""
Using info collected in self.csdl_collector,
update our cached DrawingSets for this frame
(unless reuse_cached_dsets_unchanged is true),
then draw them.
"""
### REVIEW: move inside csdl_collector?
# or into some new cooperating object, which keeps the DrawingSets?
# as of 090317, defined and used only in this class (in _after_drawing_csdls)
incremental = debug_pref("GLPane: use incremental DrawingSets?",
Choice_boolean_True, #bruce 090226, since it works
non_debug = True,
prefs_key = "v1.2/GLPane: incremental DrawingSets?" )
csdl_collector = self.csdl_collector
intent_to_csdls = \
csdl_collector.grab_intent_to_csdls_dict()
# grab (and reset) the current value of the
# dict from intent (about how a csdl's drawingset should be drawn)
# to a set of csdls (as a dict from their csdl_id's),
# which includes exactly the CSDLs which should be drawn in this
# frame (whether or not they were drawn in the last frame).
# We own this dict, and can destructively modify it as convenient
# (though ownership is needed only in our incremental case below).
if reuse_cached_dsets_unchanged:
# note: we assume reuse_cached_dsets_unchanged is never true
# unless caller verified that the cached dsets in question
# actually exist, so we don't need to check this
assert incremental # simple sanity check of caller behavior
intent_to_csdls.clear() # [no longer needed as of 090313]
# set dset_cache to the DrawingSetCache we should use;
# if it's temporary, make sure not to store it in any dict
if incremental:
# figure out (temporary, cachename)
cache_before = self._current_drawingset_cache_policy # chosen during _before_drawing_csdls
cache_after = self._choose_drawingset_cache_policy() # chosen now
## assert cache_after == cache_before
if not (cache_after == cache_before):
print "bug: _choose_drawingset_cache_policy differs: before %r vs after %r" % \
(cache_before, cache_after)
dset_cache = self._find_or_make_dset_cache_to_use( cache_before)
else:
# not incremental:
# destroy all old caches (matters after runtime prefs change)
if self._dset_caches:
for cachename, cache in self._dset_caches.items():
cache.destroy()
self._dset_caches = None
pass
# make a new DrawingSetCache to use
temporary, cachename = True, None
dset_cache = DrawingSetCache(cachename, temporary)
del temporary, cachename
pass
##### REVIEW: do this inside some method of dset_cache?
# This might relate to its upcoming usage_tracking features. [090313]
if dset_change_indicator:
dset_cache.saved_change_indicator = dset_change_indicator
##### REVIEW: if not, save None?
if not reuse_cached_dsets_unchanged:
# (note: if not incremental, then dset_cache is empty, so the
# following method just fills it non-incrementally in that case,
# so we don't need to pass an incremental flag to the method)
dset_cache.incrementally_set_contents_to(
intent_to_csdls,
## dset_change_indicator = dset_change_indicator
)
del intent_to_csdls
# draw all current DrawingSets
dset_cache.draw( self,
self._draw_options,
debug = _DEBUG_DSETS,
destroy_as_drawn = dset_cache.temporary or not incremental
# review (not urgent): can this value be simplified
# due to relations between
# dset_cache.temporary and incremental?
)
if dset_cache.temporary:
#### REVIEW: do this in dset_cache.draw when destroy_as_drawn is true,
# or when some other option is passed?
# note: dset_cache is guaranteed not to be in any dict we have
dset_cache.destroy()
return
def _find_or_make_dset_cache_to_use(self, policy, make = True):
"""
Find, or make (if option permits), the DrawingSetCache to use,
based on policy, which can be None if not make,
or can be (temporary, cachename).
@return: existing or new DrawingSetCache, or None if not make and
no existing one is found.
"""
# as of 090317, called only in this class, in _before_drawing_csdls and
# (during _after_drawing_csdls) in _draw_drawingsets;
# defined only in this class
if not make and not policy:
return None
temporary, cachename = policy
if not make:
return not temporary and \
self._dset_caches and \
self._dset_caches.get(cachename)
else:
if temporary:
dset_cache = DrawingSetCache(cachename, temporary)
else:
if self._dset_caches is None:
self._dset_caches = {}
dset_cache = self._dset_caches.get(cachename)
if not dset_cache:
dset_cache = DrawingSetCache(cachename, temporary)
self._dset_caches[cachename] = dset_cache
pass
pass
return dset_cache
pass
def _choose_drawingset_cache_policy(self): #bruce 090227
"""
Based on self.drawing_phase, decide which cache to keep DrawingSets in
and whether it should be temporary.
@return: (temporary, cachename)
@rtype: (bool, string)
[overridden in subclasses of the class we mix into;
for calling, private to this mixin class]
"""
# as of 090317, called only in this class, in _before_drawing_csdls and
# (during _after_drawing_csdls) in _draw_drawingsets;
# defined here and overridden in one other class
return False, None
pass # end of mixin class GLPane_drawingset_methods
# end
|