comparison bGrease/renderer/vector.py @ 65:e856b604b650

Changed "import bGrease" to "import parpg.bGrease".
author KarstenBock@gmx.net
date Wed, 21 Sep 2011 16:10:14 +0200
parents ff3e395abf91
children
comparison
equal deleted inserted replaced
64:b73050f98411 65:e856b604b650
13 13
14 __version__ = '$Id$' 14 __version__ = '$Id$'
15 15
16 __all__ = ('Vector',) 16 __all__ = ('Vector',)
17 17
18 from bGrease.geometry import Vec2d 18 from parpg.bGrease.geometry import Vec2d
19 import ctypes 19 import ctypes
20 from math import sin, cos, radians 20 from math import sin, cos, radians
21 import pyglet 21 import pyglet
22 22
23 23
24 class Vector(object): 24 class Vector(object):
25 """Renders shapes in a classic vector graphics style 25 """Renders shapes in a classic vector graphics style
26
27 :param scale: Scaling factor applied to shape vertices when rendered.
28
29 :param line_width: The line width provided to ``glLineWidth`` before rendering.
30 If not specified or None, ``glLineWidth`` is not called, and the line
31 width used is determined by the OpenGL state at the time of rendering.
32 26
33 :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled. 27 :param scale: Scaling factor applied to shape vertices when rendered.
34 This allows for fractional line widths as well. If ``False``, the blending
35 and line smoothing modes are unchanged.
36 28
37 :param corner_fill: If true (the default), the shape corners will be filled 29 :param line_width: The line width provided to ``glLineWidth`` before rendering.
38 with round points when the ``line_width`` exceeds 2.0. This improves 30 If not specified or None, ``glLineWidth`` is not called, and the line
39 the visual quality of the rendering at larger line widths at some 31 width used is determined by the OpenGL state at the time of rendering.
40 cost to performance. Has no effect if ``line_width`` is not specified.
41 32
42 :param position_component: Name of :class:`grease.component.Position` 33 :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled.
43 component to use. Shapes rendered are offset by the entity positions. 34 This allows for fractional line widths as well. If ``False``, the blending
35 and line smoothing modes are unchanged.
44 36
45 :param renderable_component: Name of :class:`grease.component.Renderable` 37 :param corner_fill: If true (the default), the shape corners will be filled
46 component to use. This component specifies the entities to be 38 with round points when the ``line_width`` exceeds 2.0. This improves
47 rendered and their base color. 39 the visual quality of the rendering at larger line widths at some
40 cost to performance. Has no effect if ``line_width`` is not specified.
48 41
49 :param shape_component: Name of :class:`grease.component.Shape` 42 :param position_component: Name of :class:`grease.component.Position`
50 component to use. Source of the shape vertices for each entity. 43 component to use. Shapes rendered are offset by the entity positions.
51 44
52 The entities rendered are taken from the intersection of he position, 45 :param renderable_component: Name of :class:`grease.component.Renderable`
53 renderable and shape components each time :meth:`draw` is called. 46 component to use. This component specifies the entities to be
54 """ 47 rendered and their base color.
55 48
56 CORNER_FILL_SCALE = 0.6 49 :param shape_component: Name of :class:`grease.component.Shape`
57 CORNER_FILL_THRESHOLD = 2.0 50 component to use. Source of the shape vertices for each entity.
58 51
59 def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True, 52 The entities rendered are taken from the intersection of he position,
60 position_component='position', 53 renderable and shape components each time :meth:`draw` is called.
61 renderable_component='renderable', 54 """
62 shape_component='shape'):
63 self.scale = float(scale)
64 self.corner_fill = corner_fill
65 self.line_width = line_width
66 self.anti_alias = anti_alias
67 self._max_line_width = None
68 self.position_component = position_component
69 self.renderable_component = renderable_component
70 self.shape_component = shape_component
71
72 def set_world(self, world):
73 self.world = world
74 55
75 def _generate_verts(self): 56 CORNER_FILL_SCALE = 0.6
76 """Generate vertex and index arrays for rendering""" 57 CORNER_FILL_THRESHOLD = 2.0
77 vert_count = sum(len(shape.verts) + 1
78 for shape, ignored, ignored in self.world.components.join(
79 self.shape_component, self.position_component, self.renderable_component))
80 v_array = (CVertColor * vert_count)()
81 if vert_count > 65536:
82 i_array = (ctypes.c_uint * 2 * vert_count)()
83 i_size = pyglet.gl.GL_UNSIGNED_INT
84 else:
85 i_array = (ctypes.c_ushort * (2 * vert_count))()
86 i_size = pyglet.gl.GL_UNSIGNED_SHORT
87 v_index = 0
88 i_index = 0
89 scale = self.scale
90 rot_vec = Vec2d(0, 0)
91 for shape, position, renderable in self.world.components.join(
92 self.shape_component, self.position_component, self.renderable_component):
93 shape_start = v_index
94 angle = radians(-position.angle)
95 rot_vec.x = cos(angle)
96 rot_vec.y = sin(angle)
97 r = int(renderable.color.r * 255)
98 g = int(renderable.color.g * 255)
99 b = int(renderable.color.b * 255)
100 a = int(renderable.color.a * 255)
101 for vert in shape.verts:
102 vert = vert.cpvrotate(rot_vec) * scale + position.position
103 v_array[v_index].vert.x = vert.x
104 v_array[v_index].vert.y = vert.y
105 v_array[v_index].color.r = r
106 v_array[v_index].color.g = g
107 v_array[v_index].color.b = b
108 v_array[v_index].color.a = a
109 if v_index > shape_start:
110 i_array[i_index] = v_index - 1
111 i_index += 1
112 i_array[i_index] = v_index
113 i_index += 1
114 v_index += 1
115 if shape.closed and v_index - shape_start > 2:
116 i_array[i_index] = v_index - 1
117 i_index += 1
118 i_array[i_index] = shape_start
119 i_index += 1
120 return v_array, i_size, i_array, i_index
121 58
122 def draw(self, gl=pyglet.gl): 59 def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True,
123 vertices, index_size, indices, index_count = self._generate_verts() 60 position_component='position',
124 if index_count: 61 renderable_component='renderable',
125 if self.anti_alias: 62 shape_component='shape'):
126 gl.glEnable(gl.GL_LINE_SMOOTH) 63 self.scale = float(scale)
127 gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST) 64 self.corner_fill = corner_fill
128 gl.glEnable(gl.GL_BLEND) 65 self.line_width = line_width
129 gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) 66 self.anti_alias = anti_alias
130 gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT) 67 self._max_line_width = None
131 gl.glEnableClientState(gl.GL_VERTEX_ARRAY) 68 self.position_component = position_component
132 gl.glEnableClientState(gl.GL_COLOR_ARRAY) 69 self.renderable_component = renderable_component
133 gl.glVertexPointer( 70 self.shape_component = shape_component
134 2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices)) 71
135 gl.glColorPointer( 72 def set_world(self, world):
136 4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor), 73 self.world = world
137 ctypes.pointer(vertices[0].color)) 74
138 if self.line_width is not None: 75 def _generate_verts(self):
139 gl.glLineWidth(self.line_width) 76 """Generate vertex and index arrays for rendering"""
140 if self._max_line_width is None: 77 vert_count = sum(len(shape.verts) + 1
141 range_out = (ctypes.c_float * 2)() 78 for shape, ignored, ignored in self.world.components.join(
142 gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out) 79 self.shape_component, self.position_component, self.renderable_component))
143 self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE 80 v_array = (CVertColor * vert_count)()
144 if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD: 81 if vert_count > 65536:
145 gl.glEnable(gl.GL_POINT_SMOOTH) 82 i_array = (ctypes.c_uint * 2 * vert_count)()
146 gl.glPointSize( 83 i_size = pyglet.gl.GL_UNSIGNED_INT
147 min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width)) 84 else:
148 gl.glDrawArrays(gl.GL_POINTS, 0, index_count) 85 i_array = (ctypes.c_ushort * (2 * vert_count))()
149 gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices)) 86 i_size = pyglet.gl.GL_UNSIGNED_SHORT
150 gl.glPopClientAttrib() 87 v_index = 0
88 i_index = 0
89 scale = self.scale
90 rot_vec = Vec2d(0, 0)
91 for shape, position, renderable in self.world.components.join(
92 self.shape_component, self.position_component, self.renderable_component):
93 shape_start = v_index
94 angle = radians(-position.angle)
95 rot_vec.x = cos(angle)
96 rot_vec.y = sin(angle)
97 r = int(renderable.color.r * 255)
98 g = int(renderable.color.g * 255)
99 b = int(renderable.color.b * 255)
100 a = int(renderable.color.a * 255)
101 for vert in shape.verts:
102 vert = vert.cpvrotate(rot_vec) * scale + position.position
103 v_array[v_index].vert.x = vert.x
104 v_array[v_index].vert.y = vert.y
105 v_array[v_index].color.r = r
106 v_array[v_index].color.g = g
107 v_array[v_index].color.b = b
108 v_array[v_index].color.a = a
109 if v_index > shape_start:
110 i_array[i_index] = v_index - 1
111 i_index += 1
112 i_array[i_index] = v_index
113 i_index += 1
114 v_index += 1
115 if shape.closed and v_index - shape_start > 2:
116 i_array[i_index] = v_index - 1
117 i_index += 1
118 i_array[i_index] = shape_start
119 i_index += 1
120 return v_array, i_size, i_array, i_index
121
122 def draw(self, gl=pyglet.gl):
123 vertices, index_size, indices, index_count = self._generate_verts()
124 if index_count:
125 if self.anti_alias:
126 gl.glEnable(gl.GL_LINE_SMOOTH)
127 gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST)
128 gl.glEnable(gl.GL_BLEND)
129 gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
130 gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT)
131 gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
132 gl.glEnableClientState(gl.GL_COLOR_ARRAY)
133 gl.glVertexPointer(
134 2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices))
135 gl.glColorPointer(
136 4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor),
137 ctypes.pointer(vertices[0].color))
138 if self.line_width is not None:
139 gl.glLineWidth(self.line_width)
140 if self._max_line_width is None:
141 range_out = (ctypes.c_float * 2)()
142 gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out)
143 self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE
144 if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD:
145 gl.glEnable(gl.GL_POINT_SMOOTH)
146 gl.glPointSize(
147 min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width))
148 gl.glDrawArrays(gl.GL_POINTS, 0, index_count)
149 gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices))
150 gl.glPopClientAttrib()
151 151
152 152
153 class CVert(ctypes.Structure): 153 class CVert(ctypes.Structure):
154 _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)] 154 _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)]
155 155
156 class CColor(ctypes.Structure): 156 class CColor(ctypes.Structure):
157 _fields_ = [ 157 _fields_ = [
158 ("r", ctypes.c_ubyte), 158 ("r", ctypes.c_ubyte),
159 ("g", ctypes.c_ubyte), 159 ("g", ctypes.c_ubyte),
160 ("b", ctypes.c_ubyte), 160 ("b", ctypes.c_ubyte),
161 ("a", ctypes.c_ubyte), 161 ("a", ctypes.c_ubyte),
162 ] 162 ]
163 163
164 class CVertColor(ctypes.Structure): 164 class CVertColor(ctypes.Structure):
165 _fields_ = [("vert", CVert), ("color", CColor)] 165 _fields_ = [("vert", CVert), ("color", CColor)]
166