view pytouhou/ui/sdl/gamerenderer.py @ 612:73f134f84c7f

Request a RGB888 context, since SDL2’s default of RGB332 sucks. On X11/GLX, it will select the first config available, that is the best one, while on EGL it will iterate over them to select the one closest to what the application requested. Of course, anything lower than RGB888 looks bad and we really don’t want that.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Thu, 26 Mar 2015 20:20:37 +0100
parents e15672733c93
children d1f0bb0b7a17
line wrap: on
line source

# -*- encoding: utf-8 -*-
##
## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com>
##
## 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; version 3 only.
##
## 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.
##

from itertools import chain
from os.path import join

from pytouhou.lib.sdl import Rect, SDLError

from pytouhou.utils.helpers import get_logger
logger = get_logger(__name__)


class GameRenderer(object):
    def __init__(self, resource_loader, window):
        self.window = window
        self.texture_manager = TextureManager(resource_loader, self.window.win)
        font_name = join(resource_loader.game_dir, 'font.ttf')
        try:
            self.font_manager = FontManager(font_name, 16, self.window.win)
        except SDLError:
            self.font_manager = None
            logger.error('Font file “%s” not found, disabling text rendering altogether.', font_name)


    def load_textures(self, anms):
        self.texture_manager.load(anms)


    def load_background(self, background):
        if background is not None:
            logger.error('Background rendering unavailable in the SDL backend.')


    def start(self, common):
        pass


    def render(self, game):
        self.render_game(game)
        self.render_text(game.texts)
        self.render_interface(game.interface, game.boss)


    def render_game(self, game):
        x, y = game.interface.game_pos
        self.window.win.render_set_viewport(Rect(x, y, game.width, game.height))
        self.window.win.render_set_clip_rect(Rect(x, -y, game.width, game.height))

        if game is not None:
            self.window.win.render_clear()

            self.render_elements([enemy for enemy in game.enemies if enemy.visible])
            self.render_elements(game.effects)
            self.render_elements(chain(game.players_bullets,
                                       game.lasers_sprites(),
                                       game.players,
                                       game.msg_sprites()))
            self.render_elements(chain(game.bullets, game.lasers,
                                       game.cancelled_bullets, game.items,
                                       game.labels))


    def render_interface(self, interface, boss):
        interface_labels = interface.labels
        if 'framerate' in interface_labels:
            interface_labels['framerate'].set_text('%.2ffps' % self.window.get_fps())

        self.window.win.render_set_viewport(Rect(0, 0, interface.width, interface.height))
        self.window.win.render_set_clip_rect(Rect(0, 0, interface.width, interface.height))

        items = [item for item in interface.items if item.anmrunner and item.anmrunner.running]
        labels = interface_labels.values()

        if items:
            # Redraw all the interface
            self.render_elements(items)
        else:
            # Redraw only changed labels
            labels = [label for label in labels if label.changed]

        self.render_elements(interface.level_start)

        if boss:
            self.render_elements(interface.boss_items)

        self.render_elements(labels)
        for label in labels:
            label.changed = False


    def render_elements(self, elements):
        nb_vertices = 0

        objects = chain(*[element.objects for element in elements])
        for element in objects:
            if nb_vertices >= MAX_ELEMENTS - 4:
                break

            sprite = element.sprite
            if sprite and sprite.visible:
                ox, oy = element.x, element.y
                data = get_sprite_rendering_data(sprite)

                #XXX
                texture_width = 256
                texture_height = 256

                source = Rect(data.left * texture_width,
                              data.bottom * texture_height,
                              (data.right - data.left) * texture_width,
                              (data.top - data.bottom) * texture_height)

                dest = Rect(ox + data.x, oy + data.y, data.width, data.height)

                texture = sprite.anm.texture
                texture.set_color_mod(data.r, data.g, data.b)
                texture.set_alpha_mod(data.a)
                texture.set_blend_mode(2 if data.blendfunc else 1)

                if data.rotation or data.flip:
                    self.window.win.render_copy_ex(texture, source, dest, data.rotation, data.flip)
                else:
                    self.window.win.render_copy(texture, source, dest)

                nb_vertices += 4


    def render_text(self, texts):
        if self.font_manager is None:
            return

        self.font_manager.load(texts)

        for label in texts.values():
            texture = label.texture

            source = Rect(0, 0, label.width, label.height)
            rect = Rect(label.x, label.y, label.width, label.height)

            texture.set_alpha_mod(label.alpha)

            if label.shadow:
                shadow_rect = Rect(label.x + 1, label.y + 1, label.width, label.height)
                texture.set_color_mod(0, 0, 0)
                self.window.win.render_copy(label.texture, source, shadow_rect)
                texture.set_color_mod(192, 192, 255)
                self.window.win.render_copy(label.texture, source, rect)
            else:
                texture.set_color_mod(192, 192, 255)
                self.window.win.render_copy(label.texture, source, rect)