From 12193dc560820d29ac0ea9b59dcb1942a9dce91e Mon Sep 17 00:00:00 2001 From: Quinn Date: Wed, 28 Aug 2024 22:16:11 -0400 Subject: [PATCH] added dropdown menus --- lib/Animator/Animation.h | 35 ++++-- tools/animation-tools/AnimationExporter.py | 4 +- tools/animation-tools/CustomWidgets.py | 18 --- tools/animation-tools/UI.py | 129 +++++++++++++++++---- tools/animation-tools/animation-tool.py | 1 - 5 files changed, 136 insertions(+), 51 deletions(-) delete mode 100644 tools/animation-tools/CustomWidgets.py diff --git a/lib/Animator/Animation.h b/lib/Animator/Animation.h index 6f78b7a..189877c 100644 --- a/lib/Animator/Animation.h +++ b/lib/Animator/Animation.h @@ -211,23 +211,38 @@ namespace RisingCubes{ .delay = std::chrono::milliseconds(1) }; - AnimationFrame frame0{ + AnimationFrame frame00{ .frame = { - CreateCell(0.0,0.0,0.0,V3D(255.0,255.0,255.0)), - CreateCell(0.0,0.5,0.0,V3D(0.0,255.0,0.0)), - CreateCell(0.0,1.0,0.0,V3D(0.0,255.0,0.0)), - CreateCell(0.0,0.0,0.5,V3D(0.0,0.0,255.0)), - CreateCell(0.0,0.0,1.0,V3D(0.0,0.0,255.0)), - CreateCell(0.5,0.0,0.0,V3D(255.0,0.0,0.0)), - CreateCell(1.0,0.0,0.0,V3D(255.0,0.0,0.0)) + CreateCell(0.0,0.0,1.0,V3D(128.0,128.0,255.0)), + CreateCell(0.5,0.0,1.0,V3D(128.0,128.0,255.0)), + CreateCell(1.0,0.0,0.0,V3D(255.0,118.0,205.0)), + CreateCell(1.0,0.0,0.5,V3D(255.0,118.0,205.0)), + CreateCell(1.0,0.0,1.0,V3D(255.0,116.0,0.0)), + CreateCell(1.0,0.5,1.0,V3D(183.0,0.0,255.0)), + CreateCell(1.0,1.0,1.0,V3D(183.0,0.0,255.0)) }, - .fillInterpolation = FillInterpolation::NO_FILL, + .fillInterpolation = FillInterpolation::CLOSEST_COLOR, + .frameInterpolation = FrameInterpolation::FADE, + .delay = std::chrono::milliseconds(1000) + }; + + AnimationFrame frame01{ + .frame = { + CreateCell(0.0,0.0,1.0,V3D(255.0,255.0,171.0)), + CreateCell(0.5,0.0,1.0,V3D(255.0,255.0,171.0)), + CreateCell(1.0,0.0,0.0,V3D(0.0,195.0,88.0)), + CreateCell(1.0,0.0,0.5,V3D(0.0,195.0,88.0)), + CreateCell(1.0,0.0,1.0,V3D(0.0,195.0,88.0)), + CreateCell(1.0,0.5,1.0,V3D(112.0,222.0,255.0)), + CreateCell(1.0,1.0,1.0,V3D(112.0,222.0,255.0)) + }, + .fillInterpolation = FillInterpolation::CLOSEST_COLOR, .frameInterpolation = FrameInterpolation::FADE, .delay = std::chrono::milliseconds(1000) }; std::vector rising{ - frame0, frame0 + frame00, frame01, frame00 // frame1, // 0 // frame2, // 1 // frame3, // 2 diff --git a/tools/animation-tools/AnimationExporter.py b/tools/animation-tools/AnimationExporter.py index fdab606..db194b5 100644 --- a/tools/animation-tools/AnimationExporter.py +++ b/tools/animation-tools/AnimationExporter.py @@ -8,10 +8,12 @@ class FillInterpolation(StrEnum): CLOSEST_COLOR = "CLOSEST_COLOR" LINEAR_WEIGHTED_DISTANCE = "LINEAR_WEIGHTED_DISTANCE" SQUARE_WEIGHTED_DISTANCE = "SQUARE_WEIGHTED_DISTANCE" + # options = [NO_FILL, CLOSEST_COLOR, LINEAR_WEIGHTED_DISTANCE, SQUARE_WEIGHTED_DISTANCE] class FrameInterpolation(StrEnum): SNAP = "SNAP" FADE = "FADE" + # options = [SNAP, FADE] class Cell: def __init__(self, position: Vector3, color: Vector3): @@ -68,7 +70,7 @@ def mesh_to_cell(mesh: Mesh) -> Cell: cell = Cell(pos, Vector3(mesh.face_color)) return cell -def scene_to_frame(scene: Scene, scene_number: int) -> str: +def scene_to_frame(scene: Scene, fill_interpolation: FillInterpolation, frame_interpolation: FrameInterpolation, delay: int, scene_number: int) -> str: cells = [mesh_to_cell(cube) for cube in scene.meshes] frame = AnimationFrame(cells, FillInterpolation.NO_FILL, FrameInterpolation.FADE, 1000) return frame.to_string(scene_number) \ No newline at end of file diff --git a/tools/animation-tools/CustomWidgets.py b/tools/animation-tools/CustomWidgets.py deleted file mode 100644 index 395baa8..0000000 --- a/tools/animation-tools/CustomWidgets.py +++ /dev/null @@ -1,18 +0,0 @@ -from pygame_widgets.slider import Slider - -class ColorPicker: - def __init__(self, screen, x_pos: int, y_pos: int, width: int, height: int): - width = max(50, width) - self.sliders: list[Slider] = [ - Slider(screen, int(x_pos + i*(width/3)), y_pos, int((width-50)/3), height, min=0, max=255, step=1, vertical=True) for i in range(3) - ] - for slider in self.sliders: - slider.enable() - - def get_color(self) -> tuple[int]: - # return (0,0,0) - return tuple([slider.getValue() for slider in self.sliders]) - - def set_color(self, color: tuple[int]): - for i, slider in enumerate(self.sliders): - slider.setValue(color[i]) \ No newline at end of file diff --git a/tools/animation-tools/UI.py b/tools/animation-tools/UI.py index 5dca482..0651c96 100644 --- a/tools/animation-tools/UI.py +++ b/tools/animation-tools/UI.py @@ -1,15 +1,41 @@ -from AnimationExporter import scene_to_frame -from CustomWidgets import ColorPicker from itertools import product from pygame_widgets.button import Button +from pygame_widgets.slider import Slider +from pygame_widgets.dropdown import Dropdown +from pygame_widgets.textbox import TextBox from Scene import Scene from Shapes import * import pygame +from AnimationExporter import * +class ColorPicker: + def __init__(self, screen, x_pos: int, y_pos: int, width: int, height: int): + width = max(50, width) + slider_colors = ((255,0,0),(0,255,0),(0,0,255)) + self.sliders: list[Slider] = [ + Slider(screen, int(x_pos + i*(width/3)), y_pos, int((width-50)/3), height, min=0, max=255, step=1, vertical=True, handleColour=slider_colors[i]) for i in range(3) + ] + for slider in self.sliders: + slider.enable() + + def get_color(self) -> tuple[int]: + return tuple([slider.getValue() for slider in self.sliders]) + + def set_color(self, color: tuple[int]): + for i, slider in enumerate(self.sliders): + slider.setValue(color[i]) + +class SceneStore: + def __init__(self, scene: Scene, fill: FillInterpolation, fade: FrameInterpolation, delay: int): + self.scene: Scene = scene + self.fill: FillInterpolation = fill + self.fade: FrameInterpolation = fade + self.delay: int = delay + class SceneManager: def __init__(self, window, color_picker: ColorPicker): self.file_data: str = "" - self._scenes: list[Scene] = [self.new_scene()] + self._scenes: list[SceneStore] = [SceneStore(self.new_scene(), FillInterpolation.NO_FILL, FrameInterpolation.FADE, 1000)] self._current_scene_idx: int = 0 self.window = window self.color_picker = color_picker @@ -18,7 +44,7 @@ class SceneManager: def save_frame_to_file(self): with open("tools/animation-tools/output.txt", 'w') as file: for i, scene in enumerate(self._scenes): - file.write(scene_to_frame(scene, i)) + file.write(scene_to_frame(scene.scene, scene.fill_interpolation, scene.frame_interpolation, scene.delay, i)) def generate_meshes(self) -> list[Mesh]: # generate a list of cubes @@ -37,13 +63,13 @@ class SceneManager: def draw(self): for mesh in self._selected_meshes: mesh.set_face_color(self.color_picker.get_color()) - self.get_current_scene().draw(self.window) + self.get_current_scene().scene.draw(self.window) - def get_current_scene(self) -> Scene: + def get_current_scene(self) -> SceneStore: return self._scenes[self._current_scene_idx] def click_mesh(self, coordinates: tuple[int, int]): - mesh = self.get_current_scene().get_mesh_from_xy(coordinates) + mesh = self.get_current_scene().scene.get_mesh_from_xy(coordinates) if mesh == None: return @@ -62,34 +88,60 @@ class SceneManager: def next_scene(self): self.deselect_all_mesh() - current_angles = self.get_current_scene().euler_angles + current_angles = self.get_current_scene().scene.euler_angles if len(self._scenes)-1 == self._current_scene_idx: - self._scenes.append(self.new_scene()) + self._scenes.append(SceneStore(self.new_scene(), FillInterpolation.NO_FILL, FrameInterpolation.FADE, 1000)) self._current_scene_idx += 1 - self.get_current_scene().euler_angles = [angle for angle in current_angles] + self.get_current_scene().scene.euler_angles = [angle for angle in current_angles] - def previous_scene(self): + def last_scene(self): if self._current_scene_idx > 0: - current_angles = self.get_current_scene().euler_angles + current_angles = self.get_current_scene().scene.euler_angles self._current_scene_idx -= 1 - self.get_current_scene().euler_angles = [angle for angle in current_angles] + self.get_current_scene().scene.euler_angles = [angle for angle in current_angles] self.deselect_all_mesh() - + + def update_scene_options(self, fill: FillInterpolation, fade: FrameInterpolation, delay: int): + cur_scene: SceneStore = self.get_current_scene() + cur_scene.fill = fill + cur_scene.fade = fade + cur_scene.delay = delay + class AnimatorUI: def __init__(self, window): scr_wdt, scr_hgt = window.get_size() self.window = window - colorPicker: ColorPicker = ColorPicker(self.window, 20, 20, 100, 300) - self.sceneManager: SceneManager = SceneManager(window, colorPicker) + self.colorPicker: ColorPicker = ColorPicker(self.window, *self.rel2abs(5, 5, 20, 60)) + self.sceneManager: SceneManager = SceneManager(window, self.colorPicker) - - self.save_button: Button = Button(self.window, 20, scr_hgt-40, 60, 30, text="Save",onClick=self.sceneManager.save_frame_to_file) - self.next_frame_button: Button = Button(self.window, scr_wdt-120, scr_hgt-40, 120, 30, text="Next Frame",onClick=self.sceneManager.next_scene) - self.last_frame_button: Button = Button(self.window, scr_wdt-240, scr_hgt-40, 120, 30, text="last Frame",onClick=self.sceneManager.previous_scene) + self.save_button: Button = Button(self.window, *self.rel2abs(5, 90, 10, 10), text="Save",onClick=self.sceneManager.save_frame_to_file) + self.next_frame_button: Button = Button(self.window, *self.rel2abs(75, 90, 25, 5), text="Next Frame",onClick=self._next_scene) + self.last_frame_button: Button = Button(self.window, *self.rel2abs(50, 90, 25, 5), text="last Frame",onClick=self._last_scene) self.trackMouseMotion: bool = False + + self.fill_dropdown: Dropdown = Dropdown(self.window, *self.rel2abs(30, 0, 40, 5), name="Fill Type", + choices=[option.value for option in FillInterpolation], onRelease=self.set_update_options_flag) + + self.fade_dropdown: Dropdown = Dropdown(self.window, *self.rel2abs(70, 0, 20, 5), name="Fade Type", + choices=[option.value for option in FrameInterpolation], onRelease=self.set_update_options_flag) + + self.updateOptions = False + self._set_dropdown_options() + + # TODO: add delay field + # TODO: Make a frame counter + + def rel2abs(self, x: float, y: float, width: float, height: float) -> tuple[int,int,int,int]: + scr_wdt, scr_hgt = self.window.get_size() + x_abs = int(x*scr_wdt/100) + y_abs = int(y*scr_hgt/100) + w_abs = int(width*scr_wdt/100) + h_abs = int(height*scr_hgt/100) + return (x_abs, y_abs, w_abs, h_abs) + def update_interaction(self, game_event): if not self.trackMouseMotion: @@ -110,4 +162,39 @@ class AnimatorUI: current_scene.euler_angles[1] -= mouseMovement[0] def draw(self): - self.sceneManager.draw() \ No newline at end of file + if self.updateOptions: + self.set_scene_options() + # make the preview window for the color picker + pygame.draw.rect(self.window, self.colorPicker.get_color(), self.rel2abs(11, 70, 5, 5)) + pygame.draw.rect(self.window, (0,0,0), self.rel2abs(11, 70, 5, 5), 2) + + self.sceneManager.draw() + + def _next_scene(self): + self.sceneManager.next_scene() + self._set_dropdown_options() + + + def _last_scene(self): + self.sceneManager.last_scene() + self._set_dropdown_options() + + def _set_dropdown_options(self): + scene = self.sceneManager.get_current_scene() + for choice in self.fill_dropdown._Dropdown__choices: + if choice.text.find(scene.fill) != -1: + self.fill_dropdown.chosen = choice + break + + for choice in self.fade_dropdown._Dropdown__choices: + if choice.text.find(scene.fade) != -1: + self.fade_dropdown.chosen = choice + break + + def set_update_options_flag(self): + self.updateOptions = True + + def set_scene_options(self): + self.updateOptions = False + self.sceneManager.update_scene_options(self.fill_dropdown.getSelected(), self.fade_dropdown.getSelected(), 1000) + current_scene = self.sceneManager.get_current_scene() \ No newline at end of file diff --git a/tools/animation-tools/animation-tool.py b/tools/animation-tools/animation-tool.py index 8d683c3..b642227 100644 --- a/tools/animation-tools/animation-tool.py +++ b/tools/animation-tools/animation-tool.py @@ -1,7 +1,6 @@ import pygame import pygame_widgets from Shapes import * -from Scene import Scene from UI import AnimatorUI WINDOW_W = 500