NouVeL/ADVect/Track.h
2023-04-06 19:50:37 -04:00

140 lines
5.2 KiB
C++

#pragma once
#include <Common.h>
#include <Environment.h>
#include "Graphics.h"
namespace ADVect {
template <typename T>
struct Varying {
u64 begin = 0, duration = 0;
std::function<T(f32)> interp;
bool done = true;
T get(u64 current_time) const {
if (done)
return interp(1.f);
else
return interp((current_time - begin) / static_cast<f32>(duration));
}
void kickoff(u64 current_time, u64 dur, const std::function<T(f32)>& f = [](f32 x) { return static_cast<T>(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;
}
};
// TODO maybe make this cleaner (packing?)
template <typename T, bool UsePointer, bool IsNamed, bool IsVisual, bool IsVisualFill, bool HasTransition>
struct Track {
std::conditional_t<UsePointer, T*, T> current{};
// [[no_unique_address]] std::conditional_t<IsNamed, std::string, std::monostate> name{};
std::conditional_t<IsNamed, std::string, std::monostate> name{};
// Visual
// [[no_unique_address]] std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{};
// [[no_unique_address]] std::conditional_t<IsVisual, u32, std::monostate> w{}, h{};
// [[no_unique_address]] std::conditional_t<IsVisual, f32, std::monostate> opacity{};
std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{};
std::conditional_t<IsVisual, u32, std::monostate> w{}, h{};
std::conditional_t<IsVisual, f32, std::monostate> opacity{};
// TODO other transforms
// Fill
static_assert(IsVisual || !IsVisualFill, "Track cannot have fill unless visual");
// [[no_unique_address]] std::conditional_t<IsVisualFill, u32, std::monostate> fill{};
std::conditional_t<IsVisualFill, u32, std::monostate> fill{};
// Transition, with assumption that we need to access the original when transition is underway
// [[no_unique_address]] std::conditional_t<HasTransition, std::conditional_t<UsePointer, T*, T>, std::monostate> next{};
// [[no_unique_address]] std::conditional_t<HasTransition, Varying<f32>, std::monostate> transition{};
std::conditional_t<HasTransition, std::conditional_t<UsePointer, T*, T>, std::monostate> next{};
std::conditional_t<HasTransition, Varying<f32>, 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<UsePointer, T*, T> n, u64 dur, const std::function<f32(f32)>& 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<typename T, bool UsePointer>
using VisualTrack = Track<T, UsePointer, false, true, false, false>;
template<typename T, bool UsePointer>
using VisualTransitionTrack = Track<T, UsePointer, false, true, false, true>;
template<typename T, bool UsePointer>
using FillVisualTrack = Track<T, UsePointer, false, true, true, false>;
template<typename T, bool UsePointer>
using FillVisualTransitionTrack = Track<T, UsePointer, false, true, true, true>;
/* TODO impl
struct AudioTrack {};
*/
using TextTrack = FillVisualTrack<NVL::String, false>;
using MarkupTextTrack = FillVisualTrack<NVL::Environment::MarkupString, false>;
using MarkupTextTransitionTrack = FillVisualTransitionTrack<NVL::Environment::MarkupString, false>;
using ImageTrack = VisualTrack<ADVect::Graphics::ImageTexture, true>;
using ImageTransitionTrack = VisualTransitionTrack<ADVect::Graphics::ImageTexture, true>;
/* TODO VideoTrack */
void draw_typewriter(u64 current_time, const MarkupTextTransitionTrack& t) {
if (t.transition.done)
ADVect::Graphics::RenderStringMarkupWrap(t.current, t.pos_x, t.pos_y, t.w, t.fill);
else
ADVect::Graphics::RenderStringMarkupWrap(t.next.substr(t.transition.get(current_time)), t.pos_x, t.pos_y, t.w, t.fill);
}
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);
}
}
}
}