Mercurial > parpg-core
annotate src/parpg/bGrease/renderer/vector.py @ 66:96af64cf3b81
Renamed grease to bGrease (Basic Grease) to get rid of conflicts with an already installed grease.
author | KarstenBock@gmx.net |
---|---|
date | Mon, 05 Sep 2011 15:00:34 +0200 |
parents | src/parpg/grease/renderer/vector.py@09b581087d68 |
children | 0f659c7675f6 |
rev | line source |
---|---|
27 | 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 | |
66
96af64cf3b81
Renamed grease to bGrease (Basic Grease) to get rid of conflicts with an already installed grease.
KarstenBock@gmx.net
parents:
27
diff
changeset
|
18 from bGrease.geometry import Vec2d |
27 | 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 |