#pragma once #include #include #include "Graphics.h" namespace ADVect { template struct Varying { u64 begin = 0, duration = 0; std::function interp; bool done = true; T get(u64 current_time) const { if (done) return interp(1.f); else return interp((current_time - begin) / static_cast(duration)); } void kickoff(u64 current_time, u64 dur, const std::function& f = [](f32 x) { return static_cast(x); }) { begin = current_time; done = false; duration = dur; interp = f; } bool check(u64 current_time) { if (done) return true; else if (current_time >= begin + duration) { done = true; return true; } else return false; } }; template struct Track { std::conditional_t current{}; // [[no_unique_address]] std::conditional_t name{}; std::conditional_t name{}; // Visual // [[no_unique_address]] std::conditional_t pos_x{}, pos_y{}; // [[no_unique_address]] std::conditional_t w{}, h{}; // [[no_unique_address]] std::conditional_t opacity{}; std::conditional_t pos_x{}, pos_y{}; std::conditional_t w{}, h{}; std::conditional_t opacity{}; // TODO other transforms // Fill static_assert(IsVisual || !IsVisualFill, "Track cannot have fill unless visual"); // [[no_unique_address]] std::conditional_t fill{}; std::conditional_t fill{}; // Transition, with assumption that we need to access the original when transition is underway // [[no_unique_address]] std::conditional_t, std::monostate> next{}; // [[no_unique_address]] std::conditional_t, std::monostate> transition{}; std::conditional_t, std::monostate> next{}; std::conditional_t, std::monostate> transition{}; void check(u64 current_time) requires HasTransition { if constexpr (UsePointer) { if (next != nullptr && transition.check(current_time)) { current = next; next = nullptr; } } else { if (transition.check(current_time)) current = next; } } void change(u64 current_time, const std::conditional_t n, u64 dur, const std::function& f = [](f32 x) { return x; }) requires HasTransition { if constexpr (UsePointer) { if (current == nullptr) current = n; else if (n == nullptr) current = n; else { next = n; transition.kickoff(current_time, dur, f); } } else { next = n; transition.kickoff(current_time, dur, f); } } }; template using VisualTrack = Track; template using VisualTransitionTrack = Track; template using FillVisualTrack = Track; template using FillVisualTransitionTrack = Track; /* TODO impl struct AudioTrack {}; */ using TextTrack = FillVisualTrack; using MarkupTextTrack = FillVisualTrack; using MarkupTextTransitionTrack = FillVisualTransitionTrack; using ImageTrack = VisualTrack; using ImageTransitionTrack = VisualTransitionTrack; /* TODO VideoTrack */ void draw_typewriter(u64 current_time, const MarkupTextTransitionTrack& t) { if (t.transition.done) ADVect::Graphics::RenderSubstringMarkupBox(t.current, t.pos_x, t.pos_y, t.w, t.fill); else ADVect::Graphics::RenderSubstringMarkupBox(t.next, t.pos_x, t.pos_y, t.w, t.fill, t.transition.get(current_time)); } void draw_image_transition_fade(u64 current_time, const ImageTransitionTrack& t) { if (t.current != nullptr) { if (t.next != nullptr) { ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.transition.get(current_time)); } else { ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); } } } void draw_image_transition_crossfade(u64 current_time, const ImageTransitionTrack& t) { if (t.current != nullptr) { if (t.next != nullptr) { ADVect::Graphics::DrawTextureImageAlpha(*t.current, t.pos_x, t.pos_y, 1.0f - t.transition.get(current_time)); ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.transition.get(current_time)); } else { ADVect::Graphics::DrawTextureImageAlpha(*t.current, t.pos_x, t.pos_y, 1.0f); } } } }