Browse Source

Get animation system working

master
C. J. Howard 3 years ago
parent
commit
1c4759badb
25 changed files with 526 additions and 105 deletions
  1. +30
    -1
      src/animation/animation.cpp
  2. +192
    -21
      src/animation/animation.hpp
  3. +23
    -1
      src/animation/animator.cpp
  4. +12
    -2
      src/animation/animator.hpp
  5. +2
    -2
      src/animation/timeline.cpp
  6. +7
    -11
      src/animation/timeline.hpp
  7. +50
    -31
      src/animation/tween.hpp
  8. +56
    -14
      src/application.cpp
  9. +5
    -0
      src/application.hpp
  10. +18
    -0
      src/debug/console-commands.cpp
  11. +4
    -0
      src/debug/console-commands.hpp
  12. +44
    -11
      src/renderer/material-property.hpp
  13. +10
    -2
      src/renderer/material.cpp
  14. +7
    -1
      src/renderer/material.hpp
  15. +1
    -1
      src/renderer/passes/material-pass.cpp
  16. +1
    -1
      src/renderer/simple-render-pass.cpp
  17. +10
    -0
      src/resources/resource-manager.cpp
  18. +5
    -0
      src/resources/resource-manager.hpp
  19. +10
    -1
      src/scene/billboard.cpp
  20. +3
    -0
      src/scene/billboard.hpp
  21. +28
    -1
      src/scene/model-instance.cpp
  22. +2
    -0
      src/scene/model-instance.hpp
  23. +1
    -1
      src/state/splash-state.cpp
  24. +1
    -1
      src/state/title-state.cpp
  25. +4
    -2
      src/timestamp.cpp

+ 30
- 1
src/animation/animation.cpp View File

@ -19,5 +19,34 @@
#include "animation.hpp"
void animation_base::animate(float dt)
animation_base::animation_base():
position(0.0f),
start_callback(nullptr),
end_callback(nullptr),
loop_callback(nullptr)
{}
void animation_base::seek(double t)
{
position = t;
}
void animation_base::reset()
{
seek(0.0);
}
void animation_base::set_start_callback(std::function<void()> callback)
{
start_callback = callback;
}
void animation_base::set_end_callback(std::function<void()> callback)
{
end_callback = callback;
}
void animation_base::set_loop_callback(std::function<void()> callback)
{
loop_callback = callback;
}

+ 192
- 21
src/animation/animation.hpp View File

