Skip to content

Commit

Permalink
Added animated gif functionality and basic but rubbish city stage
Browse files Browse the repository at this point in the history
  • Loading branch information
jinglemansweep committed Jan 30, 2024
1 parent 6f8aaee commit e1a0c5b
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 7 deletions.
Binary file added images/sprites/misc/gif_cyberpunk.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions wideboy/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,8 @@ class WidgetVinyl(ComFrame, ComFade, ComMotion, ComAlpha, ComVisible):
@entity
class WidgetGalaxy(ComFrame, ComFade, ComMotion, ComAlpha, ComVisible):
pass


@entity
class WidgetAnimatedGif(ComFrame, ComFade, ComMotion, ComAlpha, ComVisible):
pass
24 changes: 22 additions & 2 deletions wideboy/sprites/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,28 @@ def load_image(filename: str, convert_alpha: bool = True) -> Surface:
return image


def pil_to_surface(image: Image.Image) -> Surface:
return pygame.image.fromstring(image.tobytes(), image.size, image.mode).convert_alpha() # type: ignore
def load_gif(filename: str, convert_alpha: bool = True) -> list[Surface]:
gif_image = Image.open(filename)
frames = []
try:
while True:
gif_image.seek(gif_image.tell() + 1)
gif_frame = gif_image.copy()
if gif_frame:
frame = pil_to_surface(gif_frame, convert_alpha)
frames.append(frame)
except EOFError:
pass
return frames


def pil_to_surface(image: Image.Image, convert_alpha: bool = True) -> Surface:
if image.mode not in ["RGB", "RGBA"]:
image = image.convert("RGBA")
surface = pygame.image.fromstring(image.tobytes(), image.size, "RGBA")
if convert_alpha:
surface = surface.convert_alpha() # type: ignore
return surface


def surface_to_pil(surface: Surface) -> Image.Image:
Expand Down
18 changes: 17 additions & 1 deletion wideboy/systems/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pygame.display import Info as DisplayInfo
from typing import Callable, Generator, List, Tuple
from ..entities import AppState, Cache, WidgetSysMessage
from ..sprites.graphics import load_image
from ..sprites.graphics import load_image, load_gif
from .scene.sprites import build_mode7_sprite, build_system_message_sprite

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -38,6 +38,14 @@ def preprocess_load_image(cache: Cache, key: str, path: str):
cache.surfaces[key].append(load_image(path))


def preprocess_load_gif(cache: Cache, key: str, path: str):
logger.debug(f"preprocess_load_gif: key={key} path={path}")
if key not in cache.surfaces:
cache.surfaces[key] = []
surfaces = load_gif(path)
cache.surfaces[key] = surfaces


def preprocess_text(cache: Cache, key: str, text: str):
logger.debug(f"preprocess_text: key={key} text={text}")
sprite = build_system_message_sprite(text)
Expand Down Expand Up @@ -139,6 +147,7 @@ def tasks(self) -> Generator:
0.8,
)
yield f"Vinyl #1 [{r/360*100:.0f}%]"
# Mode7 Milky Way
surface = load_image(
f"{self.app_state.config.paths.images_sprites}/misc/milky_way.png"
)
Expand All @@ -156,3 +165,10 @@ def tasks(self) -> Generator:
0.6,
)
yield f"Milky Way [{r/360*100:.0f}%]"
# Animated GIF Test
preprocess_load_gif(
self.cache,
"gif_test",
f"{self.app_state.config.paths.images_sprites}/misc/gif_cyberpunk.gif",
)
yield "Animated GIF Test"
16 changes: 13 additions & 3 deletions wideboy/systems/scene/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .entity_tiles import CELLS
from .stages import Stage
from .stages.boot import StageBoot
from .stages.city import StageCity
from .stages.default import StageDefault
from .stages.galaxy import StageGalaxy
from .stages.vinyl import StageVinyl
Expand Down Expand Up @@ -157,7 +158,7 @@ def _handle_scene_mode_change(self) -> None:
)
)
else:
# Galaxy Mode
# Galaxy Stage
if self.scene_mode == "galaxy":
logger.info("GALAXY MODE")
self._switch_stage(
Expand All @@ -166,7 +167,7 @@ def _handle_scene_mode_change(self) -> None:
(self.display_info.current_w, self.display_info.current_h),
)
)
# Vinyl Mode
# Vinyl Stage
elif self.scene_mode == "vinyl":
logger.info("VINYL MODE")
self._switch_stage(
Expand All @@ -175,7 +176,16 @@ def _handle_scene_mode_change(self) -> None:
(self.display_info.current_w, self.display_info.current_h),
)
)
# Default Mode
# City Stage
elif self.scene_mode == "city":
logger.info("CITY MODE")
self._switch_stage(
StageCity(
self.entities,
(self.display_info.current_w, self.display_info.current_h),
)
)
# Default Stage
else:
logger.info("DEFAULT MODE")
self._switch_stage(
Expand Down
2 changes: 1 addition & 1 deletion wideboy/systems/scene/hass_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ModeSelect(SelectEntity):
description: str = "Mode"
initial_state: str = "default"
options: Dict[str, Any] = {
"options": ["default", "galaxy", "vinyl"],
"options": ["city", "default", "galaxy", "vinyl"],
}

def callback(
Expand Down
47 changes: 47 additions & 0 deletions wideboy/systems/scene/stages/city.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import logging
from ecs_pattern import EntityManager
from typing import Tuple
from ....entities import (
Cache,
WidgetAnimatedGif,
WidgetClockDate,
WidgetClockTime,
WidgetTileGrid,
)
from ..sprites import build_image_sprite
from . import Stage

logger = logging.getLogger(__name__)


class StageCity(Stage):
def __init__(
self,
entities: EntityManager,
display_size: Tuple[int, int],
) -> None:
super().__init__(entities)
self.display_size = display_size
self.setup()

def setup(self) -> None:
self.cache = next(self.entities.get_by_class(Cache))

for i in range(3):
self.stage_entities.append(
WidgetAnimatedGif(
build_image_sprite(self.cache.surfaces["gif_test"][0]),
x=i * 300,
y=-20,
z_order=5,
frames=self.cache.surfaces["gif_test"],
frame_delay=1,
), # type: ignore[call-arg]
)

for w in self.entities.get_by_class(
WidgetClockDate,
WidgetClockTime,
WidgetTileGrid,
):
w.fade_target_alpha = 255

0 comments on commit e1a0c5b

Please sign in to comment.