diff --git a/libs/animation.py b/libs/animation.py index 21210be..a2fb947 100644 --- a/libs/animation.py +++ b/libs/animation.py @@ -169,7 +169,8 @@ class TextStretchAnimation(BaseAnimation): class TextureResizeAnimation(BaseAnimation): def __init__(self, duration: float, initial_size: float = 1.0, final_size: float = 0.0, delay: float = 0.0, - reverse_delay: Optional[float] = None) -> None: + reverse_delay: Optional[float] = None, + ease_in: Optional[str] = None, ease_out: Optional[str] = None) -> None: super().__init__(duration, delay) self.initial_size = initial_size self.final_size = final_size @@ -177,6 +178,8 @@ class TextureResizeAnimation(BaseAnimation): self.initial_size_saved = initial_size self.final_size_saved = final_size self.reverse_delay_saved = reverse_delay + self.ease_in = ease_in + self.ease_out = ease_out def restart(self) -> None: super().restart() @@ -203,6 +206,7 @@ class TextureResizeAnimation(BaseAnimation): else: animation_time = elapsed_time - self.delay progress = animation_time / self.duration + progress = self._apply_easing(progress, self.ease_in, self.ease_out) self.attribute = self.initial_size + ((self.final_size - self.initial_size) * progress) diff --git a/libs/utils.py b/libs/utils.py index cc01935..e9e9787 100644 --- a/libs/utils.py +++ b/libs/utils.py @@ -281,62 +281,151 @@ class OutlinedText: def _create_text_vertical(self, text: str, font_size: int, color: ray.Color, bg_color: ray.Color, font: Optional[ray.Font]=None, padding: int=10): rotate_chars = {'-', '‐', '|', '/', '\\', 'ー', '~', '~', '(', ')', '(', ')', '「', '」', '[', ']', '[', ']', '【', '】', '…', '→', '→', ':', ':'} + side_punctuation = {'.', ',', '。', '、', "'", '"', '´', '`'} + horizontal_punct = {'?', '!', '?', '!', '†'} # Characters that should be drawn horizontally when repeated + lowercase_kana = { + 'ぁ', 'ア','ぃ', 'イ','ぅ', 'ウ','ぇ', 'エ','ぉ', 'オ', + 'ゃ', 'ャ','ゅ', 'ュ','ょ', 'ョ','っ', 'ッ','ゎ', 'ヮ', + 'ヶ', 'ヵ','ㇰ','ㇱ','ㇲ','ㇳ','ㇴ','ㇵ','ㇶ','ㇷ','ㇸ', + 'ㇹ','ㇺ','ㇻ','ㇼ','ㇽ','ㇾ','ㇿ' + } + + # Group consecutive horizontal punctuation marks + def group_horizontal_sequences(text): + groups = [] + i = 0 + while i < len(text): + if text[i] in horizontal_punct: + # Start of a horizontal sequence + sequence = text[i] + j = i + 1 + # Continue collecting consecutive horizontal punctuation + while j < len(text) and text[j] in horizontal_punct: + sequence += text[j] + j += 1 + + # Only treat as horizontal if there are 2 or more characters + if len(sequence) >= 2: + groups.append(('horizontal', sequence)) + else: + groups.append(('single', sequence)) + i = j + else: + groups.append(('single', text[i])) + i += 1 + return groups + + # Helper function to calculate adjusted character height + def get_char_height(char): + if char in side_punctuation: + return font_size // 4 + elif char.islower() or char in lowercase_kana: + return font_size * 0.88 + elif char.isspace(): + return font_size * 0.6 + else: + return font_size + + grouped_text = group_horizontal_sequences(text) + + # Calculate dimensions with proper height adjustments max_char_width = 0 total_height = padding * 2 - for char in text: - if font: - char_size = ray.measure_text_ex(font, char, font_size, 0) + for group_type, content in grouped_text: + if group_type == 'horizontal': + # For horizontal sequences, measure the combined width + if font: + seq_size = ray.measure_text_ex(font, content, font_size, 0) + else: + seq_width = ray.measure_text(content, font_size) + seq_size = ray.Vector2(seq_width, font_size) + max_char_width = max(max_char_width, seq_size.x) + total_height += font_size # Horizontal sequences use full font_size else: - char_width = ray.measure_text(char, font_size) - char_size = ray.Vector2(char_width, font_size) + # Single character + char = content + if font: + char_size = ray.measure_text_ex(font, char, font_size, 0) + else: + char_width = ray.measure_text(char, font_size) + char_size = ray.Vector2(char_width, font_size) - if char in rotate_chars: - effective_width = char_size.y - else: - effective_width = char_size.x + if char in rotate_chars: + effective_width = char_size.y + else: + effective_width = char_size.x + max_char_width = max(max_char_width, effective_width) - max_char_width = max(max_char_width, effective_width) + # Use the adjusted height instead of fixed font_size + total_height += get_char_height(char) - total_height += len(text) * font_size width = int(max_char_width + (padding * 2)) - height = total_height + height = int(total_height) # Make sure it's an integer image = ray.gen_image_color(width, height, bg_color) - for i, char in enumerate(text): - char_y = i * font_size + padding + curr_char_y = padding - font_size + + for group_type, content in grouped_text: + if group_type == 'horizontal': + # Handle horizontal punctuation sequence + char_y = font_size + curr_char_y += char_y + + if font: + seq_size = ray.measure_text_ex(font, content, font_size, 0) + seq_image = ray.image_text_ex(font, content, font_size, 0, color) + else: + seq_width = ray.measure_text(content, font_size) + seq_size = ray.Vector2(seq_width, font_size) + seq_image = ray.image_text(content, font_size, color) + + # Center the horizontal sequence + char_x = width // 2 - seq_size.x // 2 + + ray.image_draw(image, seq_image, + ray.Rectangle(0, 0, seq_image.width, seq_image.height), + ray.Rectangle(char_x, curr_char_y, seq_image.width, seq_image.height), + ray.WHITE) + ray.unload_image(seq_image) - if font: - char_size = ray.measure_text_ex(font, char, font_size, 0) - char_image = ray.image_text_ex(font, char, font_size, 0, color) else: - char_width = ray.measure_text(char, font_size) - char_size = ray.Vector2(char_width, font_size) - char_image = ray.image_text(char, font_size, color) + # Handle single character (existing logic) + char = content + char_y = get_char_height(char) # Use the helper function + curr_char_y += char_y - if char in rotate_chars: - rotated_image = ray.gen_image_color(char_image.height, char_image.width, ray.BLANK) + if font: + char_size = ray.measure_text_ex(font, char, font_size, 0) + char_image = ray.image_text_ex(font, char, font_size, 0, color) + else: + char_width = ray.measure_text(char, font_size) + char_size = ray.Vector2(char_width, font_size) + char_image = ray.image_text(char, font_size, color) - for y in range(char_image.height): - for x in range(char_image.width): - src_color = ray.get_image_color(char_image, x, y) - new_x = char_image.height - 1 - y - new_y = x - ray.image_draw_pixel(rotated_image, new_x, new_y, src_color) + if char in rotate_chars: + rotated_image = ray.gen_image_color(char_image.height, char_image.width, ray.BLANK) + for y in range(char_image.height): + for x in range(char_image.width): + src_color = ray.get_image_color(char_image, x, y) + new_x = char_image.height - 1 - y + new_y = x + ray.image_draw_pixel(rotated_image, new_x, new_y, src_color) + ray.unload_image(char_image) + char_image = rotated_image + effective_width = char_size.y + else: + effective_width = char_size.x + char_x = width // 2 - effective_width // 2 + if char in side_punctuation: + char_x += font_size//3 + + ray.image_draw(image, char_image, + ray.Rectangle(0, 0, char_image.width, char_image.height), + ray.Rectangle(char_x, curr_char_y, char_image.width, char_image.height), + ray.WHITE) ray.unload_image(char_image) - char_image = rotated_image - effective_width = char_size.y - else: - effective_width = char_size.x - - char_x = width // 2 - effective_width // 2 - - ray.image_draw(image, char_image, - ray.Rectangle(0, 0, char_image.width, char_image.height), - ray.Rectangle(char_x, char_y, char_image.width, char_image.height), - ray.WHITE) - ray.unload_image(char_image) texture = ray.load_texture_from_image(image) ray.unload_image(image) diff --git a/scenes/devtest.py b/scenes/devtest.py index a19fa1f..1c00a4a 100644 --- a/scenes/devtest.py +++ b/scenes/devtest.py @@ -1,7 +1,5 @@ import pyray as ray -from libs.utils import OutlinedText, get_current_ms - class DevScreen: def __init__(self, width: int, height: int): @@ -9,9 +7,6 @@ class DevScreen: self.height = height self.screen_init = False - self.time_now = get_current_ms() - self.test = OutlinedText('Triple Helix', 40, ray.Color(255, 255, 255, 255), ray.Color(101, 0, 82, 255), outline_thickness=4, vertical=True) - def on_screen_start(self): if not self.screen_init: self.screen_init = True @@ -23,10 +18,7 @@ class DevScreen: def update(self): self.on_screen_start() if ray.is_key_pressed(ray.KeyboardKey.KEY_ENTER): - return self.on_screen_end('TITLE') + return self.on_screen_end('RESULT') def draw(self): - ray.draw_rectangle(0, 0, self.width, self.height, ray.WHITE) - src = ray.Rectangle(0, 0, self.test.texture.width, self.test.texture.height) - dest = ray.Rectangle(self.width//2 - self.test.texture.width//2, self.height//2 - self.test.texture.height//2, self.test.texture.width, self.test.texture.height) - self.test.draw(src, dest, ray.Vector2(0, 0), 0, ray.WHITE) + pass diff --git a/scenes/loading.py b/scenes/loading.py index f9ad9e2..7f62ff9 100644 --- a/scenes/loading.py +++ b/scenes/loading.py @@ -1,9 +1,11 @@ import threading +from pathlib import Path import pyray as ray +from libs.animation import Animation from libs.song_hash import build_song_hashes -from libs.utils import global_data +from libs.utils import get_current_ms, global_data, load_all_textures_from_zip from scenes.song_select import SongSelectScreen @@ -18,15 +20,19 @@ class LoadScreen: self.song_select_screen = song_select_screen # Progress bar settings - self.progress_bar_width = width * 0.6 - self.progress_bar_height = 20 + self.progress_bar_width = width * 0.43 + self.progress_bar_height = 50 self.progress_bar_x = (width - self.progress_bar_width) // 2 - self.progress_bar_y = height * 0.7 + self.progress_bar_y = height * 0.85 # Thread references self.loading_thread = None self.navigator_thread = None + self.textures = load_all_textures_from_zip(Path('Graphics/lumendata/attract/kidou.zip')) + + self.fade_in = None + def _load_song_hashes(self): """Background thread function to load song hashes""" try: @@ -71,11 +77,17 @@ class LoadScreen: self.navigator_thread.start() self.navigator_started = True - if self.loading_complete: - return self.on_screen_end('TITLE') + if self.loading_complete and self.fade_in is None: + self.fade_in = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0, ease_in='cubic') + + if self.fade_in is not None: + self.fade_in.update(get_current_ms()) + if self.fade_in.is_finished: + return self.on_screen_end('TITLE') def draw(self): ray.draw_rectangle(0, 0, self.width, self.height, ray.BLACK) + ray.draw_texture(self.textures['kidou'][1], self.width//2 - self.textures['kidou'][1].width//2, 50, ray.WHITE) # Draw progress bar background ray.draw_rectangle( @@ -83,7 +95,7 @@ class LoadScreen: int(self.progress_bar_y), int(self.progress_bar_width), int(self.progress_bar_height), - ray.DARKGRAY + ray.Color(101, 0, 0, 255) ) # Draw progress bar fill @@ -98,11 +110,5 @@ class LoadScreen: ray.RED ) - # Draw border - ray.draw_rectangle_lines( - int(self.progress_bar_x), - int(self.progress_bar_y), - int(self.progress_bar_width), - int(self.progress_bar_height), - ray.WHITE - ) + if self.fade_in is not None: + ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.WHITE, self.fade_in.attribute)) diff --git a/scenes/result.py b/scenes/result.py index 70ffd5a..0b12684 100644 --- a/scenes/result.py +++ b/scenes/result.py @@ -1,6 +1,8 @@ +import math from pathlib import Path import pyray as ray +from raylib import SHADER_UNIFORM_FLOAT from libs import utils from libs.animation import Animation @@ -17,12 +19,17 @@ from libs.utils import ( ) +class State: + FAIL = 0 + CLEAR = 1 + RAINBOW = 2 + class ResultScreen: def __init__(self, width: int, height: int): self.width = width self.height = height self.screen_init = False - self.fade_out = None + self.alpha_shader = ray.load_shader('', 'shader/grayscale_alpha.fs') def load_textures(self): zip_file = Path('Graphics/lumendata/enso_result.zip') @@ -44,8 +51,12 @@ class ResultScreen: audio.play_sound(self.bgm) self.fade_in = FadeIn() self.fade_out = None + self.fade_in_bottom = None self.gauge = None self.score_delay = None + self.bottom_characters = BottomCharacters() + self.crown = None + self.state = None self.score_animator = ScoreAnimator(session_data.result_score) self.score = -1 self.good = -1 @@ -62,6 +73,10 @@ class ResultScreen: self.update_index = 0 self.is_skipped = False self.start_ms = get_current_ms() + if session_data.result_bad == 0: + self.crown_texture = 125 + else: + self.crown_texture = 124 def on_screen_end(self): self.screen_init = False @@ -112,12 +127,32 @@ class ResultScreen: self.fade_in.update(get_current_ms()) if self.fade_in.is_finished and self.gauge is None: self.gauge = Gauge(get_current_ms(), session_data.result_gauge_length) + self.bottom_characters.start() + + self.bottom_characters.update(self.state) + + if self.bottom_characters.is_finished and self.crown is None: + if self.gauge is not None and self.gauge.gauge_length > 69: + self.crown = Crown() if self.gauge is not None: self.gauge.update(get_current_ms()) if self.gauge.is_finished and self.score_delay is None: self.score_delay = get_current_ms() + 1883 + if self.score_delay is not None: + if get_current_ms() > self.score_delay and self.fade_in_bottom is None: + self.fade_in_bottom = Animation.create_fade(333, initial_opacity=0.0, final_opacity=1.0) + if self.gauge is not None: + self.state = self.gauge.state + + + if self.fade_in_bottom is not None: + self.fade_in_bottom.update(get_current_ms()) + alpha_loc = ray.get_shader_location(self.alpha_shader, "ext_alpha") + alpha_value = ray.ffi.new('float*', self.fade_in_bottom.attribute) + ray.set_shader_value(self.alpha_shader, alpha_loc, alpha_value, SHADER_UNIFORM_FLOAT) + if get_current_ms() >= self.start_ms + 5000: self.handle_input() @@ -128,6 +163,9 @@ class ResultScreen: if self.fade_out.is_finished: return self.on_screen_end() + if self.crown is not None: + self.crown.update(get_current_ms()) + def draw_score_info(self): if self.good > -1: for i in range(len(str(self.good))): @@ -146,11 +184,29 @@ class ResultScreen: ray.draw_texture(self.textures['result'][int(str(self.total_drumroll)[::-1][i]) + 136], 1217-(i*24), 186, ray.WHITE) def draw_total_score(self): + if self.fade_in is None: + return + + if not self.fade_in.is_finished: + return ray.draw_texture(self.textures['result'][167], 554, 236, ray.WHITE) if self.score > -1: for i in range(len(str(self.score))): ray.draw_texture(self.textures['result'][int(str(self.score)[::-1][i]) + 156], 723-(i*21), 252, ray.WHITE) + def draw_bottom_textures(self): + if self.fade_in_bottom is not None: + src = ray.Rectangle(0, 0, self.textures['result'][328].width, self.textures['result'][328].height) + if self.state == State.FAIL: + dest = ray.Rectangle(0, self.height//2, self.width, self.height//2) + ray.draw_texture_pro(self.textures['result'][329], src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, min(0.4, self.fade_in_bottom.attribute))) + else: + dest = ray.Rectangle(0, self.height//2 - 72, self.width, self.height//2) + ray.begin_shader_mode(self.alpha_shader) + ray.draw_texture_pro(self.textures['result'][328], src, dest, ray.Vector2(0, 0), 0, ray.fade(ray.WHITE, self.fade_in_bottom.attribute)) + ray.end_shader_mode() + self.bottom_characters.draw(self.textures['result']) + def draw(self): x = 0 while x < self.width: @@ -171,6 +227,10 @@ class ResultScreen: ray.draw_texture(self.textures['result'][175], 532, 98, ray.fade(ray.WHITE, 0.75)) + ray.draw_texture(self.textures['result'][233 + session_data.selected_difficulty], 289, 129, ray.WHITE) + + self.draw_bottom_textures() + if self.gauge is not None: self.gauge.draw(self.textures['result']) @@ -183,12 +243,141 @@ class ResultScreen: self.draw_score_info() self.draw_total_score() + if self.crown is not None: + self.crown.draw(self.textures['result'], self.crown_texture) + if self.fade_in is not None: self.fade_in.draw(self.width, self.height, self.textures['result'][326], self.textures['result'][327]) if self.fade_out is not None: self.fade_out.draw(self.width, self.height) +class Crown: + def __init__(self): + duration = 466 + self.resize = Animation.create_texture_resize(duration, initial_size=3.5, final_size=0.90, ease_in='quadratic') + self.resize_fix = Animation.create_texture_resize(216, initial_size=self.resize.final_size, final_size=1.0, delay=self.resize.duration) + self.white_fadein = Animation.create_fade(133, initial_opacity=0.0, final_opacity=1.0, delay=self.resize.duration + self.resize_fix.duration, reverse_delay=0) + self.gleam = Animation.create_texture_change(400, textures=[(0, 200, 0), (200, 250, 127), (250, 300, 128), (300, 350, 129), (350, 400, 0)], delay=self.resize.duration + self.resize_fix.duration + self.white_fadein.duration) + self.fadein = Animation.create_fade(duration, initial_opacity=0.0, final_opacity=1.0, ease_in='quadratic') + self.sound = audio.load_sound(Path('Sounds/result/SE_RESULT [1].ogg')) + self.sound_played = False + + def update(self, current_ms: float): + self.fadein.update(current_ms) + self.resize.update(current_ms) + self.resize_fix.update(current_ms) + self.white_fadein.update(current_ms) + self.gleam.update(current_ms) + if self.resize_fix.is_finished and not self.sound_played: + audio.play_sound(self.sound) + self.sound_played = True + + def draw(self, textures: list[ray.Texture], crown_index: int): + scale = self.resize.attribute + if self.resize.is_finished: + scale = self.resize_fix.attribute + texture = textures[crown_index] + x_x = 335 + (texture.width//2) - ((texture.width * scale)//2) + x_y = 150 + (texture.height//2) - ((texture.height * scale)//2) + x_source = ray.Rectangle(0, 0, texture.width, texture.height) + x_dest = ray.Rectangle(x_x, x_y, texture.width*scale, texture.height*scale) + ray.draw_texture_pro(texture, x_source, x_dest, ray.Vector2(0,0), 0, ray.fade(ray.WHITE, self.fadein.attribute)) + ray.draw_texture(textures[126], int(x_x), int(x_y), ray.fade(ray.WHITE, self.white_fadein.attribute)) + if self.gleam.attribute != 0: + ray.draw_texture(textures[self.gleam.attribute], int(x_x), int(x_y), ray.WHITE) + +class BottomCharacters: + def __init__(self): + self.move_up = None + self.move_down = None + self.move_center = None + self.bounce_up = None + self.bounce_down = None + self.flower_up = None + self.state = None + self.flower_index = 341 + self.flower_start = None + self.char_1_index = 339 + self.char_2_index = 340 + self.c_bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic') + self.c_bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.c_bounce_up.duration) + self.is_finished = False + + def start(self): + self.move_up = Animation.create_move(366, total_distance=380, ease_out='cubic') + self.move_down = Animation.create_move(133, total_distance=30, ease_out='cubic', delay=self.move_up.duration-5) + + def update(self, state): + self.state = state + if self.state == State.CLEAR or self.state == State.RAINBOW: + self.char_1_index = 345 + self.char_2_index = 346 + if self.bounce_up is None: + self.bounce_up = Animation.create_move(266, total_distance=40, ease_in='quadratic') + self.bounce_down = Animation.create_move(266, total_distance=40, ease_out='quadratic', delay=self.bounce_up.duration) + self.move_center = Animation.create_move(266, total_distance=450, ease_out='quadratic', delay=self.bounce_down.duration+self.bounce_up.duration) + if self.flower_up is None: + self.flower_up = Animation.create_move(333, total_distance=365, ease_out='quadratic') + self.flower_start = get_current_ms() + elif self.state == State.FAIL: + self.char_1_index = 347 + self.char_2_index = 348 + + if self.move_up is not None: + self.move_up.update(get_current_ms()) + if self.move_down is not None: + self.move_down.update(get_current_ms()) + self.is_finished = self.move_down.is_finished + if self.bounce_up is not None: + self.bounce_up.update(get_current_ms()) + if self.bounce_down is not None: + self.bounce_down.update(get_current_ms()) + if self.bounce_down.is_finished and self.bounce_up is not None: + self.bounce_up.restart() + self.bounce_down.restart() + if self.move_center is not None: + self.move_center.update(get_current_ms()) + if self.flower_up is not None: + self.flower_up.update(get_current_ms()) + + if self.flower_start is not None: + if get_current_ms() > self.flower_start + 116*2 + 333: + self.flower_index = 343 + elif get_current_ms() > self.flower_start + 116 + 333: + self.flower_index = 342 + + self.c_bounce_up.update(get_current_ms()) + self.c_bounce_down.update(get_current_ms()) + if self.c_bounce_down.is_finished: + self.c_bounce_up.restart() + self.c_bounce_down.restart() + + def draw_flowers(self, textures: list[ray.Texture]): + if self.flower_up is None: + return + y = 720+textures[self.flower_index].height - int(self.flower_up.attribute) + source_rect = ray.Rectangle(0, 0, textures[self.flower_index].width, textures[self.flower_index].height) + dest_rect = ray.Rectangle(1280-textures[self.flower_index].width, y, textures[self.flower_index].width, textures[self.flower_index].height) + source_rect.width = -textures[self.flower_index].width + ray.draw_texture_pro(textures[self.flower_index], source_rect, dest_rect, ray.Vector2(0, 0), 0, ray.WHITE) + ray.draw_texture(textures[self.flower_index], 0, y, ray.WHITE) + + def draw(self, textures: list[ray.Texture]): + if self.move_up is None or self.move_down is None: + return + + self.draw_flowers(textures) + + y = 720 - int(self.move_up.attribute) + int(self.move_down.attribute) + if self.bounce_up is not None and self.bounce_down is not None: + y = 720 - int(self.move_up.attribute) + int(self.move_down.attribute) + int(self.bounce_up.attribute) - int(self.bounce_down.attribute) + if self.state == State.RAINBOW and self.move_center is not None: + center_y = int(self.c_bounce_up.attribute) - int(self.c_bounce_down.attribute) + ray.draw_texture(textures[344], 1280//2 - textures[344].width//2, (800 - int(self.move_center.attribute)) + int(center_y), ray.WHITE) + + ray.draw_texture(textures[self.char_1_index], 125, y, ray.WHITE) + ray.draw_texture(textures[self.char_2_index], 820, y, ray.WHITE) class FadeIn: def __init__(self): @@ -240,6 +429,12 @@ class Gauge: self.rainbow_animation = None self.gauge_fade_in = Animation.create_fade(366, initial_opacity=0.0, final_opacity=1.0) self.is_finished = self.gauge_fade_in.is_finished + if self.gauge_length == 87: + self.state = State.RAINBOW + elif self.gauge_length > 69: + self.state = State.CLEAR + else: + self.state = State.FAIL def _create_rainbow_anim(self, current_ms): anim = Animation.create_texture_change((16.67*8) * 3, textures=[((16.67 * 3) * i, (16.67 * 3) * (i + 1), i) for i in range(8)]) diff --git a/shader/grayscale_alpha.fs b/shader/grayscale_alpha.fs new file mode 100644 index 0000000..3a3cec2 --- /dev/null +++ b/shader/grayscale_alpha.fs @@ -0,0 +1,13 @@ +// fragment shader +#version 330 +in vec2 fragTexCoord; +uniform sampler2D texture0; +out vec4 finalColor; +uniform float ext_alpha; +void main() { + vec4 texColor = texture(texture0, fragTexCoord); + vec3 last_color = vec3(1.0, 253.0/255.0, (186.0*0.80)/255.0); + // Use luminance as alpha (0.0 = transparent, 1.0 = opaque) + float alpha = ((texColor.r + texColor.g + texColor.b)/3)*0.70; + finalColor = vec4(last_color, alpha * ext_alpha); +}