@ -21,44 +21,215 @@
#define ANTKEEPER_ANIMATION_HPP
#include <functional>
#include <set>
#include <tuple>
#include <type_traits>
class animation_channel_base
/**
* Abstract base class for animations.
*/
class animation_base
{
public:
animation_base();
/**
* Advances the animation position (t) by @p dt.
*
* @param dt Delta time by which the animation position will be advanced.
*/
virtual void advance(double dt) = 0;
/**
* Sets the animation position to @p t.
*
* @param t Position in time to which the animation position will be set.
*/
void seek(double t);
void reset();
/// Returns the current position in time of the animation.
double get_position() const;
/// Sets the callback that's executed when the animation is started.
void set_start_callback(std::function<void()> callback);
/// Sets the callback that's executed when the animation ends.
void set_end_callback(std::function<void()> callback);
/// Sets the callback that's executed when the animation loops.
void set_loop_callback(std::function<void()> callback);
protected:
double position;
std::function<void()> start_callback;
std::function<void()> end_callback;
std::function<void()> loop_callback;
};
/**
* Templated keyframe animation class.
*/
template <typename T>
class animation_channel: public animation_channel_base
class animation: public animation_base
{
public:
void insert_keyframe(float position, const T& value);
/// Scheduled function consisting of a time and function object.
typedef std::tuple<double, T> keyframe;
/// Interpolator function type.
typedef typename std::decay<std::function<T(const T&, const T&, double)>>::type interpolator_type;
/// Creates an animation
animation();
/// @copydoc animation_base::advance()
virtual void advance(double dt);
/**
* Adds a keyframe to the animation.
*
* @param k Keyframe to add.
*/
void insert_keyframe(const keyframe& k);
/**
* Removes all keyframes on `[start, end)`.
*
* @param start Starting position in time (inclusive).
* @param end Ending position in time (non-inclusive).
*/
void remove_keyframes(double start, double end);
/**
* Returns all the keyframes on `[start, end)`.
*
* @param start Starting position in time (inclusive).
* @param end Ending position in time (non-inclusive).
* @return All keyframes on `[start, end)`.
*/
std::list<keyframe> get_keyframes(double start, double end) const;
/// Removes all keyframes from the animation.
void clear();
/**
* Sets the frame interpolator function object.
*
* @param interpolator Frame interpolator function object.
*/
void set_interpolator(interpolator_type interpolator);
/**
* Sets the callback that's executed on each frame of animation.
*
* @param callback Frame callback which receives the value of the interpolated frames.
*/
void set_frame_callback(std::function<void(const T&)> callback);
private:
//static bool keyframe_compare(const keyframe& a, const keyframe & b);
struct keyframe_compare
{
inline bool operator()(const keyframe& lhs, const keyframe& rhs) const
{
return std::get<0>(lhs) < std::get<0>(rhs);
}
};
interpolator_type interpolator;
std::function<void(const T&)> frame_callback;
std::set<keyframe, keyframe_compare> keyframes;
};
class animation_base
/*
template <typename T>
bool animation<T>::keyframe_compare(const keyframe& a, const keyframe & b)
{
public:
void animate(float dt);
};
return std::get<0>(a) < std::get<0>(b);
}
*/
template <typename T>
class animation: public animation_base
animation<T>::animation():
interpolator(nullptr),
frame_callback(nullptr),
keyframes(keyframe_compare())
{}
template <typename T>
void animation<T>::advance(double dt)
{
public:
void set_start_callback(std::function<void()> callback);
void set_end_callback(std::function<void()> callback);
void set_loop_callback(std::function<void()> callback);
void set_frame_callback(std::function<void(std::size_t, const T&)> callback);
position += dt;
if (frame_callback != nullptr && interpolator != nullptr)
{
auto upper_bound = keyframes.upper_bound({position, T()});
auto lower_bound = upper_bound;
--lower_bound;
if (lower_bound != keyframes.end() && upper_bound != keyframes.end())
{
// Calculate interpolated frame
double t0 = std::get<0>(*lower_bound);
double t1 = std::get<0>(*upper_bound);
double alpha = (position - t0) / (t1 - t0);
T frame = interpolator(std::get<1>(*lower_bound), std::get<1>(*upper_bound), alpha);
// Pass frame to frame callback
frame_callback(frame);
}
}
}
private:
std::function<void()> start_callback;
std::function<void()> end_callback;
std::function<void()> loop_callback;
std::function<void(std::size_t, const T&)> motion_callback;
};
template <typename T>
void animation<T>::insert_keyframe(const keyframe& k)
{
keyframes.emplace(k);
}
class skeletal_animation: public animation<int>
template <typename T>
void animation<T>::remove_keyframes(double start, double end)
{
auto lower_bound = keyframes.lower_bound({start, T()});
auto upper_bound = keyframes.upper_bound({end, T()});
keyframes.erase(lower_bound, upper_bound);
}
};
template <typename T>
std::list<typename animation<T>::keyframe> animation<T>::get_keyframes(double start, double end) const
{
std::list<keyframe> keyframe_list;
auto lower_bound = keyframes.lower_bound({start, T()});
auto upper_bound = keyframes.upper_bound({end, T()});
for (auto iterator = lower_bound; iterator != upper_bound; ++iterator)
{
keyframe_list.push_back(*iterator);
}
return keyframe_list;
}
template <typename T>
void animation<T>::clear()
{
keyframes.clear();
}
template <typename T>
void animation<T>::set_interpolator(interpolator_type interpolator)
{
this->interpolator = interpolator;
}
template <typename T>
void animation<T>::set_frame_callback(std::function<void(const T&)> callback)
{
this->frame_callback = callback;
}
#endif // ANTKEEPER_ANIMATION_HPP

+ 23
- 1
src/animation/animator.cpp View File

