comparison grease/renderer/vector.py @ 5:bc88f7d5ca8b

Added base files for grease
author KarstenBock@gmx.net
date Tue, 12 Jul 2011 10:16:48 +0200
parents
children
comparison
equal deleted inserted replaced
4:bf1dd9c24a7e 5:bc88f7d5ca8b
1 #############################################################################
2 #
3 # Copyright (c) 2010 by Casey Duncan and contributors
4 # All Rights Reserved.
5 #
6 # This software is subject to the provisions of the MIT License
7 # A copy of the license should accompany this distribution.
8 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 #
12 #############################################################################
13
14 __version__ = '$Id$'
15
16 __all__ = ('Vector',)
17
18 from grease.geometry import Vec2d
19 import ctypes
20 from math import sin, cos, radians
21 import pyglet
22
23
24 class Vector(object):
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
33 :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled.
34 This allows for fractional line widths as well. If ``False``, the blending
35 and line smoothing modes are unchanged.
36
37 :param corner_fill: If true (the default), the shape corners will be filled
38 with round points when the ``line_width`` exceeds 2.0. This improves
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.
41
42 :param position_component: Name of :class:`grease.component.Position`
43 component to use. Shapes rendered are offset by the entity positions.
44
45 :param renderable_component: Name of :class:`grease.component.Renderable`
46 component to use. This component specifies the entities to be
47 rendered and their base color.
48
49 :param shape_component: Name of :class:`grease.component.Shape`
50 component to use. Source of the shape vertices for each entity.
51
52 The entities rendered are taken from the intersection of he position,
53 renderable and shape components each time :meth:`draw` is called.
54 """
55
56 CORNER_FILL_SCALE = 0.6
57 CORNER_FILL_THRESHOLD = 2.0
58
59 def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True,
60 position_component='position',
61 renderable_component='renderable',
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
75 def _generate_verts(self):
76 """Generate vertex and index arrays for rendering"""
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
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
152
153 class CVert(ctypes.Structure):
154 _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)]
155
156 class CColor(ctypes.Structure):
157 _fields_ = [
158 ("r", ctypes.c_ubyte),
159 ("g", ctypes.c_ubyte),
160 ("b", ctypes.c_ubyte),
161 ("a", ctypes.c_ubyte),
162 ]
163
164 class CVertColor(ctypes.Structure):
165 _fields_ = [("vert", CVert), ("color", CColor)]
166