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
|
# Copyright 2004-2009 Nanorex, Inc. See LICENSE file for details.
"""
GLPrimitiveSet.py -- Cached data structure for rapidly drawing a set of batched
primitives collected from the CSDLs in a DrawingSet.
@author: Russ
@version: $Id$
@copyright: 2004-2009 Nanorex, Inc. See LICENSE file for details.
History:
Originally written by Russ Fish; designed together with Bruce Smith.
================================================================
See design comments on:
* GL contexts, CSDLs and DrawingSet in DrawingSet.py
* TransformControl in TransformControl.py
* VBOs, IBOs, and GLPrimitiveBuffer in GLPrimitiveBuffer.py
* GLPrimitiveSet in GLPrimitiveSet in GLPrimitiveSet.py
== GLPrimitiveSet ==
* GLPrimitiveSets are used for drawing sets of primitives from the VBO array
hunks, using indexed glMultiDrawElements calls. They are created and cached
by DrawingSet.draw() from the possibly-large sequences of primitive types and
IDs contained in the CSDLs in the DrawingSet.
* Each GLPrimitiveSet caches a drawIndex for glMultiDrawElements, which gives the
locations and lengths of blocks of indices in a hunk IBO to draw.
* It is generated from the primitive IDs contained in the CSDL's of a
DrawingSet, and stored as two host-side C/Numpy arrays for the locations and
lengths.
* Possible optimization: The drawing index could use a separate run of vertices
for each primitive, allowing the run lengths (always the same constant) to be
a constant hunk-sized array, whose values all equal the size of an index
block.
* Possible optimization: Alternately, it may turn out to be faster to compress
the primitive index into "runs", each consisting of contiguous primitives
within the hunk.
* If the primitives in a GLPrimitiveSet are in multiple VBO hunks, there will be
multiple IBO handles in the GLPrimitiveSet. While drawing, each one gets a
glMultiDrawElements call, with the relevant VBO hunk arrays enabled in the GL.
"""
import graphics.drawing.drawing_globals as drawing_globals
from graphics.drawing.ColorSortedDisplayList import ColorSortedDisplayList
from graphics.drawing.GLPrimitiveBuffer import GLPrimitiveBuffer
from graphics.drawing.TransformControl import TransformControl
from OpenGL.GL import glPushMatrix, glPopMatrix
class GLPrimitiveSet:
"""
Cached data structure for rapidly drawing a list of batched primitives
collected from the CSDLs in a DrawingSet.
"""
def __init__(self, csdl_list):
self.CSDLs = csdl_list
# Collect lists of primitives to draw in batches, and those CSDLs with
# display lists to draw as well. (A given CSDL may have both.)
self.spheres = [] # Generalize to a dict of lists?
self.cylinders = []
self.CSDLs_with_DLs = []
for csdl in self.CSDLs:
self.spheres += csdl.spheres
self.cylinders += csdl.cylinders
if len(csdl.per_color_dls) > 0:
self.CSDLs_with_DLs += [csdl]
pass
continue
self.drawIndices = {} # Generated on demand.
# Support for lazily updating drawing caches, namely a
# timestamp showing when this GLPrimitiveSet was created.
self.created = drawing_globals.eventStamp()
return
def draw(self, highlighted = False, selected = False,
patterning = True, highlight_color = None, opacity = 1.0):
"""
Draw the cached display.
"""
# Draw primitives from CSDLs through shaders, if that's turned on.
if drawing_globals.use_batched_primitive_shaders_pref:
primShaders = [(self.spheres, drawing_globals.spherePrimitives)]
if drawing_globals.use_cylinder_shaders:
primShaders += [(self.cylinders,
drawing_globals.cylinderPrimitives)]
pass
for primitives, shader in primShaders:
if len(primitives) > 0:
if True: # False ## True: indexed drawing, False: unindexed.
# Generate and cache index lists for selective drawing
# of primitives through glMultiDrawElements().
if shader not in self.drawIndices:
self.drawIndices[shader] = shader.makeDrawIndex(primitives)
pass
# With a drawIndex, draw calls glMultiDrawElements().
shader.draw(self.drawIndices[shader], highlighted, selected,
patterning, highlight_color, opacity)
else:
# (For initial testing.) Here GLPrimitiveBuffer draws the
# entire set of sphere primitives using glDrawElements().
shader.draw()
pass
pass
continue
pass
# Draw just the Display Lists, in all CSDLs which have any.
# Put TransformControl matrices onto the GL matrix stack when present.
# (Pushing/popping could be minimized by sorting the cached CSDL's.)
# [algorithm revised by bruce 090203]
lastTC = None
for csdl in self.CSDLs_with_DLs:
tc = csdl.transformControl
if tc is not lastTC:
if lastTC is not None:
glPopMatrix()
pass
if tc is not None:
glPushMatrix()
tc.applyTransform()
pass
pass
lastTC = tc
csdl.draw(highlighted, selected, patterning, highlight_color,
draw_primitives = False) # Just draw the DL's.
continue
if lastTC is not None:
glPopMatrix()
return
pass # End of class GLPrimitiveSet.
|