From 83383f71f70218232ee4032860d0490a2b2f1737 Mon Sep 17 00:00:00 2001 From: LoafyLemon Date: Tue, 10 Sep 2024 14:31:48 +0100 Subject: [PATCH] Implement disk cache for renders --- game/scripts/doll/clothes.rpy | 8 ++++-- game/scripts/doll/clothes_dynamic.rpy | 6 +++- game/scripts/doll/common.rpy | 40 ++++++++++++++++++++++++++- game/scripts/doll/outfits.rpy | 6 +++- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/game/scripts/doll/clothes.rpy b/game/scripts/doll/clothes.rpy index 24403d80..959bf938 100644 --- a/game/scripts/doll/clothes.rpy +++ b/game/scripts/doll/clothes.rpy @@ -176,6 +176,9 @@ init python: @functools.cache def build_icon(self, hash): + if (d := self.get_disk_cache(hash)): + return d + matrix = SaturationMatrix(0.0) sprites = [i for i in self.build_image(hash, matrix=matrix) if not i[0] == "mask"] @@ -205,7 +208,8 @@ init python: if y+h > hmax: y = hmax-h - return Transform(Fixed(*[i[1] for i in sprites], fit_first=True), crop=(x, y, w, h), size=(96, 96), fit="contain", align=(0.5, 0.5)) + d = Transform(Fixed(*[i[1] for i in sprites], fit_first=True), crop=(x, y, w, h), size=(256, 256), fit="contain", align=(0.5, 0.5)) + return self.create_disk_cache(d, hash) @property def icon(self): @@ -269,7 +273,7 @@ init python: foreground = "#b2000040" hover_foreground = "#CD5C5C40" - return Button(child=child, focus_mask=None, xysize=(96, 96), background=self.icon, action=action, tooltip=("\n".join(warnings)), foreground=foreground, hover_foreground=hover_foreground, unhovered=unhovered, style=style) + return Button(child=child, focus_mask=None, xysize=(96, 96), background=Transform(self.icon, xysize=(96, 96)), action=action, tooltip=("\n".join(warnings)), foreground=foreground, hover_foreground=hover_foreground, unhovered=unhovered, style=style) @functools.cache def build_button(self, _=None): diff --git a/game/scripts/doll/clothes_dynamic.rpy b/game/scripts/doll/clothes_dynamic.rpy index 9b800cc4..6ecd49d3 100644 --- a/game/scripts/doll/clothes_dynamic.rpy +++ b/game/scripts/doll/clothes_dynamic.rpy @@ -164,6 +164,9 @@ init python: else: tracking_object = self.tracking_object + if (d := self.get_disk_cache(hash)): + return d + matrix = SaturationMatrix(0.0) sprites = [i for i in self.build_image(hash, matrix=matrix) if not i[0] == "mask"] @@ -192,7 +195,8 @@ init python: if y+h > hmax: y = hmax-h - return Transform(Fixed(*[i[1] for i in sprites], fit_first=True), crop=(x, y, w, h), size=(96, 96), fit="contain", align=(0.5, 0.5)) + d = Transform(Fixed(*[i[1] for i in sprites], fit_first=True), crop=(x, y, w, h), size=(256, 256), fit="contain", align=(0.5, 0.5)) + return self.create_disk_cache(d, hash) def clone(self): """Creates a clone of this cloth object. Since it requires a parent object it should be used internally only to avoid object depth issue.""" diff --git a/game/scripts/doll/common.rpy b/game/scripts/doll/common.rpy index a0bc9b0d..1ad363a5 100644 --- a/game/scripts/doll/common.rpy +++ b/game/scripts/doll/common.rpy @@ -71,10 +71,48 @@ init -1 python: def is_stale(self): curr_hash = self.generate_hash() - stale = curr_hash != self._hash + if (stale := curr_hash != self._hash): + self.remove_disk_cache(self._hash) self._hash = curr_hash return stale + def create_disk_cache(self, d, hash, size=None, type="img"): + width, height = size or self.sizes + filepath = os.path.join("cache", type, f"{hash}.png") + rendpath = os.path.join("game", filepath) + syspath = os.path.join(config.gamedir, "cache", type) + + try: + os.makedirs(syspath, exist_ok=True) + except OSError as e: + print(f"Warning! Failed to create cache directory: {cache_dir} - {e}") + return d + + try: + if not renpy.loadable(filepath): + renpy.render_to_file(d, rendpath, width=width, height=height, resize=True) + return Image(filepath) + except Exception as e: + print(f"Warning! Failed to return cached file: {filepath} - {e}") + return d + + def get_disk_cache(self, hash, type="img"): + filepath = os.path.join("cache", type, f"{hash}.png") + + return Image(filepath) if renpy.loadable(filepath) else None + + def remove_disk_cache(self, hash, type="img"): + syspath = os.path.join(config.gamedir, "cache", type, f"{hash}.png") + + try: + os.unlink(syspath) + except FileNotFoundError: + print(f"Warning! Cached file {syspath} not found") + except PermissionError: + print(f"Warning! Permission denied to remove cached file: {syspath}") + except Exception as e: + print(f"Warning! Failed to remove cached file: {syspath} - {e}") + def DollRebuild(): for i in states.dolls: doll = getattr(store, i) diff --git a/game/scripts/doll/outfits.rpy b/game/scripts/doll/outfits.rpy index 51b28b86..14c45ace 100644 --- a/game/scripts/doll/outfits.rpy +++ b/game/scripts/doll/outfits.rpy @@ -46,6 +46,9 @@ init python: @functools.cache def build_image(self, hash): + if (d := self.get_disk_cache(hash)): + return d + from itertools import chain matrix = SaturationMatrix(0.0) @@ -79,7 +82,8 @@ init python: sprites = back_sprites + [x[1] for x in sprites] - return Fixed(*sprites, fit_first=True) + d = Fixed(*sprites, fit_first=True) + return self.create_disk_cache(d, hash) @property def image(self):