Mercurial > parpg-source
diff 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 |
line wrap: on
line diff
--- a/bGrease/renderer/vector.py Wed Sep 21 15:43:12 2011 +0200 +++ b/bGrease/renderer/vector.py Wed Sep 21 16:10:14 2011 +0200 @@ -1,166 +1,165 @@ -############################################################################# -# -# Copyright (c) 2010 by Casey Duncan and contributors -# All Rights Reserved. -# -# This software is subject to the provisions of the MIT License -# A copy of the license should accompany this distribution. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# -############################################################################# - -__version__ = '$Id$' - -__all__ = ('Vector',) - -from bGrease.geometry import Vec2d -import ctypes -from math import sin, cos, radians -import pyglet - - -class Vector(object): - """Renders shapes in a classic vector graphics style - - :param scale: Scaling factor applied to shape vertices when rendered. - - :param line_width: The line width provided to ``glLineWidth`` before rendering. - If not specified or None, ``glLineWidth`` is not called, and the line - width used is determined by the OpenGL state at the time of rendering. - - :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled. - This allows for fractional line widths as well. If ``False``, the blending - and line smoothing modes are unchanged. - - :param corner_fill: If true (the default), the shape corners will be filled - with round points when the ``line_width`` exceeds 2.0. This improves - the visual quality of the rendering at larger line widths at some - cost to performance. Has no effect if ``line_width`` is not specified. - - :param position_component: Name of :class:`grease.component.Position` - component to use. Shapes rendered are offset by the entity positions. - - :param renderable_component: Name of :class:`grease.component.Renderable` - component to use. This component specifies the entities to be - rendered and their base color. - - :param shape_component: Name of :class:`grease.component.Shape` - component to use. Source of the shape vertices for each entity. - - The entities rendered are taken from the intersection of he position, - renderable and shape components each time :meth:`draw` is called. - """ - - CORNER_FILL_SCALE = 0.6 - CORNER_FILL_THRESHOLD = 2.0 - - def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True, - position_component='position', - renderable_component='renderable', - shape_component='shape'): - self.scale = float(scale) - self.corner_fill = corner_fill - self.line_width = line_width - self.anti_alias = anti_alias - self._max_line_width = None - self.position_component = position_component - self.renderable_component = renderable_component - self.shape_component = shape_component - - def set_world(self, world): - self.world = world - - def _generate_verts(self): - """Generate vertex and index arrays for rendering""" - vert_count = sum(len(shape.verts) + 1 - for shape, ignored, ignored in self.world.components.join( - self.shape_component, self.position_component, self.renderable_component)) - v_array = (CVertColor * vert_count)() - if vert_count > 65536: - i_array = (ctypes.c_uint * 2 * vert_count)() - i_size = pyglet.gl.GL_UNSIGNED_INT - else: - i_array = (ctypes.c_ushort * (2 * vert_count))() - i_size = pyglet.gl.GL_UNSIGNED_SHORT - v_index = 0 - i_index = 0 - scale = self.scale - rot_vec = Vec2d(0, 0) - for shape, position, renderable in self.world.components.join( - self.shape_component, self.position_component, self.renderable_component): - shape_start = v_index - angle = radians(-position.angle) - rot_vec.x = cos(angle) - rot_vec.y = sin(angle) - r = int(renderable.color.r * 255) - g = int(renderable.color.g * 255) - b = int(renderable.color.b * 255) - a = int(renderable.color.a * 255) - for vert in shape.verts: - vert = vert.cpvrotate(rot_vec) * scale + position.position - v_array[v_index].vert.x = vert.x - v_array[v_index].vert.y = vert.y - v_array[v_index].color.r = r - v_array[v_index].color.g = g - v_array[v_index].color.b = b - v_array[v_index].color.a = a - if v_index > shape_start: - i_array[i_index] = v_index - 1 - i_index += 1 - i_array[i_index] = v_index - i_index += 1 - v_index += 1 - if shape.closed and v_index - shape_start > 2: - i_array[i_index] = v_index - 1 - i_index += 1 - i_array[i_index] = shape_start - i_index += 1 - return v_array, i_size, i_array, i_index - - def draw(self, gl=pyglet.gl): - vertices, index_size, indices, index_count = self._generate_verts() - if index_count: - if self.anti_alias: - gl.glEnable(gl.GL_LINE_SMOOTH) - gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST) - gl.glEnable(gl.GL_BLEND) - gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) - gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT) - gl.glEnableClientState(gl.GL_VERTEX_ARRAY) - gl.glEnableClientState(gl.GL_COLOR_ARRAY) - gl.glVertexPointer( - 2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices)) - gl.glColorPointer( - 4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor), - ctypes.pointer(vertices[0].color)) - if self.line_width is not None: - gl.glLineWidth(self.line_width) - if self._max_line_width is None: - range_out = (ctypes.c_float * 2)() - gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out) - self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE - if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD: - gl.glEnable(gl.GL_POINT_SMOOTH) - gl.glPointSize( - min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width)) - gl.glDrawArrays(gl.GL_POINTS, 0, index_count) - gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices)) - gl.glPopClientAttrib() - - -class CVert(ctypes.Structure): - _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)] - -class CColor(ctypes.Structure): - _fields_ = [ - ("r", ctypes.c_ubyte), - ("g", ctypes.c_ubyte), - ("b", ctypes.c_ubyte), - ("a", ctypes.c_ubyte), - ] - -class CVertColor(ctypes.Structure): - _fields_ = [("vert", CVert), ("color", CColor)] - +############################################################################# +# +# Copyright (c) 2010 by Casey Duncan and contributors +# All Rights Reserved. +# +# This software is subject to the provisions of the MIT License +# A copy of the license should accompany this distribution. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# +############################################################################# + +__version__ = '$Id$' + +__all__ = ('Vector',) + +from parpg.bGrease.geometry import Vec2d +import ctypes +from math import sin, cos, radians +import pyglet + + +class Vector(object): + """Renders shapes in a classic vector graphics style + + :param scale: Scaling factor applied to shape vertices when rendered. + + :param line_width: The line width provided to ``glLineWidth`` before rendering. + If not specified or None, ``glLineWidth`` is not called, and the line + width used is determined by the OpenGL state at the time of rendering. + + :param anti_alias: If ``True``, OpenGL blending and line smoothing is enabled. + This allows for fractional line widths as well. If ``False``, the blending + and line smoothing modes are unchanged. + + :param corner_fill: If true (the default), the shape corners will be filled + with round points when the ``line_width`` exceeds 2.0. This improves + the visual quality of the rendering at larger line widths at some + cost to performance. Has no effect if ``line_width`` is not specified. + + :param position_component: Name of :class:`grease.component.Position` + component to use. Shapes rendered are offset by the entity positions. + + :param renderable_component: Name of :class:`grease.component.Renderable` + component to use. This component specifies the entities to be + rendered and their base color. + + :param shape_component: Name of :class:`grease.component.Shape` + component to use. Source of the shape vertices for each entity. + + The entities rendered are taken from the intersection of he position, + renderable and shape components each time :meth:`draw` is called. + """ + + CORNER_FILL_SCALE = 0.6 + CORNER_FILL_THRESHOLD = 2.0 + + def __init__(self, scale=1.0, line_width=None, anti_alias=True, corner_fill=True, + position_component='position', + renderable_component='renderable', + shape_component='shape'): + self.scale = float(scale) + self.corner_fill = corner_fill + self.line_width = line_width + self.anti_alias = anti_alias + self._max_line_width = None + self.position_component = position_component + self.renderable_component = renderable_component + self.shape_component = shape_component + + def set_world(self, world): + self.world = world + + def _generate_verts(self): + """Generate vertex and index arrays for rendering""" + vert_count = sum(len(shape.verts) + 1 + for shape, ignored, ignored in self.world.components.join( + self.shape_component, self.position_component, self.renderable_component)) + v_array = (CVertColor * vert_count)() + if vert_count > 65536: + i_array = (ctypes.c_uint * 2 * vert_count)() + i_size = pyglet.gl.GL_UNSIGNED_INT + else: + i_array = (ctypes.c_ushort * (2 * vert_count))() + i_size = pyglet.gl.GL_UNSIGNED_SHORT + v_index = 0 + i_index = 0 + scale = self.scale + rot_vec = Vec2d(0, 0) + for shape, position, renderable in self.world.components.join( + self.shape_component, self.position_component, self.renderable_component): + shape_start = v_index + angle = radians(-position.angle) + rot_vec.x = cos(angle) + rot_vec.y = sin(angle) + r = int(renderable.color.r * 255) + g = int(renderable.color.g * 255) + b = int(renderable.color.b * 255) + a = int(renderable.color.a * 255) + for vert in shape.verts: + vert = vert.cpvrotate(rot_vec) * scale + position.position + v_array[v_index].vert.x = vert.x + v_array[v_index].vert.y = vert.y + v_array[v_index].color.r = r + v_array[v_index].color.g = g + v_array[v_index].color.b = b + v_array[v_index].color.a = a + if v_index > shape_start: + i_array[i_index] = v_index - 1 + i_index += 1 + i_array[i_index] = v_index + i_index += 1 + v_index += 1 + if shape.closed and v_index - shape_start > 2: + i_array[i_index] = v_index - 1 + i_index += 1 + i_array[i_index] = shape_start + i_index += 1 + return v_array, i_size, i_array, i_index + + def draw(self, gl=pyglet.gl): + vertices, index_size, indices, index_count = self._generate_verts() + if index_count: + if self.anti_alias: + gl.glEnable(gl.GL_LINE_SMOOTH) + gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST) + gl.glEnable(gl.GL_BLEND) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + gl.glPushClientAttrib(gl.GL_CLIENT_VERTEX_ARRAY_BIT) + gl.glEnableClientState(gl.GL_VERTEX_ARRAY) + gl.glEnableClientState(gl.GL_COLOR_ARRAY) + gl.glVertexPointer( + 2, gl.GL_FLOAT, ctypes.sizeof(CVertColor), ctypes.pointer(vertices)) + gl.glColorPointer( + 4, gl.GL_UNSIGNED_BYTE, ctypes.sizeof(CVertColor), + ctypes.pointer(vertices[0].color)) + if self.line_width is not None: + gl.glLineWidth(self.line_width) + if self._max_line_width is None: + range_out = (ctypes.c_float * 2)() + gl.glGetFloatv(gl.GL_ALIASED_LINE_WIDTH_RANGE, range_out) + self._max_line_width = float(range_out[1]) * self.CORNER_FILL_SCALE + if self.corner_fill and self.line_width > self.CORNER_FILL_THRESHOLD: + gl.glEnable(gl.GL_POINT_SMOOTH) + gl.glPointSize( + min(self.line_width * self.CORNER_FILL_SCALE, self._max_line_width)) + gl.glDrawArrays(gl.GL_POINTS, 0, index_count) + gl.glDrawElements(gl.GL_LINES, index_count, index_size, ctypes.pointer(indices)) + gl.glPopClientAttrib() + + +class CVert(ctypes.Structure): + _fields_ = [("x", ctypes.c_float), ("y", ctypes.c_float)] + +class CColor(ctypes.Structure): + _fields_ = [ + ("r", ctypes.c_ubyte), + ("g", ctypes.c_ubyte), + ("b", ctypes.c_ubyte), + ("a", ctypes.c_ubyte), + ] + +class CVertColor(ctypes.Structure): + _fields_ = [("vert", CVert), ("color", CColor)]