@ -18,9 +18,31 @@
*/
#include "animator.hpp"
#include "animation/animation.hpp"
void animator::animate(float dt)
void animator::animate(double dt)
{
for (animation_base* animation: animations)
{
animation->advance(dt);
}
}
void animator::add_animation(animation_base* animation)
{
animations.emplace(animation);
}
void animator::remove_animation(animation_base* animation)
{
auto it = animations.find(animation);
if (it != animations.end())
{
animations.erase(it);
}
}
void animator::remove_animations()
{
animations.clear();
}

+ 12
- 2
src/animation/animator.hpp View File

@ -20,6 +20,10 @@
#ifndef ANTKEEPER_ANIMATOR_HPP
#define ANTKEEPER_ANIMATOR_HPP
#include <set>
class animation_base;
class animator
{
public:
@ -28,8 +32,14 @@ public:
*
* @param dt Delta time by which the animations will be progressed.
*/
void animate(float dt);
void animate(double dt);
void add_animation(animation_base* animation);
void remove_animation(animation_base* animation);
void remove_animations();
private:
std::set<animation_base*> animations;
};
#endif // ANTKEEPER_ANIMATOR_HPP

+ 2
- 2
src/animation/timeline.cpp View File

@ -19,7 +19,7 @@
#include "timeline.hpp"
auto cue_compare = [](const cue& a, const cue& b)
auto cue_compare = [](const typename timeline::cue& a, const typename timeline::cue& b)
{
return std::get<0>(a) < std::get<0>(b);
};
@ -96,7 +96,7 @@ void timeline::set_autoremove(bool enabled)
autoremove = enabled;
}
sequence timeline::get_cues(float start, float end)
typename timeline::sequence timeline::get_cues(float start, float end) const
{
sequence s;

+ 7
- 11
src/animation/timeline.hpp View File

@ -24,22 +24,18 @@
#include <set>
#include <tuple>
/**
* Scheduled function consisting of a time and function object.
*/
typedef std::tuple<float, std::function<void()>> cue;
/**
* List of cues.
*/
typedef std::list<cue> sequence;
/**
* Timeline which executes cues (scheduled functions) when advanced over their respective positions in time.
*/
class timeline
{
public:
/// Scheduled function consisting of a time and function object.
typedef std::tuple<float, std::function<void()>> cue;
/// List of cues.
typedef std::list<cue> sequence;
/**
* Creates a timeline.
*/
@ -119,7 +115,7 @@ public:
* @param end Ending position in time (non-inclusive).
* @return All cues on `[start, end)`.
*/
sequence get_cues(float start, float end);
sequence get_cues(float start, float end) const;
private:
std::multiset<cue, std::function<bool(const cue&, const cue&)>> cues;

+ 50
- 31
src/animation/tween.hpp View File

@ -33,21 +33,21 @@
* @return Interpolated value.
*/
template <class T>
T tween_default_lerp(const T& x, const T& y, float a);
T tween_default_interpolator(const T& x, const T& y, double a);
/**
* Container which stores two states along with an interpolator, for quick and easy tweening.
*
* @tparam T Value type.
* @tparam Interpolator Interpolator function or function object type.
*/
template <class T, class Interpolator = typename std::function<std::remove_pointer<T>::type(const T&, const T&, float)>>
template <class T>
class tween
{
public:
typedef typename std::remove_pointer<T>::type value_type;
typedef typename std::decay<Interpolator>::type interpolator_type;
//typedef typename std::remove_pointer<T>::type value_type;
typedef T value_type;
typedef typename std::decay<std::function<value_type(const T&, const T&, double)>>::type interpolator_type;
/**
* Creates a tween.
*
@ -55,7 +55,7 @@ public:
* @param state1 Initial value of state 1.
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1.
*/
explicit tween(const T& state0, const T& state1, const interpolator_type& interpolator = tween_default_lerp<T>);
explicit tween(const T& state0, const T& state1, const interpolator_type& interpolator = tween_default_interpolator<T>);
/**
* Creates a tween.
@ -63,14 +63,14 @@ public:
* @param value Initial value of states 0 and 1.
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1.
*/
explicit tween(const T& value, const interpolator_type& interpolator = tween_default_lerp<T>);
explicit tween(const T& value, const interpolator_type& interpolator = tween_default_interpolator<T>);
/**
* Creates a tween.
*
* @param interpolator Function or function object that will be used to interpolate between states 0 and 1.
*/
explicit tween(const interpolator_type& interpolator = tween_default_lerp<T>);
explicit tween(const interpolator_type& interpolator = tween_default_interpolator<T>);
/**
* Returns a reference to the specified tween state.
@ -89,7 +89,14 @@ public:
* @param a Interpolation factor. Should be on `[0.0, 1.0]`.
* @return Interpolated state.
*/
value_type interpolate(float a) const;
value_type interpolate(double a) const;
/**
* Sets the function object used to interpolate between states 0 and 1.
*
* @param interpolator Interpolator function object.
*/
void set_interpolator(const interpolator_type& interpolator);
/**
* Returns the function or function object that is used to interpolate between states 0 and 1.
@ -113,65 +120,77 @@ private:
};
template <class T>
inline T tween_default_lerp(const T& x, const T& y, float a)
inline T tween_default_interpolator(const T& x, const T& y, double a)
{
return x * (1.0f - a) + y * a;
//return x * (1.0 - a) + y * a;
return y;
}
template <class T, class Interpolator>
tween<T, Interpolator>::tween(const T& value, const interpolator_type& interpolator):
template <>
inline float tween_default_interpolator<float>(const float& x, const float& y, double a)
{
return (y - x) * a + x;
}
template <class T>
tween<T>::tween(const T& value, const interpolator_type& interpolator):
interpolator(interpolator),
state0(value),
state1(value)
{}
template <class T, class Interpolator>
tween<T, Interpolator>::tween(const T& state0, const T& state1, const interpolator_type& interpolator):
template <class T>
tween<T>::tween(const T& state0, const T& state1, const interpolator_type& interpolator):
interpolator(interpolator),
state0(state0),
state1(state1)
{}
template <class T, class Interpolator>
tween<T, Interpolator>::tween(const interpolator_type& interpolator):
template <class T>
tween<T>::tween(const interpolator_type& interpolator):
interpolator(interpolator)
{}
template <class T, class Interpolator>
inline const T& tween<T, Interpolator>::operator[](int state) const
template <class T>
inline const T& tween<T>::operator[](int state) const
{
return (state <= 0) ? state0 : state1;
}
template <class T, class Interpolator>
inline T& tween<T, Interpolator>::operator[](int state)
template <class T>
inline T& tween<T>::operator[](int state)
{
return (state <= 0) ? state0 : state1;
}
template <class T, class Interpolator>
inline typename tween<T, Interpolator>::value_type tween<T, Interpolator>::interpolate(float a) const
template <class T>
inline typename tween<T>::value_type tween<T>::interpolate(double a) const
{
return interpolator(state0, state1, a);
}
template <class T, class Interpolator>
inline const typename tween<T, Interpolator>::interpolator_type& tween<T, Interpolator>::get_interpolator() const
template <class T>
inline void tween<T>::set_interpolator(const interpolator_type& interpolator)
{
this->interpolator = interpolator;
}
template <class T>
inline const typename tween<T>::interpolator_type& tween<T>::get_interpolator() const
{
return interpolator;
}
template <class T, class Interpolator>
inline void tween<T, Interpolator>::update()
template <class T>
inline void tween<T>::update()
{
state0 = state1;
}
template <class T, class Interpolator>
inline void tween<T, Interpolator>::swap()
template <class T>
inline void tween<T>::swap()
{
std::swap(state0, state1);
}
#endif // ANTKEEPER_TWEEN_HPP

+ 56
- 14
src/application.cpp View File

@ -75,6 +75,7 @@
#include "renderer/material-property.hpp"
// Animation
#include "animation/animation.hpp"
#include "animation/animator.hpp"
// Scene
@ -100,6 +101,24 @@
// Entity components
#include "entity/components/cavity-component.hpp"
template <typename T>
inline T ease_linear(const T& x, const T& y, double a)
{
return (y - x) * a + x;
}
template <typename T>
T ease_in_quad(const T& x, const T& y, double a)
{
return (y - x) * a * a + x;
}
template <typename T>
T ease_out_quad(const T& x, const T& y, double a)
{
return -(y - x) * a * (a - 2.0f) + x;
}
using namespace vmq::operators;
application::application(int argc, char** argv):
@ -156,6 +175,15 @@ application::application(int argc, char** argv):
}
}
// Register CLI commands
cli.register_command("echo", cc::echo);
cli.register_command("exit", std::function<std::string()>(std::bind(&cc::exit, this)));
cli.register_command("scrot", std::function<std::string()>(std::bind(&cc::scrot, this)));
cli.register_command("cue", std::function<std::string(float, std::string)>(std::bind(&cc::cue, this, std::placeholders::_1, std::placeholders::_2)));
//std::string cmd = "cue 20 exit";
//logger.log(cmd + "\n");
//logger.log(cli.interpret(cmd) + "\n");
// Setup resource manager
resource_manager = new ::resource_manager();
resource_manager->set_logger(&logger);
@ -229,9 +257,10 @@ application::application(int argc, char** argv):
int window_height = 1080;
fullscreen = true;
window_width = 1280;
window_height = 720;
fullscreen = false;
//window_width = 1280;
//window_height = 720;
//fullscreen = false;
viewport = {0.0f, 0.0f, static_cast<float>(window_width), static_cast<float>(window_height)};
int window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
@ -446,8 +475,23 @@ application::application(int argc, char** argv):
underworld_final_pass = new simple_render_pass(rasterizer, &rasterizer->get_default_framebuffer(), underworld_final_shader);
underworld_final_pass->set_time_tween(&time);
underground_transition_property = underworld_final_pass->get_material()->add_property<float>("transition");
underground_transition_property->set_value(0.0f);
underground_color_texture_property = underworld_final_pass->get_material()->add_property<const texture_2d*>("color_texture");
underground_color_texture_property->set_value(framebuffer_hdr_color);
underworld_final_pass->get_material()->update_tweens();
float radial_transition_time = 0.5f;
radial_transition_in = new animation<float>();
radial_transition_in->insert_keyframe({0.0f, 0.0f});
radial_transition_in->insert_keyframe({radial_transition_time, 1.0f});
radial_transition_in->set_frame_callback(std::bind(&material_property<float>::set_val, underground_transition_property, std::placeholders::_1));
radial_transition_in->set_interpolator(ease_in_quad<float>);
radial_transition_out = new animation<float>();
radial_transition_out->insert_keyframe({0.0f, 1.0f});
radial_transition_out->insert_keyframe({radial_transition_time, 0.0f});
radial_transition_out->set_frame_callback(std::bind(&material_property<float>::set_val, underground_transition_property, std::placeholders::_1));
radial_transition_out->set_interpolator(ease_out_quad<float>);
// Setup underworld compositor
underworld_compositor.add_pass(underworld_clear_pass);
@ -497,7 +541,7 @@ application::application(int argc, char** argv):
model_system = new ::model_system(ecs_registry, overworld_scene);
// Setup systems
systems.push_back([this](double t, double dt){ this->overworld_scene.update_tweens(); this->underworld_scene.update_tweens(); this->ui_system->get_scene()->update_tweens(); focal_point_tween.update(); });
systems.push_back([this](double t, double dt){ this->overworld_scene.update_tweens(); this->underworld_scene.update_tweens(); this->ui_system->get_scene()->update_tweens(); focal_point_tween.update(); this->underworld_final_pass->get_material()->update_tweens(); });
systems.push_back([this](double t, double dt){ this->translate_sdl_events(); });
systems.push_back([this](double t, double dt){ this->event_dispatcher.update(t); });
systems.push_back([this](double t, double dt){ this->timeline.advance(dt); });
@ -627,13 +671,19 @@ application::application(int argc, char** argv):
//this->overworld_camera.set_active(false);
this->underworld_camera.set_active(true);
this->active_scene = &this->underworld_scene;
this->animator->remove_animation(this->radial_transition_out);
this->animator->add_animation(this->radial_transition_in);
this->radial_transition_in->reset();
}
else
{
// Switch to overworld
this->underworld_camera.set_active(false);
//this->underworld_camera.set_active(false);
this->overworld_camera.set_active(true);
this->active_scene = &this->overworld_scene;
this->animator->remove_animation(this->radial_transition_in);
this->animator->add_animation(this->radial_transition_out);
this->radial_transition_out->reset();
}
});
@ -801,14 +851,6 @@ application::application(int argc, char** argv):
// Set overworld as active scene
active_scene = &overworld_scene;
// Setup debug CLI
cli.register_command("echo", cc::echo);
cli.register_command("exit", std::function<std::string()>(std::bind(&cc::exit, this)));
std::string cmd = "echo abc 123";
logger.log(cmd + "\n");
logger.log(cli.interpret(cmd) + "\n");
}
application::~application()
@ -830,7 +872,7 @@ void application::close(int status)
int application::execute()
{
// Enter inital state
state_machine.change_state(splash_state);
state_machine.change_state(play_state);
// Perform initial update
update(0.0, 0.0);

+ 5
- 0
src/application.hpp View File

@ -116,6 +116,9 @@
template <class T>
class material_property;
template <class T>
class animation;
//}
class application
@ -206,6 +209,8 @@ private:
// Updatable systems
timeline timeline;
animator* animator;
animation<float>* radial_transition_in;
animation<float>* radial_transition_out;
std::list<std::function<void(double, double)>> systems;
int shadow_map_resolution;

+ 18
- 0
src/debug/console-commands.cpp View File

@ -19,6 +19,8 @@
#include "console-commands.hpp"
#include "application.hpp"
#include "animation/timeline.hpp"
#include "debug/cli.hpp"
namespace cc
{
@ -34,4 +36,20 @@ std::string exit(application* app)
return std::string();
}
std::string scrot(application* app)
{
app->take_screenshot();
return std::string("screenshot saved");
}
std::string cue(application* app, float t, std::string command)
{
::timeline* timeline = app->get_timeline();
::cli* cli = app->get_cli();
timeline->add_cue({timeline->get_position() + t, std::function<void()>(std::bind(&::cli::interpret, cli, command))});
return std::string("command \"" + command + "\" will execute in " + std::to_string(t) + " seconds");
}
} // namespace cc

+ 4
- 0
src/debug/console-commands.hpp View File

@ -31,6 +31,10 @@ std::string echo(std::string text);
std::string exit(application* app);
std::string scrot(application* app);
std::string cue(application* app, float t, std::string command);
} // namespace cc
#endif // ANTKEEPER_CONSOLE_COMMANDS_HPP

+ 44
- 11
src/renderer/material-property.hpp View File

@ -20,6 +20,7 @@
#ifndef ANTKEEPER_MATERIAL_PROPERTY_HPP
#define ANTKEEPER_MATERIAL_PROPERTY_HPP
#include "animation/tween.hpp"
#include "rasterizer/shader-variable-type.hpp"
#include "rasterizer/shader-input.hpp"
#include <vmq/vmq.hpp>
@ -50,13 +51,19 @@ public:
* Disconnects the material property from its shader input.
*/
void disconnect();
/**
* Sets state 0 = state 1.
*/
virtual void update_tweens() = 0;
/**
* Uploads the material property to its shader program.
*
* @param a Interpolation factor. Should be on `[0.0, 1.0]`.
* @return `true` if the property was uploaded successfully, `false` otherwise.
*/
virtual bool upload() const = 0;
virtual bool upload(double a) const = 0;
/**
* Returns the type of data which the property contains.
@ -107,9 +114,12 @@ public:
material_property(const material_property<T>&) = delete;
material_property<T>& operator=(const material_property<T>&) = delete;
/// @copydoc material_property_base::update_tweens()
virtual void update_tweens();
/// @copydoc material_property_base::upload() const
virtual bool upload() const;
virtual bool upload(double a) const;
/**
* Sets the value of this property.
@ -117,6 +127,7 @@ public:
* @param value Value to set.
*/
void set_value(const T& value);
void set_val(const T& value);
/**
* Sets the value of a single element in this array property.
@ -143,7 +154,7 @@ public:
private:
std::size_t element_count;
T* values;
tween<T>* values;
};
template <class T>
@ -151,7 +162,7 @@ material_property::material_property(std::size_t element_count):
element_count(element_count),
values(nullptr)
{
values = new T[element_count];
values = new tween<T>[element_count];
}
template <class T>
@ -161,7 +172,16 @@ material_property::~material_property()
}
template <class T>
bool material_property<T>::upload() const
void material_property<T>::update_tweens()
{
for (std::size_t i = 0; i < element_count; ++i)
{
values[i].update();
}
}
template <class T>
bool material_property<T>::upload(double a) const
{
if (!is_connected())
{
@ -170,24 +190,36 @@ bool material_property::upload() const
if (element_count > 1)
{
return input->upload(0, values, element_count);
for (std::size_t i = 0; i < element_count; ++i)
{
if (!input->upload(i, values[i].interpolate(a)))
return false;
}
return true;
}
else
{
return input->upload(values[0]);
return input->upload(values[0].interpolate(a));
}
}
template <class T>
void material_property<T>::set_value(const T& value)
{
values[0] = value;
values[0][1] = value;
}
template <class T>
void material_property<T>::set_val(const T& value)
{
values[0][1] = value;
}
template <class T>
void material_property<T>::set_value(std::size_t index, const T& value)
{
values[index] = value;
values[index][1] = value;
}
template <class T>
@ -195,7 +227,7 @@ void material_property::set_values(std::size_t index, const T* values, std::s
{
for (std::size_t i = 0; i < count; ++i)
{
this->values[index + i] = values[i];
this->values[index + i][1] = values[i];
}
}
@ -331,7 +363,8 @@ material_property_base* material_property::clone() const
material_property<T>* property = new material_property<T>(element_count);
for (std::size_t i = 0; i < element_count; ++i)
{
property->values[i] = values[i];
property->values[i][0] = values[i][0];
property->values[i][1] = values[i][1];
}
property->input = input;

+ 10
- 2
src/renderer/material.cpp View File

@ -64,7 +64,15 @@ material& material::operator=(const material& other)
return *this;
}
std::size_t material::upload() const
void material::update_tweens()
{
for (material_property_base* property: properties)
{
property->update_tweens();
}
}
std::size_t material::upload(double a) const
{
if (!program)
{
@ -75,7 +83,7 @@ std::size_t material::upload() const
for (material_property_base* property: properties)
{
if (!property->upload())
if (!property->upload(a))
{
++failed_upload_count;
}

+ 7
- 1
src/renderer/material.hpp View File

@ -65,13 +65,19 @@ public:
* @return Reference to this material.
*/
material& operator=(const material& other);
/**
* Sets state 0 = state 1 for each material property tween.
*/
void update_tweens();
/**
* Uploads each material property to the material's shader program.
*
* @param a Interpolation factor. Should be on `[0.0, 1.0]`.
* @return Number of material property uploads which failed.
*/
std::size_t upload() const;
std::size_t upload(double a) const;
/**
* Sets the material's shader program and reconnects all shader properties to their corresponding shader inputs.

+ 1
- 1
src/renderer/passes/material-pass.cpp View File

@ -403,7 +403,7 @@ void material_pass::render(render_context* context) const
}
// Upload material properties to shader
active_material->upload();
active_material->upload(context->alpha);
}
// Calculate operation-dependent parameters

+ 1
- 1
src/renderer/simple-render-pass.cpp View File

@ -103,7 +103,7 @@ void simple_render_pass::render(render_context* context) const
resolution_property->set_value({static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))});
// Upload material properties
material->upload();
material->upload(context->alpha);
// Draw quad
rasterizer->draw_arrays(*quad_vao, drawing_mode::triangles, 0, 6);

+ 10
- 0
src/resources/resource-manager.cpp View File

@ -43,7 +43,17 @@ void resource_manager::unload(const std::string& path)
// Free the resource if the resource handle is unreferenced
if (it->second->reference_count <= 0)
{
if (logger)
{
logger->push_task("Unloading resource \"" + path + "\"");
}
delete it->second;
if (logger)
{
logger->pop_task(EXIT_SUCCESS);
}
}
// Remove resource from the cache

+ 5
- 0
src/resources/resource-manager.hpp View File

@ -98,6 +98,11 @@ T* resource_manager::load(const std::string& path)
auto it = resource_cache.find(path);
if (it != resource_cache.end())
{
if (logger)
{
logger->log("Fetched resource \"" + path + "\"\n");
}
// Resource found
resource_handle<T>* resource = static_cast<resource_handle<T>*>(it->second);

+ 10
- 1
src/scene/billboard.cpp View File

@ -18,8 +18,8 @@
*/
#include "scene/billboard.hpp"
#include "renderer/material.hpp"
#include "configuration.hpp"
#include <algorithm>
const aabb<float> billboard::untransformed_bounds = {{-1, -1, -1}, {1, 1, 1}};
@ -63,3 +63,12 @@ void billboard::transformed()
{
bounds = aabb<float>::transform(untransformed_bounds, get_transform());
}
void billboard::update_tweens()
{
scene_object_base::update_tweens();
if (material)
{
material->update_tweens();
}
}

+ 3
- 0
src/scene/billboard.hpp View File

@ -61,12 +61,15 @@ public:
material* get_material() const;
billboard_type get_billboard_type() const;
const float3& get_alignment_axis() const;
virtual void update_tweens();
private:
static const aabb<float> untransformed_bounds;
virtual void transformed();
aabb<float> bounds;
material* material;
billboard_type type;

+ 28
- 1
src/scene/model-instance.cpp View File

@ -19,7 +19,7 @@
#include "scene/model-instance.hpp"
#include "renderer/model.hpp"
#include <algorithm>
#include "renderer/material.hpp"
model_instance::model_instance(::model* model):
model(nullptr),
@ -99,3 +99,30 @@ void model_instance::transformed()
{
update_bounds();
}
void model_instance::update_tweens()
{
scene_object_base::update_tweens();
// Update model material tweens
if (model)
{
for (model_group* group: *model->get_groups())
{
material* material = group->get_material();
if (material)
{
material->update_tweens();
}
}
}
// Update material override tweens
for (::material* material: materials)
{
if (material)
{
material->update_tweens();
}
}
}

+ 2
- 0
src/scene/model-instance.hpp View File

@ -74,6 +74,8 @@ public:
bool is_instanced() const;
std::size_t get_instance_count() const;
virtual void update_tweens();
private:
void update_bounds();
virtual void transformed();

+ 1
- 1
src/state/splash-state.cpp View File

@ -48,7 +48,7 @@ void enter_splash_state(application* app)
// Create splash sequence
float t = timeline->get_position();
sequence splash_sequence =
timeline::sequence splash_sequence =
{
{t + 0.0f, fade_in},
{t + 3.0f, fade_out},

+ 1
- 1
src/state/title-state.cpp View File

@ -30,7 +30,7 @@ void enter_title_state(application* app)
// Create title sequence
float t = timeline->get_position();
sequence title_sequence =
timeline::sequence title_sequence =
{
{t + 0.0f, [logger](){ logger->log("cue sound fade-in\n"); }},
{t + 3.0f, [logger](){ logger->log("cue scene fade-in from black\n"); }},

+ 4
- 2
src/timestamp.cpp View File

@ -25,6 +25,8 @@
std::string timestamp()
{
const char* time_format = "%y%m%d-%H%M%S-";
auto now = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t(now);
std::size_t ms = (std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000).count();
@ -33,12 +35,12 @@ std::string timestamp()
struct std::tm timeinfo;
localtime_s(&timeinfo, &tt);
std::stringstream stream;
stream << std::put_time(&timeinfo, "%Y%m%d-%H%M%S-");
stream << std::put_time(&timeinfo, time_format);
stream << std::setfill('0') << std::setw(3) << ms;
#else
struct std::tm* timeinfo = localtime(&tt);
std::stringstream stream;
stream << std::put_time(timeinfo, "%Y%m%d-%H%M%S-");
stream << std::put_time(timeinfo, time_format);
stream << std::setfill('0') << std::setw(3) << ms;
#endif

Loading…
Cancel
Save