add custom box color support

This commit is contained in:
Anthony Samms
2025-12-20 12:39:13 -05:00
parent ed8b8fb185
commit 3f9a1e3a4c
6 changed files with 288 additions and 164 deletions

View File

@@ -1,3 +1,4 @@
#TITLE:Recommended #TITLE:Recommended
#TITLEJA: #TITLEJA:
#COLLECTION:RECOMMENDED #COLLECTION:RECOMMENDED
#FORECOLOR:#8c275c

View File

@@ -1,3 +1,4 @@
#TITLE:Favorites #TITLE:Favorites
#TITLEJA: #TITLEJA:
#COLLECTION:FAVORITE #COLLECTION:FAVORITE
#FORECOLOR:#97391e

View File

@@ -1,3 +1,4 @@
#TITLE:Recently Played #TITLE:Recently Played
#TITLEJA: #TITLEJA:
#COLLECTION:RECENT #COLLECTION:RECENT
#FORECOLOR:#237b67

View File

@@ -1,3 +1,5 @@
#TITLE:Diff Sort #TITLE:Diff Sort
#TITLEJA: #TITLEJA:
#COLLECTION:DIFFICULTY #COLLECTION:DIFFICULTY
#BACKCOLOR:#ff555f
#FORECOLOR:#9d0d1f

View File

