Mercurial > parpg-core
view src/parpg/bGrease/renderer/vector.py @ 144:a6b25c2cedab
Move comment to correct place.
author | KarstenBock@gmx.net |
---|---|
date | Mon, 03 Oct 2011 13:05:23 +0200 |
parents | 0f659c7675f6 |
children |
line wrap: on
line source
############################################################################# # # 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)]