Source code for xsge_lighting

# xSGE Lighting Library
# Copyright (c) 2015, 2016 onpon4 <onpon4@riseup.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
xSGE is a collection of extensions for the SGE licensed under the GNU
General Public License.  They are designed to give additional features
to free/libre software games which aren't necessary, but are nice to
have.

xSGE extensions are not dependent on any particular SGE implementation.
They should work with any implementation that follows the specification.

This extension provides a simple interface for lighting.
"""

from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals

__version__ = "1.0.1"

import six
import sge


__all__ = ["project_light", "clear_lights", "project_darkness"]

_lights = []


[docs]def project_light(x, y, sprite, image=0): """ Add a light to the current frame. This must be called every frame :func:`xsge_lighting.project_darkness` is called to maintain the respective light. This function should be called *before* :func:`xsge_lighting.project_darkness`. Arguments: - ``x`` -- The horizontal location of the light relative to the room. - ``y`` -- The vertical location of the light relative to the room. - ``sprite`` -- The sprite to use as the light. Black pixels are ignored, and all other colors make the appropriate pixel - ``image`` -- The frame of the sprite to use, where ``0`` is the first frame. """ _lights.append((x, y, sprite, image))
[docs]def clear_lights(): """ Remove all lights that have been projected by :func:`xsge_lighting.project_light`. """ global _lights _lights = []
[docs]def project_darkness(z=100000, ambient_light=None, buffer=0): """ This function must be called every frame to maintain darkness. Arguments: - ``z`` -- The Z-axis position of the darkness in the room. Anything with a higher Z-axis value will not be affected. - ``ambient_light`` -- A :class:`sge.gfx.Color` object indicating the color that should be applied as lighting to the entirety of the darkness. Set to :const:`None` for no ambient lighting. - ``buffer`` -- An extra portion of the room, in addition to what is covered by the room's views, to cover with darkness. This can be used to prevent situations where movement of a view at the wrong time causes part of the view to not be properly covered in darkness. To ensure maximum efficiency, this should be the smallest number possible, i.e. the maximum amount of view movement that can happen in a single frame. """ global _lights if ambient_light is None: ambient_light = sge.gfx.Color("black") groups = [] for view in sge.game.current_room.views: my_groups = [] for i in six.moves.range(len(groups)): for member in groups[i]: if (view.x + view.width > member.x and view.x < member.x + member.width and view.y + view.height > member.y and view.y < member.y + member.height): my_groups.append(i) break if my_groups: g = my_groups[0] groups[g].append(view) for i in my_groups[1:]: groups[g].extend(groups[i]) del groups[i] else: groups.append([view]) for group in groups: rw = sge.game.current_room.width rh = sge.game.current_room.height dx = rw dy = rh dx2 = 0 dy2 = 0 for view in group: dx = min(dx, max(0, view.x - buffer)) dy = min(dy, max(0, view.y - buffer)) dx2 = max(dx2, min(view.x + view.width + buffer, rw)) dy2 = max(dy2, min(view.y + view.height + buffer, rh)) width = dx2 - dx height = dy2 - dy darkness = sge.gfx.Sprite(width=width, height=height) darkness.draw_lock() darkness.draw_rectangle(0, 0, width, height, fill=ambient_light) for x, y, sprite, image in _lights: darkness.draw_sprite(sprite, image, x - dx, y - dy, blend_mode=sge.BLEND_RGB_MAXIMUM) darkness.draw_unlock() sge.game.current_room.project_sprite(darkness, 0, dx, dy, z, blend_mode=sge.BLEND_RGB_MULTIPLY) clear_lights()