@@ -1,11 +1,12 @@
from dataclasses import dataclass from dataclasses import dataclass
from enum import IntEnum
import json import json
import logging import logging
from pathlib import Path from pathlib import Path
import random import random
from typing import Optional, Union from typing import Optional, Union
from raylib import SHADER_UNIFORM_FLOAT, SHADER_UNIFORM_VEC3 from raylib import SHADER_UNIFORM_VEC3
from libs.audio import audio from libs.audio import audio
from libs.animation import Animation, MoveAnimation from libs.animation import Animation, MoveAnimation
from libs.global_data import Crown, Difficulty from libs.global_data import Crown, Difficulty
@@ -51,7 +52,6 @@ def calculate_hue_shift(source_rgb, target_rgb):
shift = (target_hue - source_hue) / 360.0 shift = (target_hue - source_hue) / 360.0
# Normalize to 0.0-1.0 range
while shift < 0: while shift < 0:
shift += 1.0 shift += 1.0
while shift >= 1.0: while shift >= 1.0:
@@ -59,68 +59,78 @@ def calculate_hue_shift(source_rgb, target_rgb):
return shift return shift
def darken_color(rgb: tuple[int, int, int]):
r, g, b = rgb
darkening_factor = 0.63
darkened_r = int(r * darkening_factor)
darkened_g = int(g * darkening_factor)
darkened_b = int(b * darkening_factor)
return (darkened_r, darkened_g, darkened_b)
class TextureIndex(IntEnum):
BLANK = 0
VOCALOID = 1
DEFAULT = 2
RECOMMENDED = 3
FAVORITE = 4
RECENT = 5
class GenreIndex(IntEnum):
TUTORIAL = 0
JPOP = 1
ANIME = 2
VOCALOID = 3
CHILDREN = 4
VARIETY = 5
CLASSICAL = 6
GAME = 7
NAMCO = 8
DEFAULT = 9
RECOMMENDED = 10
FAVORITE = 11
RECENT = 12
DAN = 13
DIFFICULTY = 14
class BaseBox(): class BaseBox():
OUTLINE_MAP = {
1: ray.Color(0, 77, 104, 255),
2: ray.Color(156, 64, 2, 255),
3: ray.Color(84, 101, 126, 255),
4: ray.Color(153, 4, 46, 255),
5: ray.Color(60, 104, 0, 255),
6: ray.Color(134, 88, 0, 255),
7: ray.Color(79, 40, 134, 255),
8: ray.Color(148, 24, 0, 255),
9: ray.Color(101, 0, 82, 255),
10: ray.Color(140, 39, 92, 255),
11: ray.Color(151, 57, 30, 255),
12: ray.Color(35, 123, 103, 255),
13: ray.Color(25, 68, 137, 255),
14: ray.Color(157, 13, 31, 255)
}
BACK_INDEX = 17
DEFAULT_INDEX = 9
DIFFICULTY_SORT_INDEX = 14
"""Base class for all box types in the song select screen.""" """Base class for all box types in the song select screen."""
def __init__(self, name: str, texture_index: int): def __init__(self, name: str, back_color: Optional[tuple[int, int, int]], fore_color: Optional[tuple[int, int, int]], texture_index: TextureIndex):
self.text_name = name self.text_name = name
self.texture_index = texture_index self.texture_index = texture_index
self.genre_index = GenreIndex.DEFAULT
self.back_color = back_color
if fore_color is not None:
self.fore_color = ray.Color(fore_color[0], fore_color[1], fore_color[2], 255)
elif self.back_color is not None:
dark_ver = darken_color(self.back_color)
self.fore_color = ray.Color(dark_ver[0], dark_ver[1], dark_ver[2], 255)
else:
self.fore_color = ray.Color(101, 0, 82, 255)
self.position = float('inf') self.position = float('inf')
self.start_position: float = -1 self.start_position = -1.0
self.target_position: float = -1 self.target_position = -1.0
self.open_anim = Animation.create_move(233, total_distance=150*tex.screen_scale, delay=50) self.open_anim = Animation.create_move(233, total_distance=150*tex.screen_scale, delay=50)
self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0) self.open_fade = Animation.create_fade(200, initial_opacity=0, final_opacity=1.0)
self.move = None self.move = None
self.shader = None
self.is_open = False self.is_open = False
self.text_loaded = False self.text_loaded = False
self.wait = 0 self.wait = 0
def __lt__(self, other):
return self.position < other.position
def __le__(self, other):
return self.position <= other.position
def __gt__(self, other):
return self.position > other.position
def __ge__(self, other):
return self.position >= other.position
def __eq__(self, other):
return self.position == other.position
def load_text(self): def load_text(self):
self.name = OutlinedText(self.text_name, tex.skin_config["song_box_name"].font_size, ray.WHITE, outline_thickness=5, vertical=True) self.name = OutlinedText(self.text_name, tex.skin_config["song_box_name"].font_size, ray.WHITE, outline_thickness=5, vertical=True)
''' if self.back_color is not None:
self.shader = ray.load_shader('', 'shader/colortransform.fs') self.shader = ray.load_shader('', 'shader/colortransform.fs')
source_rgb = (142, 212, 30) source_rgb = (142, 212, 30)
target_rgb = (209, 162, 19) target_rgb = self.back_color
source_color = ray.ffi.new('float[3]', [source_rgb[0]/255.0, source_rgb[1]/255.0, source_rgb[2]/255.0]) source_color = ray.ffi.new('float[3]', [source_rgb[0]/255.0, source_rgb[1]/255.0, source_rgb[2]/255.0])
target_color = ray.ffi.new('float[3]', [target_rgb[0]/255.0, target_rgb[1]/255.0, target_rgb[2]/255.0]) target_color = ray.ffi.new('float[3]', [target_rgb[0]/255.0, target_rgb[1]/255.0, target_rgb[2]/255.0])
source_loc = ray.get_shader_location(self.shader, 'sourceColor') source_loc = ray.get_shader_location(self.shader, 'sourceColor')
target_loc = ray.get_shader_location(self.shader, 'targetColor') target_loc = ray.get_shader_location(self.shader, 'targetColor')
ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3) ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3)
ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3) ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3)
'''
def move_box(self, current_time: float): def move_box(self, current_time: float):
if self.position != self.target_position and self.move is None: if self.position != self.target_position and self.move is None:
@@ -148,15 +158,16 @@ class BaseBox():
self.open_fade.update(current_time) self.open_fade.update(current_time)
def _draw_closed(self, x: float, y: float, outer_fade_override: float): def _draw_closed(self, x: float, y: float, outer_fade_override: float):
#ray.begin_shader_mode(self.shader) if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.begin_shader_mode(self.shader)
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x, fade=outer_fade_override) tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x, fade=outer_fade_override)
offset = 1 * tex.screen_scale if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0 tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x, x2=tex.skin_config["song_box_bg"].width, fade=outer_fade_override)
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x, x2=tex.skin_config["song_box_bg"].width, y=offset, fade=outer_fade_override)
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x, fade=outer_fade_override) tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x, fade=outer_fade_override)
#ray.end_shader_mode() if self.shader is not None and self.texture_index == TextureIndex.BLANK:
if self.texture_index == BaseBox.DEFAULT_INDEX: ray.end_shader_mode()
if self.texture_index == TextureIndex.DEFAULT:
tex.draw_texture('box', 'genre_overlay', x=x, y=y, fade=outer_fade_override) tex.draw_texture('box', 'genre_overlay', x=x, y=y, fade=outer_fade_override)
elif self.texture_index == BaseBox.DIFFICULTY_SORT_INDEX: if self.genre_index == GenreIndex.DIFFICULTY:
tex.draw_texture('box', 'diff_overlay', x=x, y=y, fade=outer_fade_override) tex.draw_texture('box', 'diff_overlay', x=x, y=y, fade=outer_fade_override)
def _draw_open(self, x: float, y: float, fade_override: Optional[float], is_ura: bool): def _draw_open(self, x: float, y: float, fade_override: Optional[float], is_ura: bool):
@@ -169,8 +180,9 @@ class BaseBox():
self._draw_closed(x, y, outer_fade_override) self._draw_closed(x, y, outer_fade_override)
class BackBox(BaseBox): class BackBox(BaseBox):
def __init__(self, name: str, texture_index: int): COLOR = (170, 115, 35)
super().__init__(name, texture_index) def __init__(self, name: str):
super().__init__(name, BackBox.COLOR, BackBox.COLOR, TextureIndex.BLANK)
self.yellow_box = None self.yellow_box = None
def load_text(self): def load_text(self):
@@ -200,12 +212,8 @@ class BackBox(BaseBox):
self.yellow_box.draw(self, fade_override, is_ura, self.name) self.yellow_box.draw(self, fade_override, is_ura, self.name)
class SongBox(BaseBox): class SongBox(BaseBox):
def __init__(self, name: str, texture_index: int, tja: TJAParser, name_texture_index: Optional[int] = None): def __init__(self, name: str, back_color: Optional[tuple[int, int, int]], fore_color: Optional[tuple[int, int, int]], texture_index: TextureIndex, tja: TJAParser):
super().__init__(name, texture_index) super().__init__(name, back_color, fore_color, texture_index)
if name_texture_index is None:
self.name_texture_index = texture_index
else:
self.name_texture_index = name_texture_index
self.scores = dict() self.scores = dict()
self.hash = dict() self.hash = dict()
self.score_history = None self.score_history = None
@@ -270,7 +278,7 @@ class SongBox(BaseBox):
def _draw_closed(self, x: float, y: float, outer_fade_override: float): def _draw_closed(self, x: float, y: float, outer_fade_override: float):
super()._draw_closed(x, y, outer_fade_override) super()._draw_closed(x, y, outer_fade_override)
self.name.draw(outline_color=SongBox.OUTLINE_MAP.get(self.name_texture_index, ray.Color(101, 0, 82, 255)), x=x + tex.skin_config["song_box_name"].x - int(self.name.texture.width / 2), y=y+tex.skin_config["song_box_name"].y, y2=min(self.name.texture.height, tex.skin_config["song_box_name"].height)-self.name.texture.height, fade=outer_fade_override) self.name.draw(outline_color=self.fore_color, x=x + tex.skin_config["song_box_name"].x - int(self.name.texture.width / 2), y=y+tex.skin_config["song_box_name"].y, y2=min(self.name.texture.height, tex.skin_config["song_box_name"].height)-self.name.texture.height, fade=outer_fade_override)
if self.tja.ex_data.new: if self.tja.ex_data.new:
tex.draw_texture('yellow_box', 'ex_data_new_song_balloon', x=x, y=y, fade=outer_fade_override) tex.draw_texture('yellow_box', 'ex_data_new_song_balloon', x=x, y=y, fade=outer_fade_override)
@@ -295,13 +303,13 @@ class SongBox(BaseBox):
self.score_history.draw() self.score_history.draw()
class FolderBox(BaseBox): class FolderBox(BaseBox):
def __init__(self, name: str, texture_index: int, tja_count: int = 0, def __init__(self, name: str, back_color: Optional[tuple[int, int, int]], fore_color: Optional[tuple[int, int, int]], texture_index: TextureIndex, genre_index: GenreIndex, tja_count: int = 0, box_texture: Optional[str] = None):
box_texture: Optional[str] = None): super().__init__(name, back_color, fore_color, texture_index)
super().__init__(name, texture_index)
self.box_texture_path = Path(box_texture) if box_texture else None self.box_texture_path = Path(box_texture) if box_texture else None
self.is_back = self.texture_index == SongBox.BACK_INDEX self.is_back = self.back_color == BackBox.COLOR
self.tja_count = tja_count self.tja_count = tja_count
self.crown = dict() self.crown = dict()
self.genre_index = genre_index
def load_text(self): def load_text(self):
super().load_text() super().load_text()
@@ -323,17 +331,20 @@ class FolderBox(BaseBox):
self.open_anim.start() self.open_anim.start()
self.open_fade.start() self.open_fade.start()
self.wait = current_time self.wait = current_time
if self.texture_index != SongBox.BACK_INDEX and not audio.is_sound_playing('voice_enter'): if self.back_color != BackBox.COLOR and not audio.is_sound_playing('voice_enter'):
audio.play_sound(f'genre_voice_{self.texture_index}', 'voice') audio.play_sound(f'genre_voice_{self.genre_index}', 'voice')
elif not self.is_open and is_open_prev and self.texture_index != 17 and audio.is_sound_playing(f'genre_voice_{self.texture_index}'): elif not self.is_open and is_open_prev and self.back_color != BackBox.COLOR and audio.is_sound_playing(f'genre_voice_{self.genre_index}'):
audio.stop_sound(f'genre_voice_{self.texture_index}') audio.stop_sound(f'genre_voice_{self.genre_index}')
def _draw_closed(self, x: float, y: float, outer_fade_override: float): def _draw_closed(self, x: float, y: float, outer_fade_override: float):
super()._draw_closed(x, y, outer_fade_override) super()._draw_closed(x, y, outer_fade_override)
offset = 1 * tex.screen_scale if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0 if self.shader is not None and self.texture_index == TextureIndex.BLANK:
tex.draw_texture('box', 'folder_clip', frame=self.texture_index, x=x - ((1 * tex.screen_scale) - offset), y=y, fade=outer_fade_override) ray.begin_shader_mode(self.shader)
tex.draw_texture('box', 'folder_clip', frame=self.texture_index, x=x - ((1 * tex.screen_scale)), y=y, fade=outer_fade_override)
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.end_shader_mode()
self.name.draw(outline_color=SongBox.OUTLINE_MAP.get(self.texture_index, ray.Color(101, 0, 82, 255)), x=x + tex.skin_config["song_box_name"].x - int(self.name.texture.width / 2), y=y+tex.skin_config["song_box_name"].y, y2=min(self.name.texture.height, tex.skin_config["song_box_name"].height)-self.name.texture.height, fade=outer_fade_override) self.name.draw(outline_color=self.fore_color, x=x + tex.skin_config["song_box_name"].x - int(self.name.texture.width / 2), y=y+tex.skin_config["song_box_name"].y, y2=min(self.name.texture.height, tex.skin_config["song_box_name"].height)-self.name.texture.height, fade=outer_fade_override)
if self.crown: #Folder lamp if self.crown: #Folder lamp
highest_crown = max(self.crown) highest_crown = max(self.crown)
@@ -349,34 +360,42 @@ class FolderBox(BaseBox):
if fade_override is not None: if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override) color = ray.fade(ray.WHITE, fade_override)
if not self.is_back and self.open_anim.attribute >= (100 * tex.screen_scale): if not self.is_back and self.open_anim.attribute >= (100 * tex.screen_scale):
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.begin_shader_mode(self.shader)
tex.draw_texture('box', 'folder_top_edge', x=x, y=y - self.open_anim.attribute, color=color, mirror='horizontal', frame=self.texture_index) tex.draw_texture('box', 'folder_top_edge', x=x, y=y - self.open_anim.attribute, color=color, mirror='horizontal', frame=self.texture_index)
tex.draw_texture('box', 'folder_top', x=x, y=y - self.open_anim.attribute, color=color, frame=self.texture_index) tex.draw_texture('box', 'folder_top', x=x, y=y - self.open_anim.attribute, color=color, frame=self.texture_index)
tex.draw_texture('box', 'folder_top_edge', x=x+tex.skin_config["song_folder_top"].x, y=y - self.open_anim.attribute, color=color, frame=self.texture_index) tex.draw_texture('box', 'folder_top_edge', x=x+tex.skin_config["song_folder_top"].x, y=y - self.open_anim.attribute, color=color, frame=self.texture_index)
dest_width = min(tex.skin_config["song_hori_name"].width, self.hori_name.texture.width) dest_width = min(tex.skin_config["song_hori_name"].width, self.hori_name.texture.width)
self.hori_name.draw(outline_color=ray.BLACK, x=(x + tex.skin_config["song_hori_name"].x) - (dest_width//2), y=y + tex.skin_config["song_hori_name"].y - self.open_anim.attribute, x2=dest_width-self.hori_name.texture.width, color=color) self.hori_name.draw(outline_color=ray.BLACK, x=(x + tex.skin_config["song_hori_name"].x) - (dest_width//2), y=y + tex.skin_config["song_hori_name"].y - self.open_anim.attribute, x2=dest_width-self.hori_name.texture.width, color=color)
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.end_shader_mode()
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.begin_shader_mode(self.shader)
tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x - self.open_anim.attribute) tex.draw_texture('box', 'folder_texture_left', frame=self.texture_index, x=x - self.open_anim.attribute)
offset = 1 * tex.screen_scale if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0 offset = 1 * tex.screen_scale if self.texture_index == 3 or self.texture_index >= 9 and self.texture_index not in {10,11,12} else 0
tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x - self.open_anim.attribute, y=offset, x2=(self.open_anim.attribute*2)+tex.skin_config["song_box_bg"].width) tex.draw_texture('box', 'folder_texture', frame=self.texture_index, x=x - self.open_anim.attribute, y=offset, x2=(self.open_anim.attribute*2)+tex.skin_config["song_box_bg"].width)
tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x + self.open_anim.attribute) tex.draw_texture('box', 'folder_texture_right', frame=self.texture_index, x=x + self.open_anim.attribute)
if self.shader is not None and self.texture_index == TextureIndex.BLANK:
ray.end_shader_mode()
if self.texture_index == BaseBox.DEFAULT_INDEX: if self.texture_index == TextureIndex.DEFAULT:
tex.draw_texture('box', 'genre_overlay_large', x=x, y=y, color=color) tex.draw_texture('box', 'genre_overlay_large', x=x, y=y, color=color)
elif self.texture_index == BaseBox.DIFFICULTY_SORT_INDEX: if self.genre_index == GenreIndex.DIFFICULTY:
tex.draw_texture('box', 'diff_overlay_large', x=x, y=y, color=color) tex.draw_texture('box', 'diff_overlay_large', x=x, y=y, color=color)
color = ray.WHITE color = ray.WHITE
if fade_override is not None: if fade_override is not None:
color = ray.fade(ray.WHITE, fade_override) color = ray.fade(ray.WHITE, fade_override)
if self.texture_index != BaseBox.DIFFICULTY_SORT_INDEX: if self.genre_index != GenreIndex.DIFFICULTY:
tex.draw_texture('yellow_box', 'song_count_back', color=color, fade=0.5) tex.draw_texture('yellow_box', 'song_count_back', color=color, fade=0.5)
tex.draw_texture('yellow_box', 'song_count_num', color=color) tex.draw_texture('yellow_box', 'song_count_num', color=color)
tex.draw_texture('yellow_box', 'song_count_songs', color=color) tex.draw_texture('yellow_box', 'song_count_songs', color=color)
dest_width = min(tex.skin_config["song_tja_count"].width, self.tja_count_text.texture.width) dest_width = min(tex.skin_config["song_tja_count"].width, self.tja_count_text.texture.width)
self.tja_count_text.draw(outline_color=ray.BLACK, x=tex.skin_config["song_tja_count"].x - (dest_width//2), y=tex.skin_config["song_tja_count"].y, x2=dest_width-self.tja_count_text.texture.width, color=color) self.tja_count_text.draw(outline_color=ray.BLACK, x=tex.skin_config["song_tja_count"].x - (dest_width//2), y=tex.skin_config["song_tja_count"].y, x2=dest_width-self.tja_count_text.texture.width, color=color)
if self.texture_index != SongBox.DEFAULT_INDEX: if self.texture_index != TextureIndex.DEFAULT:
tex.draw_texture('box', 'folder_graphic', color=color, frame=self.texture_index) tex.draw_texture('box', 'folder_graphic', color=color, frame=self.genre_index)
tex.draw_texture('box', 'folder_text', color=color, frame=self.texture_index) tex.draw_texture('box', 'folder_text', color=color, frame=self.genre_index)
elif self.box_texture is not None: elif self.box_texture is not None:
scaled_width = self.box_texture.width * tex.screen_scale scaled_width = self.box_texture.width * tex.screen_scale
scaled_height = self.box_texture.height * tex.screen_scale scaled_height = self.box_texture.height * tex.screen_scale
@@ -600,8 +619,8 @@ class YellowBox:
self._draw_text(song_box, name) self._draw_text(song_box, name)
class DanBox(BaseBox): class DanBox(BaseBox):
def __init__(self, name, color: int, songs: list[tuple[TJAParser, int, int, int]], exams: list['Exam']): def __init__(self, name, color: TextureIndex, songs: list[tuple[TJAParser, int, int, int]], exams: list['Exam']):
super().__init__(name, color) super().__init__(name, None, None, color)
self.songs = songs self.songs = songs
self.exams = exams self.exams = exams
self.song_text: list[tuple[OutlinedText, OutlinedText]] = [] self.song_text: list[tuple[OutlinedText, OutlinedText]] = []
@@ -718,29 +737,48 @@ class DanBox(BaseBox):
class GenreBG: class GenreBG:
"""The background for a genre box.""" """The background for a genre box."""
def __init__(self, start_box: BaseBox, end_box: BaseBox, title: OutlinedText, diff_sort: Optional[int]): def __init__(self, start_box: BaseBox, end_box: BaseBox, title: OutlinedText, diff_sort: Optional[int]):
self.title = title
self.start_box = start_box self.start_box = start_box
self.end_box = end_box self.end_box = end_box
self.start_position = start_box.position self.start_position = start_box.position
self.end_position_final = end_box.position self.end_position_final = end_box.position
self.title = title
self.fade_in = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, ease_in='quadratic', delay=50) self.fade_in = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, ease_in='quadratic', delay=50)
self.fade_in.start()
self.move = Animation.create_move(316, delay=self.fade_in.duration/2, total_distance=abs(self.end_position_final - self.start_position), ease_in='quadratic') self.move = Animation.create_move(316, delay=self.fade_in.duration/2, total_distance=abs(self.end_position_final - self.start_position), ease_in='quadratic')
self.move.start()
self.box_fade_in = Animation.create_fade(66.67*2, delay=self.move.duration, initial_opacity=0.0, final_opacity=1.0) self.box_fade_in = Animation.create_fade(66.67*2, delay=self.move.duration, initial_opacity=0.0, final_opacity=1.0)
self.fade_in.start()
self.move.start()
self.box_fade_in.start() self.box_fade_in.start()
self.end_position = self.start_position + self.move.attribute self.end_position = self.start_position + self.move.attribute
self.diff_num = diff_sort self.diff_num = diff_sort
self.color = self.end_box.back_color
self.shader = None
self.shader_loaded = False
def load_shader(self):
if self.color is not None:
self.shader = ray.load_shader('', 'shader/colortransform.fs')
source_rgb = (142, 212, 30)
target_rgb = self.color
source_color = ray.ffi.new('float[3]', [source_rgb[0]/255.0, source_rgb[1]/255.0, source_rgb[2]/255.0])
target_color = ray.ffi.new('float[3]', [target_rgb[0]/255.0, target_rgb[1]/255.0, target_rgb[2]/255.0])
source_loc = ray.get_shader_location(self.shader, 'sourceColor')
target_loc = ray.get_shader_location(self.shader, 'targetColor')
ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3)
ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3)
self.shader_loaded = True
def update(self, current_ms): def update(self, current_ms):
self.start_position = self.start_box.position self.start_position = self.start_box.position
#self.end_position_final = self.end_box.position
self.end_position = self.start_position + self.move.attribute self.end_position = self.start_position + self.move.attribute
if self.move.is_finished: if self.move.is_finished:
self.end_position = self.end_box.position self.end_position = self.end_box.position
self.box_fade_in.update(current_ms) self.box_fade_in.update(current_ms)
self.fade_in.update(current_ms) self.fade_in.update(current_ms)
self.move.update(current_ms) self.move.update(current_ms)
def draw(self, y): def draw(self, y):
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
ray.begin_shader_mode(self.shader)
offset = (tex.skin_config["genre_bg_offset"].x * -1) if self.start_box.is_open else 0 offset = (tex.skin_config["genre_bg_offset"].x * -1) if self.start_box.is_open else 0
tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", fade=self.fade_in.attribute) tex.draw_texture('box', 'folder_background_edge', frame=self.end_box.texture_index, x=self.start_position+offset, y=y, mirror="horizontal", fade=self.fade_in.attribute)
@@ -767,13 +805,19 @@ class GenreBG:
offset = tex.skin_config["genre_bg_offset"].x if self.end_box.is_open else 0 offset = tex.skin_config["genre_bg_offset"].x if self.end_box.is_open else 0
tex.draw_texture('box', 'folder_background_edge', x=self.end_position+tex.skin_config["genre_bg_folder_edge"].x+offset, y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_background_edge', x=self.end_position+tex.skin_config["genre_bg_folder_edge"].x+offset, y=y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
ray.end_shader_mode()
if ((self.start_position <= BOX_CENTER and self.end_position >= BOX_CENTER) or if ((self.start_position <= BOX_CENTER and self.end_position >= BOX_CENTER) or
((self.start_position <= BOX_CENTER or self.end_position >= BOX_CENTER) and (self.start_position > self.end_position))): ((self.start_position <= BOX_CENTER or self.end_position >= BOX_CENTER) and (self.start_position > self.end_position))):
offset = tex.skin_config["genre_bg_offset_3"].x if self.diff_num is not None else 0 offset = tex.skin_config["genre_bg_offset_3"].x if self.diff_num is not None else 0
dest_width = min(tex.skin_config["genre_bg_title"].width, self.title.texture.width) dest_width = min(tex.skin_config["genre_bg_title"].width, self.title.texture.width)
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
ray.begin_shader_mode(self.shader)
tex.draw_texture('box', 'folder_background_folder', x=-((offset+dest_width)//2), y=y+tex.skin_config["genre_bg_folder_background_folder"].y, x2=dest_width+offset++tex.skin_config["genre_bg_folder_background_folder"].width, fade=self.fade_in.attribute, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_background_folder', x=-((offset+dest_width)//2), y=y+tex.skin_config["genre_bg_folder_background_folder"].y, x2=dest_width+offset++tex.skin_config["genre_bg_folder_background_folder"].width, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
tex.draw_texture('box', 'folder_background_folder_edge', x=-((offset+dest_width)//2), y=y+tex.skin_config["genre_bg_folder_background_folder"].y, fade=self.fade_in.attribute, frame=self.end_box.texture_index, mirror="horizontal") tex.draw_texture('box', 'folder_background_folder_edge', x=-((offset+dest_width)//2), y=y+tex.skin_config["genre_bg_folder_background_folder"].y, fade=self.fade_in.attribute, frame=self.end_box.texture_index, mirror="horizontal")
tex.draw_texture('box', 'folder_background_folder_edge', x=((offset+dest_width)//2)+tex.skin_config["genre_bg_folder_background_folder"].x, y=y+tex.skin_config["genre_bg_folder_background_folder"].y, fade=self.fade_in.attribute, frame=self.end_box.texture_index) tex.draw_texture('box', 'folder_background_folder_edge', x=((offset+dest_width)//2)+tex.skin_config["genre_bg_folder_background_folder"].x, y=y+tex.skin_config["genre_bg_folder_background_folder"].y, fade=self.fade_in.attribute, frame=self.end_box.texture_index)
if self.shader is not None and self.end_box.texture_index == TextureIndex.BLANK:
ray.end_shader_mode()
if self.diff_num is not None: if self.diff_num is not None:
tex.draw_texture('diff_sort', 'star_num', frame=self.diff_num, x=(tex.skin_config["genre_bg_offset"].x * -1) + (dest_width//2), y=tex.skin_config["diff_sort_star_num"].y) tex.draw_texture('diff_sort', 'star_num', frame=self.diff_num, x=(tex.skin_config["genre_bg_offset"].x * -1) + (dest_width//2), y=tex.skin_config["diff_sort_star_num"].y)
self.title.draw(outline_color=ray.BLACK, x=(tex.screen_width//2) - (dest_width//2)-(offset//2), y=y+tex.skin_config["genre_bg_title"].y, x2=dest_width - self.title.texture.width, color=ray.fade(ray.WHITE, self.fade_in.attribute)) self.title.draw(outline_color=ray.BLACK, x=(tex.screen_width//2) - (dest_width//2)-(offset//2), y=y+tex.skin_config["genre_bg_title"].y, x2=dest_width - self.title.texture.width, color=ray.fade(ray.WHITE, self.fade_in.attribute))
@@ -872,59 +916,108 @@ class ScoreHistory:
for i in range(len(counter)): for i in range(len(counter)):
tex.draw_texture('leaderboard', 'counter', frame=int(counter[i]), x=-(total_width // 2) + (i * tex.skin_config["score_info_counter_margin"].width), y=tex.skin_config["score_info_bg_offset"].y, color=ray.WHITE) tex.draw_texture('leaderboard', 'counter', frame=int(counter[i]), x=-(total_width // 2) + (i * tex.skin_config["score_info_counter_margin"].width), y=tex.skin_config["score_info_bg_offset"].y, color=ray.WHITE)
def parse_hex_color(color) -> tuple[int, int, int]:
"""Parse hex color to RGB tuple"""
color = color.lstrip('#')
if len(color) == 3:
color = ''.join([c*2 for c in color])
res = tuple(int(color[i:i+2], 16) for i in (0, 2, 4))
return (res[0], res[1], res[2])
def get_genre_index(genre_string: str) -> GenreIndex:
genre_upper = genre_string.upper()
for genre_index, genre_set in FileSystemItem.GENRE_MAP.items():
if genre_upper in genre_set:
return genre_index
return GenreIndex.DEFAULT
DEFAULT_COLORS = {
GenreIndex.JPOP: [(32, 160, 186), (0, 77, 104)],
GenreIndex.ANIME: [(255, 152, 0), (156, 64, 2)],
GenreIndex.VOCALOID: [None, (84, 101, 126)],
GenreIndex.CHILDREN: [(255, 82, 134), (153, 4, 46)],
GenreIndex.VARIETY: [(142, 212, 30), (60, 104, 0)],
GenreIndex.CLASSICAL: [(209, 162, 19), (134, 88, 0)],
GenreIndex.GAME: [(156, 117, 189), (79, 40, 134)],
GenreIndex.NAMCO: [(255, 90, 19), (148, 24, 0)],
GenreIndex.DEFAULT: [None, (101, 0, 82)],
GenreIndex.RECOMMENDED: [None, (140, 39, 92)],
GenreIndex.FAVORITE: [None, (151, 57, 30)],
GenreIndex.RECENT: [None, (35, 123, 103)],
GenreIndex.DAN: [(35, 102, 170), (25, 68, 137)],
GenreIndex.DIFFICULTY: [(255, 85, 95), (157, 13, 31)]
}
def parse_box_def(path: Path): def parse_box_def(path: Path):
"""Parse box.def file for directory metadata""" """Parse box.def file for directory metadata"""
texture_index = SongBox.DEFAULT_INDEX
name = path.name name = path.name
genre = '' genre = ''
texture_index = TextureIndex.DEFAULT
genre_index = GenreIndex.DEFAULT
collection = None collection = None
back_color = None
fore_color = None
encoding = test_encodings(path / "box.def") encoding = test_encodings(path / "box.def")
try:
with open(path / "box.def", 'r', encoding=encoding) as box_def: with open(path / "box.def", 'r', encoding=encoding) as box_def:
for line in box_def: for line in box_def:
line = line.strip() line = line.strip()
if line.startswith("#GENRE:"): if line.startswith("#GENRE:"):
genre = line.split(":", 1)[1].strip() genre = line.split(":", 1)[1].strip()
texture_index = FileSystemItem.GENRE_MAP.get(genre, SongBox.DEFAULT_INDEX) texture_index = FileSystemItem.TEXTURE_MAP.get(genre, texture_index)
if texture_index == SongBox.DEFAULT_INDEX: genre_index = get_genre_index(genre)
texture_index = FileSystemItem.GENRE_MAP_2.get(genre, SongBox.DEFAULT_INDEX)
elif line.startswith("#TITLE:"): elif line.startswith("#TITLE:"):
name = line.split(":", 1)[1].strip() name = line.split(":", 1)[1].strip()
elif line.startswith("#TITLEJA:"): elif line.startswith("#TITLEJA:"):
if global_data.config['general']['language'] == 'ja': if global_data.config['general']['language'] == 'ja':
name = line.split(":", 1)[1].strip() name = line.split(":", 1)[1].strip()
elif line.startswith("#COLLECTION"): elif line.startswith("#COLLECTION:"):
collection = line.split(":", 1)[1].strip() collection = line.split(":", 1)[1].strip()
texture_index = FileSystemItem.TEXTURE_MAP.get(collection, texture_index)
genre_index = get_genre_index(collection)
elif line.startswith("#BACKCOLOR:"):
back_color = parse_hex_color(line.split(":", 1)[1].strip())
texture_index = TextureIndex.BLANK
elif line.startswith("#FORECOLOR:"):
fore_color = parse_hex_color(line.split(":", 1)[1].strip())
if name == '': if name == '':
if genre: if genre:
name = genre name = genre
else: else:
name = path.name name = path.name
except Exception as e:
logger.error(f"Error parsing box.def in {path}: {e}")
return name, texture_index, collection if back_color is None and fore_color is None and genre_index in DEFAULT_COLORS:
back_color, fore_color = DEFAULT_COLORS[genre_index]
if genre_index != GenreIndex.DEFAULT:
texture_index = TextureIndex.BLANK
return name, texture_index, genre_index, collection, back_color, fore_color
class FileSystemItem: class FileSystemItem:
GENRE_MAP = { TEXTURE_MAP = {
'J-POP': 1, 'VOCALOID': TextureIndex.VOCALOID,
'アニメ': 2, 'ボーカロイド': TextureIndex.VOCALOID,
'VOCALOID': 3, 'RECOMMENDED': TextureIndex.RECOMMENDED,
'どうよう': 4, 'FAVORITE': TextureIndex.FAVORITE,
'バラエティー': 5, 'RECENT': TextureIndex.RECENT,
'クラシック': 6,
'ゲームミュージック': 7,
'ナムコオリジナル': 8,
'RECOMMENDED': 10,
'FAVORITE': 11,
'RECENT': 12,
'段位道場': 13,
'DIFFICULTY': 14
} }
GENRE_MAP_2 = { GENRE_MAP = {
'ボーカロイド': 3, GenreIndex.TUTORIAL: {"TUTORIAL"},
'バラエティ': 5 GenreIndex.JPOP: {"J-POP"},
GenreIndex.ANIME: {"ANIME", "アニメ"},
GenreIndex.CHILDREN: {"CHILDREN", "どうよう"},
GenreIndex.VOCALOID: {"VOCALOID", "ボーカロイド"},
GenreIndex.VARIETY: {"VARIETY", "バラエティー", "バラエティ"},
GenreIndex.CLASSICAL: {"CLASSICAL", "クラシック"},
GenreIndex.GAME: {"GAME", "ゲームミュージック"},
GenreIndex.NAMCO: {"NAMCO", "ナムコオリジナル"},
GenreIndex.RECOMMENDED: {"RECOMMENDED"},
GenreIndex.FAVORITE: {"FAVORITE"},
GenreIndex.RECENT: {"RECENT"},
GenreIndex.DAN: {"DAN", "段位道場"},
GenreIndex.DIFFICULTY: {"DIFFICULTY"},
} }
"""Base class for files and directories in the navigation system""" """Base class for files and directories in the navigation system"""
def __init__(self, path: Path, name: str): def __init__(self, path: Path, name: str):
@@ -940,7 +1033,7 @@ class Directory(FileSystemItem):
'DIFFICULTY', 'DIFFICULTY',
'RECOMMENDED' 'RECOMMENDED'
] ]
def __init__(self, path: Path, name: str, texture_index: int, has_box_def=False, to_root=False, back=False, tja_count=0, box_texture=None, collection=None): def __init__(self, path: Path, name: str, back_color: Optional[tuple[int, int, int]], fore_color: Optional[tuple[int, int, int]], texture_index: TextureIndex, genre_index: GenreIndex, has_box_def=False, to_root=False, back=False, tja_count=0, box_texture=None, collection=None):
super().__init__(path, name) super().__init__(path, name)
self.has_box_def = has_box_def self.has_box_def = has_box_def
self.to_root = to_root self.to_root = to_root
@@ -949,27 +1042,23 @@ class Directory(FileSystemItem):
self.collection = None self.collection = None
if collection in Directory.COLLECTIONS: if collection in Directory.COLLECTIONS:
self.collection = collection self.collection = collection
if collection in FileSystemItem.GENRE_MAP:
texture_index = FileSystemItem.GENRE_MAP[collection]
elif self.to_root or self.back:
texture_index = SongBox.BACK_INDEX
if self.back: if self.back:
self.box = BackBox(name, texture_index) self.box = BackBox(name)
else: else:
self.box = FolderBox(name, texture_index, tja_count=tja_count, box_texture=box_texture) self.box = FolderBox(name, back_color, fore_color, texture_index, genre_index, tja_count=tja_count, box_texture=box_texture)
class SongFile(FileSystemItem): class SongFile(FileSystemItem):
"""Represents a song file (TJA) in the navigation system""" """Represents a song file (TJA) in the navigation system"""
def __init__(self, path: Path, name: str, texture_index: int, tja=None, name_texture_index: Optional[int]=None): def __init__(self, path: Path, name: str, back_color: Optional[tuple[int, int, int]], fore_color: Optional[tuple[int, int, int]], texture_index: TextureIndex):
super().__init__(path, name) super().__init__(path, name)
self.is_recent = (datetime.now() - datetime.fromtimestamp(path.stat().st_mtime)) <= timedelta(days=7) self.is_recent = (datetime.now() - datetime.fromtimestamp(path.stat().st_mtime)) <= timedelta(days=7)
self.tja = tja or TJAParser(path) self.tja = TJAParser(path)
if self.is_recent: if self.is_recent:
self.tja.ex_data.new = True self.tja.ex_data.new = True
title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en']) title = self.tja.metadata.title.get(global_data.config['general']['language'].lower(), self.tja.metadata.title['en'])
self.hash = global_data.song_paths[path] self.hash = global_data.song_paths[path]
self.box = SongBox(title, texture_index, self.tja, name_texture_index=name_texture_index if name_texture_index is not None else texture_index) self.box = SongBox(title, back_color, fore_color, texture_index, self.tja)
self.box.hash = global_data.song_hashes[self.hash][0]["diff_hashes"] self.box.hash = global_data.song_hashes[self.hash][0]["diff_hashes"]
self.box.get_scores() self.box.get_scores()
@@ -1008,11 +1097,11 @@ class DanCourse(FileSystemItem):
path = Path(global_data.song_hashes[hash_val][i]["file_path"]) path = Path(global_data.song_hashes[hash_val][i]["file_path"])
break break
if (path.parent.parent / "box.def").exists(): if (path.parent.parent / "box.def").exists():
_, genre_index, _ = parse_box_def(path.parent.parent) texture_index = parse_box_def(path.parent.parent)[1]
else: else:
genre_index = 9 texture_index = TextureIndex.DEFAULT
tja = TJAParser(path) tja = TJAParser(path)
self.charts.append((tja, genre_index, difficulty, tja.metadata.course_data[difficulty].level)) self.charts.append((tja, texture_index, difficulty, tja.metadata.course_data[difficulty].level))
self.exams = [] self.exams = []
for exam in data["exams"]: for exam in data["exams"]:
self.exams.append(Exam(exam["type"], exam["value"][0], exam["value"][1], exam["range"])) self.exams.append(Exam(exam["type"], exam["value"][0], exam["value"][1], exam["range"]))
@@ -1126,11 +1215,12 @@ class FileNavigator:
if has_box_def: if has_box_def:
# Parse box.def if it exists # Parse box.def if it exists
name = dir_path.name if dir_path.name else str(dir_path) name = dir_path.name if dir_path.name else str(dir_path)
texture_index = SongBox.DEFAULT_INDEX
box_texture = None box_texture = None
collection = None collection = None
back_color = None
fore_color = None
name, texture_index, collection = parse_box_def(dir_path) name, texture_index, genre_index, collection, back_color, fore_color = parse_box_def(dir_path)
box_png_path = dir_path / "box.png" box_png_path = dir_path / "box.png"
if box_png_path.exists(): if box_png_path.exists():
box_texture = str(box_png_path) box_texture = str(box_png_path)
@@ -1144,11 +1234,11 @@ class FileNavigator:
# Create Directory object # Create Directory object
directory_obj = Directory( directory_obj = Directory(
dir_path, name, texture_index, dir_path, name, back_color, fore_color, texture_index, genre_index,
has_box_def=has_box_def, has_box_def=has_box_def,
tja_count=tja_count, tja_count=tja_count,
box_texture=box_texture, box_texture=box_texture,
collection=collection collection=collection,
) )
if directory_obj.collection == Directory.COLLECTIONS[2]: if directory_obj.collection == Directory.COLLECTIONS[2]:
self.favorite_folder = directory_obj self.favorite_folder = directory_obj
@@ -1185,7 +1275,7 @@ class FileNavigator:
song_obj = DanCourse(tja_path, tja_path.name) song_obj = DanCourse(tja_path, tja_path.name)
self.all_song_files[song_key] = song_obj self.all_song_files[song_key] = song_obj
elif song_key not in self.all_song_files and tja_path in global_data.song_paths: elif song_key not in self.all_song_files and tja_path in global_data.song_paths:
song_obj = SongFile(tja_path, tja_path.name, texture_index) song_obj = SongFile(tja_path, tja_path.name, back_color, fore_color, texture_index)
song_obj.box.get_scores() song_obj.box.get_scores()
for course in song_obj.tja.metadata.course_data: for course in song_obj.tja.metadata.course_data:
level = song_obj.tja.metadata.course_data[course].level level = song_obj.tja.metadata.course_data[course].level
@@ -1210,7 +1300,7 @@ class FileNavigator:
elif is_cleared: elif is_cleared:
self.diff_sort_statistics[course][level][2] += 1 self.diff_sort_statistics[course][level][2] += 1
if song_obj.is_recent: if song_obj.is_recent:
self.new_items.append(SongFile(tja_path, tja_path.name, SongBox.DEFAULT_INDEX, name_texture_index=texture_index)) self.new_items.append(SongFile(tja_path, tja_path.name, back_color, fore_color, texture_index))
self.song_count += 1 self.song_count += 1
global_data.song_progress = self.song_count / global_data.total_songs global_data.song_progress = self.song_count / global_data.total_songs
self.all_song_files[song_key] = song_obj self.all_song_files[song_key] = song_obj
@@ -1232,7 +1322,7 @@ class FileNavigator:
song_key = str(tja_path) song_key = str(tja_path)
if song_key not in self.all_song_files: if song_key not in self.all_song_files:
try: try:
song_obj = SongFile(tja_path, tja_path.name, SongBox.DEFAULT_INDEX) song_obj = SongFile(tja_path, tja_path.name, None, None, TextureIndex.DEFAULT)
self.song_count += 1 self.song_count += 1
global_data.song_progress = self.song_count / global_data.total_songs global_data.song_progress = self.song_count / global_data.total_songs
self.all_song_files[song_key] = song_obj self.all_song_files[song_key] = song_obj
@@ -1269,7 +1359,7 @@ class FileNavigator:
# Add back navigation item (only if not at root) # Add back navigation item (only if not at root)
if not self.is_at_root(): if not self.is_at_root():
back_dir = Directory(self.current_dir.parent, "", SongBox.BACK_INDEX, back=True) back_dir = Directory(self.current_dir.parent, "", BackBox.COLOR, BackBox.COLOR, TextureIndex.BLANK, GenreIndex.DEFAULT, back=True)
if not has_children: if not has_children:
start_box = back_dir.box start_box = back_dir.box
self.items.insert(self.selected_index, back_dir) self.items.insert(self.selected_index, back_dir)
@@ -1330,11 +1420,13 @@ class FileNavigator:
for item in content_items: for item in content_items:
if isinstance(item, SongFile) and not has_children: if isinstance(item, SongFile) and not has_children:
if i % 10 == 0 and i != 0: if i % 10 == 0 and i != 0:
back_dir = Directory(self.current_dir.parent, "", SongBox.BACK_INDEX, back=True) back_dir = Directory(self.current_dir.parent, "", BackBox.COLOR, BackBox.COLOR, TextureIndex.BLANK, GenreIndex.DEFAULT, back=True)
self.items.insert(self.selected_index+i, back_dir) self.items.insert(self.selected_index+i, back_dir)
i += 1 i += 1
if not has_children: if not has_children:
if selected_item is not None: if selected_item is not None:
item.box.back_color = selected_item.box.back_color
item.box.genre_index = selected_item.box.genre_index
item.box.texture_index = selected_item.box.texture_index item.box.texture_index = selected_item.box.texture_index
self.items.insert(self.selected_index+i, item) self.items.insert(self.selected_index+i, item)
else: else:

View File

@@ -5,7 +5,9 @@ from pathlib import Path
import pyray as ray import pyray as ray
import logging import logging
from libs.file_navigator import BackBox, DanCourse, navigator from raylib import SHADER_UNIFORM_VEC3
from libs.file_navigator import DEFAULT_COLORS, BackBox, DanCourse, GenreIndex, navigator
from libs.audio import audio from libs.audio import audio
from libs.chara_2d import Chara2D from libs.chara_2d import Chara2D
from libs.file_navigator import Directory, SongBox, SongFile from libs.file_navigator import Directory, SongBox, SongFile
@@ -57,14 +59,17 @@ class SongSelectScreen(Screen):
self.coin_overlay = CoinOverlay() self.coin_overlay = CoinOverlay()
self.allnet_indicator = AllNetIcon() self.allnet_indicator = AllNetIcon()
self.indicator = Indicator(Indicator.State.SELECT) self.indicator = Indicator(Indicator.State.SELECT)
self.texture_index = SongBox.DEFAULT_INDEX self.genre_index = GenreIndex.DEFAULT
self.last_texture_index = SongBox.DEFAULT_INDEX self.last_genre_index = self.genre_index
self.last_moved = get_current_ms() self.last_moved = get_current_ms()
self.timer_browsing = Timer(100, get_current_ms(), self.navigator.select_current_item) self.timer_browsing = Timer(100, get_current_ms(), self.navigator.select_current_item)
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper) self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
self.screen_init = True self.screen_init = True
self.ura_switch_animation = UraSwitchAnimation() self.ura_switch_animation = UraSwitchAnimation()
self.dan_transition = DanTransition() self.dan_transition = DanTransition()
self.shader = ray.load_shader('', 'shader/colortransform.fs')
self.color = None
self.load_shader_values(self.color)
session_data = global_data.session_data[global_data.player_num] session_data = global_data.session_data[global_data.player_num]
self.player_1 = SongSelectPlayer(global_data.player_num, self.text_fade_in) self.player_1 = SongSelectPlayer(global_data.player_num, self.text_fade_in)
@@ -83,11 +88,22 @@ class SongSelectScreen(Screen):
curr_item.box.get_scores() curr_item.box.get_scores()
self.navigator.add_recent() self.navigator.add_recent()
def load_shader_values(self, target_rgb):
source_rgb = (142, 212, 30)
if target_rgb is None:
target_rgb = source_rgb
source_color = ray.ffi.new('float[3]', [source_rgb[0]/255.0, source_rgb[1]/255.0, source_rgb[2]/255.0])
target_color = ray.ffi.new('float[3]', [target_rgb[0]/255.0, target_rgb[1]/255.0, target_rgb[2]/255.0])
source_loc = ray.get_shader_location(self.shader, 'sourceColor')
target_loc = ray.get_shader_location(self.shader, 'targetColor')
ray.set_shader_value(self.shader, source_loc, source_color, SHADER_UNIFORM_VEC3)
ray.set_shader_value(self.shader, target_loc, target_color, SHADER_UNIFORM_VEC3)
def finalize_song(self, current_item: SongFile): def finalize_song(self, current_item: SongFile):
global_data.session_data[global_data.player_num].selected_song = current_item.path global_data.session_data[global_data.player_num].selected_song = current_item.path
global_data.session_data[global_data.player_num].song_hash = global_data.song_hashes[current_item.hash][0]["diff_hashes"][self.player_1.selected_difficulty] global_data.session_data[global_data.player_num].song_hash = global_data.song_hashes[current_item.hash][0]["diff_hashes"][self.player_1.selected_difficulty]
global_data.session_data[global_data.player_num].selected_difficulty = self.player_1.selected_difficulty global_data.session_data[global_data.player_num].selected_difficulty = self.player_1.selected_difficulty
global_data.session_data[global_data.player_num].genre_index = current_item.box.name_texture_index global_data.session_data[global_data.player_num].genre_index = current_item.box.genre_index
def on_screen_end(self, next_screen): def on_screen_end(self, next_screen):
self.screen_init = False self.screen_init = False
@@ -268,11 +284,11 @@ class SongSelectScreen(Screen):
elif self.state == State.SONG_SELECTED: elif self.state == State.SONG_SELECTED:
self.timer_selected.update(current_time) self.timer_selected.update(current_time)
if self.last_texture_index != self.texture_index: if self.last_genre_index != self.genre_index:
if not self.background_fade_change.is_started: if not self.background_fade_change.is_started:
self.background_fade_change.start() self.background_fade_change.start()
if self.background_fade_change.is_finished: if self.background_fade_change.is_finished:
self.last_texture_index = self.texture_index self.last_genre_index = self.genre_index
self.background_fade_change.reset() self.background_fade_change.reset()
if self.game_transition is not None: if self.game_transition is not None:
@@ -287,6 +303,8 @@ class SongSelectScreen(Screen):
if self.navigator.genre_bg is not None: if self.navigator.genre_bg is not None:
self.navigator.genre_bg.update(current_time) self.navigator.genre_bg.update(current_time)
if not self.navigator.genre_bg.shader_loaded:
self.navigator.genre_bg.load_shader()
if self.diff_sort_selector is not None: if self.diff_sort_selector is not None:
self.diff_sort_selector.update(current_time) self.diff_sort_selector.update(current_time)
@@ -309,7 +327,9 @@ class SongSelectScreen(Screen):
if song.box.is_open: if song.box.is_open:
current_box = song.box current_box = song.box
if not isinstance(current_box, BackBox) and current_time >= song.box.wait + (83.33*3): if not isinstance(current_box, BackBox) and current_time >= song.box.wait + (83.33*3):
self.texture_index = current_box.texture_index self.genre_index = current_box.genre_index
self.color = current_box.back_color
self.load_shader_values(self.color)
if ray.is_key_pressed(global_data.config["keys"]["back_key"]): if ray.is_key_pressed(global_data.config["keys"]["back_key"]):
logger.info("Back key pressed, returning to ENTRY screen") logger.info("Back key pressed, returning to ENTRY screen")
@@ -323,9 +343,16 @@ class SongSelectScreen(Screen):
def draw(self): def draw(self):
width = tex.textures['box']['background'].width width = tex.textures['box']['background'].width
genre_index = self.genre_index
last_genre_index = self.last_genre_index
if genre_index in DEFAULT_COLORS and self.color != DEFAULT_COLORS[genre_index][0]:
ray.begin_shader_mode(self.shader)
genre_index = GenreIndex.VARIETY
last_genre_index = GenreIndex.VARIETY
for i in range(0, width * 4, width): for i in range(0, width * 4, width):
tex.draw_texture('box', 'background', frame=self.last_texture_index, x=i-self.background_move.attribute) tex.draw_texture('box', 'background', frame=last_genre_index, x=i-self.background_move.attribute)
tex.draw_texture('box', 'background', frame=self.texture_index, x=i-self.background_move.attribute, fade=1 - self.background_fade_change.attribute) tex.draw_texture('box', 'background', frame=genre_index, x=i-self.background_move.attribute, fade=1 - self.background_fade_change.attribute)
ray.end_shader_mode()
self.draw_background_diffs() self.draw_background_diffs()