summaryrefslogtreecommitdiff
path: root/cad/src/graphics/drawing/GLPrimitiveSet.py
blob: c964fa9c3533828f0dbb04a03778f25c31ac1e68 (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
# 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.