Mercurial > touhou
view pytouhou/ui/sdl/gamerenderer.py @ 772:7492d384d122 default tip
Rust: Add a Glide renderer (2D only for now)
This is an experiment for a Rust renderer, iterating over the Python data using
pyo3. It requires --feature=glide to be passed to cargo build, doesn’t support
NPOT textures, text rendering, the background, or even msg faces, some of that
may come in a future changeset.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Mon, 05 Sep 2022 17:53:36 +0200 |
parents | 0ea591b0b29e |
children |
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: 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 False 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)