2014-06-16 21:18:15 +02:00
|
|
|
#include "animation_system.h"
|
|
|
|
#include "animation/animation.h"
|
2015-07-30 09:18:37 +02:00
|
|
|
#include "core/base_proxy_allocator.h"
|
|
|
|
#include "core/blob.h"
|
2014-06-16 21:18:15 +02:00
|
|
|
#include "core/crc32.h"
|
|
|
|
#include "core/json_serializer.h"
|
2014-11-23 01:47:27 +01:00
|
|
|
#include "core/profiler.h"
|
2014-06-29 15:20:21 +02:00
|
|
|
#include "core/resource_manager.h"
|
2015-08-11 23:55:58 +02:00
|
|
|
#include "engine.h"
|
2016-01-27 17:05:28 +01:00
|
|
|
#include "engine/property_descriptor.h"
|
|
|
|
#include "engine/property_register.h"
|
2015-08-17 23:45:26 +02:00
|
|
|
#include "renderer/render_scene.h"
|
2014-06-16 21:18:15 +02:00
|
|
|
#include "universe/universe.h"
|
|
|
|
|
2014-08-22 22:02:53 +02:00
|
|
|
|
2014-06-16 21:18:15 +02:00
|
|
|
namespace Lumix
|
|
|
|
{
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
static const uint32 RENDERABLE_HASH = crc32("renderable");
|
|
|
|
static const uint32 ANIMABLE_HASH = crc32("animable");
|
2014-06-16 21:18:15 +02:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
namespace FS
|
|
|
|
{
|
|
|
|
class FileSystem;
|
|
|
|
};
|
2014-11-07 23:20:45 +01:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
class Animation;
|
|
|
|
class Engine;
|
|
|
|
class JsonSerializer;
|
|
|
|
class Universe;
|
2014-11-07 23:20:45 +01:00
|
|
|
|
2014-06-16 21:18:15 +02:00
|
|
|
|
2015-07-25 00:09:11 +02:00
|
|
|
class AnimationSceneImpl : public IScene
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
struct Animable
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-07-23 23:17:51 +02:00
|
|
|
bool m_is_free;
|
2015-07-24 22:38:11 +02:00
|
|
|
ComponentIndex m_renderable;
|
2015-07-23 23:17:51 +02:00
|
|
|
float m_time;
|
|
|
|
class Animation* m_animation;
|
|
|
|
Entity m_entity;
|
|
|
|
};
|
2014-06-16 21:18:15 +02:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
public:
|
2016-01-27 17:05:28 +01:00
|
|
|
AnimationSceneImpl(IPlugin& anim_system, Engine& engine, Universe& ctx, IAllocator& allocator)
|
2016-01-20 22:37:00 +01:00
|
|
|
: m_universe(ctx)
|
2015-07-23 23:17:51 +02:00
|
|
|
, m_engine(engine)
|
|
|
|
, m_anim_system(anim_system)
|
|
|
|
, m_animables(allocator)
|
|
|
|
{
|
2015-08-12 22:57:22 +02:00
|
|
|
m_render_scene = nullptr;
|
2015-11-11 21:54:25 +01:00
|
|
|
uint32 hash = crc32("renderer");
|
2016-01-20 22:37:00 +01:00
|
|
|
for (auto* scene : ctx.getScenes())
|
2015-08-12 22:57:22 +02:00
|
|
|
{
|
|
|
|
if (crc32(scene->getPlugin().getName()) == hash)
|
|
|
|
{
|
|
|
|
m_render_scene = static_cast<RenderScene*>(scene);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(m_render_scene);
|
2015-07-24 22:38:11 +02:00
|
|
|
m_render_scene->renderableCreated()
|
2016-01-27 17:05:28 +01:00
|
|
|
.bind<AnimationSceneImpl, &AnimationSceneImpl::onRenderableCreated>(this);
|
2015-07-24 22:38:11 +02:00
|
|
|
m_render_scene->renderableDestroyed()
|
2016-01-27 17:05:28 +01:00
|
|
|
.bind<AnimationSceneImpl, &AnimationSceneImpl::onRenderableDestroyed>(this);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2015-07-25 00:09:11 +02:00
|
|
|
~AnimationSceneImpl()
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2016-01-27 17:05:28 +01:00
|
|
|
for(auto& animable : m_animables)
|
|
|
|
{
|
|
|
|
if(animable.m_is_free) continue;
|
|
|
|
unloadAnimation(animable.m_animation);
|
|
|
|
}
|
|
|
|
|
2016-01-20 22:37:00 +01:00
|
|
|
m_render_scene = static_cast<RenderScene*>(m_universe.getScene(crc32("renderer")));
|
|
|
|
if (m_render_scene)
|
|
|
|
{
|
|
|
|
m_render_scene->renderableCreated()
|
|
|
|
.unbind<AnimationSceneImpl, &AnimationSceneImpl::onRenderableCreated>(this);
|
|
|
|
m_render_scene->renderableDestroyed()
|
|
|
|
.unbind<AnimationSceneImpl, &AnimationSceneImpl::onRenderableDestroyed>(this);
|
|
|
|
}
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
2015-07-19 18:37:31 +02:00
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
Universe& getUniverse() override { return m_universe; }
|
2015-07-19 18:37:31 +02:00
|
|
|
|
2015-01-04 15:05:20 +01:00
|
|
|
|
2015-12-13 11:45:31 +01:00
|
|
|
ComponentIndex getComponent(Entity entity, uint32 type) override
|
|
|
|
{
|
|
|
|
ASSERT(ownComponentType(type));
|
|
|
|
for (int i = 0; i < m_animables.size(); ++i)
|
|
|
|
{
|
|
|
|
if (!m_animables[i].m_is_free && m_animables[i].m_entity == entity) return i;
|
|
|
|
}
|
|
|
|
return INVALID_COMPONENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
bool ownComponentType(uint32 type) const override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
return type == ANIMABLE_HASH;
|
|
|
|
}
|
2015-01-04 15:05:20 +01:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
ComponentIndex createComponent(uint32 type,
|
2015-07-24 08:42:35 +02:00
|
|
|
Entity entity) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
if (type == ANIMABLE_HASH)
|
|
|
|
{
|
2015-07-25 00:09:11 +02:00
|
|
|
return createAnimable(entity);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2015-07-24 22:38:11 +02:00
|
|
|
return INVALID_COMPONENT;
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2016-01-27 17:05:28 +01:00
|
|
|
void unloadAnimation(Animation* animation)
|
|
|
|
{
|
|
|
|
if(!animation) return;
|
|
|
|
|
|
|
|
auto& rm = animation->getResourceManager();
|
|
|
|
auto* animation_manager = rm.get(ResourceManager::ANIMATION);
|
|
|
|
animation_manager->unload(*animation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void destroyComponent(ComponentIndex component, uint32 type) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
if (type == ANIMABLE_HASH)
|
|
|
|
{
|
2016-01-27 17:05:28 +01:00
|
|
|
unloadAnimation(m_animables[component].m_animation);
|
2015-07-23 23:17:51 +02:00
|
|
|
m_animables[component].m_is_free = true;
|
2016-01-27 17:05:28 +01:00
|
|
|
m_universe.destroyComponent(m_animables[component].m_entity, type, this, component);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
void serialize(OutputBlob& serializer) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
serializer.write((int32)m_animables.size());
|
2015-07-23 23:17:51 +02:00
|
|
|
for (int i = 0; i < m_animables.size(); ++i)
|
|
|
|
{
|
2015-07-24 22:38:11 +02:00
|
|
|
serializer.write(m_animables[i].m_entity);
|
2015-07-23 23:17:51 +02:00
|
|
|
serializer.write(m_animables[i].m_time);
|
|
|
|
serializer.write(m_animables[i].m_is_free);
|
|
|
|
serializer.writeString(
|
2016-01-07 13:33:52 +01:00
|
|
|
m_animables[i].m_animation ? m_animables[i].m_animation->getPath().c_str() : "");
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
void deserialize(InputBlob& serializer, int) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
int32 count;
|
2015-07-23 23:17:51 +02:00
|
|
|
serializer.read(count);
|
|
|
|
m_animables.resize(count);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
serializer.read(m_animables[i].m_entity);
|
2015-07-24 22:38:11 +02:00
|
|
|
ComponentIndex renderable =
|
2015-07-23 23:17:51 +02:00
|
|
|
m_render_scene->getRenderableComponent(m_animables[i].m_entity);
|
2015-07-24 22:38:11 +02:00
|
|
|
if (renderable >= 0)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-07-23 23:17:51 +02:00
|
|
|
m_animables[i].m_renderable = renderable;
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
2015-07-23 23:17:51 +02:00
|
|
|
serializer.read(m_animables[i].m_time);
|
|
|
|
serializer.read(m_animables[i].m_is_free);
|
2015-07-30 00:33:52 +02:00
|
|
|
char path[MAX_PATH_LENGTH];
|
2015-07-23 23:17:51 +02:00
|
|
|
serializer.readString(path, sizeof(path));
|
2016-01-27 17:05:28 +01:00
|
|
|
m_animables[i].m_animation = path[0] == '\0' ? nullptr : loadAnimation(Path(path));
|
2016-01-07 13:33:52 +01:00
|
|
|
m_universe.addComponent(m_animables[i].m_entity, ANIMABLE_HASH, this, i);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2016-01-27 17:05:28 +01:00
|
|
|
Path getAnimation(ComponentIndex cmp)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-07-31 02:42:25 +02:00
|
|
|
return m_animables[cmp].m_animation
|
2016-01-27 17:05:28 +01:00
|
|
|
? m_animables[cmp].m_animation->getPath()
|
|
|
|
: Path("");
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-06-16 21:31:04 +02:00
|
|
|
|
|
|
|
|
2016-01-27 17:05:28 +01:00
|
|
|
void setAnimation(ComponentIndex cmp, const Path& path)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2016-01-27 17:05:28 +01:00
|
|
|
unloadAnimation(m_animables[cmp].m_animation);
|
2015-07-24 08:42:35 +02:00
|
|
|
m_animables[cmp].m_animation = loadAnimation(path);
|
|
|
|
m_animables[cmp].m_time = 0;
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-07-31 23:45:57 +02:00
|
|
|
|
2014-08-21 01:22:57 +02:00
|
|
|
|
2016-01-17 23:28:20 +01:00
|
|
|
void update(float time_delta, bool paused) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
PROFILE_FUNCTION();
|
2016-01-17 23:28:20 +01:00
|
|
|
if (m_animables.empty()) return;
|
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
for (int i = 0, c = m_animables.size(); i < c; ++i)
|
|
|
|
{
|
|
|
|
Animable& animable = m_animables[i];
|
|
|
|
if (!animable.m_is_free && animable.m_animation &&
|
|
|
|
animable.m_animation->isReady())
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-07-23 23:17:51 +02:00
|
|
|
animable.m_animation->getPose(
|
|
|
|
animable.m_time,
|
2015-12-10 20:27:51 +01:00
|
|
|
*m_render_scene->getPose(animable.m_renderable),
|
2015-07-24 22:38:11 +02:00
|
|
|
*m_render_scene->getRenderableModel(animable.m_renderable));
|
2015-07-25 00:09:11 +02:00
|
|
|
float t = animable.m_time + time_delta;
|
|
|
|
float l = animable.m_animation->getLength();
|
|
|
|
while (t > l)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-07-25 00:09:11 +02:00
|
|
|
t -= l;
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
2015-07-25 00:09:11 +02:00
|
|
|
animable.m_time = t;
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-17 17:55:34 +02:00
|
|
|
|
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
private:
|
2016-01-27 17:05:28 +01:00
|
|
|
Animation* loadAnimation(const Path& path)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
ResourceManager& rm = m_engine.getResourceManager();
|
2016-01-27 17:05:28 +01:00
|
|
|
return static_cast<Animation*>(rm.get(ResourceManager::ANIMATION)->load(path));
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-08-21 01:22:57 +02:00
|
|
|
|
|
|
|
|
2015-07-24 22:38:11 +02:00
|
|
|
void onRenderableCreated(ComponentIndex cmp)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-07-24 22:38:11 +02:00
|
|
|
Entity entity = m_render_scene->getRenderableEntity(cmp);
|
|
|
|
for (int i = 0; i < m_animables.size(); ++i)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-07-24 22:38:11 +02:00
|
|
|
if (m_animables[i].m_entity == entity)
|
2014-08-21 01:22:57 +02:00
|
|
|
{
|
2015-07-24 22:38:11 +02:00
|
|
|
m_animables[i].m_renderable = cmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void onRenderableDestroyed(ComponentIndex cmp)
|
|
|
|
{
|
|
|
|
Entity entity = m_render_scene->getRenderableEntity(cmp);
|
|
|
|
for (int i = 0; i < m_animables.size(); ++i)
|
|
|
|
{
|
|
|
|
if (m_animables[i].m_entity == entity)
|
|
|
|
{
|
|
|
|
m_animables[i].m_renderable = INVALID_COMPONENT;
|
|
|
|
break;
|
2014-08-21 01:22:57 +02:00
|
|
|
}
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-21 01:22:57 +02:00
|
|
|
|
|
|
|
|
2015-07-25 00:09:11 +02:00
|
|
|
ComponentIndex createAnimable(Entity entity)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-07-25 19:33:19 +02:00
|
|
|
Animable* src = nullptr;
|
2015-07-23 23:17:51 +02:00
|
|
|
for (int i = 0, c = m_animables.size(); i < c; ++i)
|
|
|
|
{
|
|
|
|
if (m_animables[i].m_is_free)
|
2014-08-21 01:22:57 +02:00
|
|
|
{
|
2015-07-23 23:17:51 +02:00
|
|
|
src = &m_animables[i];
|
|
|
|
break;
|
2014-08-21 01:22:57 +02:00
|
|
|
}
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2016-01-14 16:22:25 +01:00
|
|
|
Animable& animable = src ? *src : m_animables.emplace();
|
2015-07-23 23:17:51 +02:00
|
|
|
animable.m_time = 0;
|
|
|
|
animable.m_is_free = false;
|
2015-07-24 22:38:11 +02:00
|
|
|
animable.m_renderable = INVALID_COMPONENT;
|
2015-07-25 19:33:19 +02:00
|
|
|
animable.m_animation = nullptr;
|
2015-07-23 23:17:51 +02:00
|
|
|
animable.m_entity = entity;
|
|
|
|
|
2015-07-24 22:38:11 +02:00
|
|
|
ComponentIndex renderable =
|
|
|
|
m_render_scene->getRenderableComponent(entity);
|
|
|
|
if (renderable >= 0)
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
animable.m_renderable = renderable;
|
|
|
|
}
|
|
|
|
|
2015-07-25 00:09:11 +02:00
|
|
|
m_universe.addComponent(
|
2015-07-23 23:17:51 +02:00
|
|
|
entity, ANIMABLE_HASH, this, m_animables.size() - 1);
|
2015-07-25 00:09:11 +02:00
|
|
|
return m_animables.size() - 1;
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-08-21 01:22:57 +02:00
|
|
|
|
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
IPlugin& getPlugin() const override { return m_anim_system; }
|
2014-08-21 01:22:57 +02:00
|
|
|
|
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
private:
|
|
|
|
Universe& m_universe;
|
|
|
|
IPlugin& m_anim_system;
|
|
|
|
Engine& m_engine;
|
|
|
|
Array<Animable> m_animables;
|
|
|
|
RenderScene* m_render_scene;
|
|
|
|
};
|
2014-08-21 01:22:57 +02:00
|
|
|
|
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
struct AnimationSystemImpl : public IPlugin
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AnimationSystemImpl(Engine& engine)
|
|
|
|
: m_allocator(engine.getAllocator())
|
|
|
|
, m_engine(engine)
|
|
|
|
, m_animation_manager(m_allocator)
|
2014-08-21 01:22:57 +02:00
|
|
|
{
|
2016-01-27 17:05:28 +01:00
|
|
|
PropertyRegister::registerComponentType("animable", "Animable");
|
|
|
|
|
|
|
|
PropertyRegister::add("animable", LUMIX_NEW(m_allocator, ResourcePropertyDescriptor<AnimationSceneImpl>)("Animation",
|
|
|
|
&AnimationSceneImpl::getAnimation,
|
|
|
|
&AnimationSceneImpl::setAnimation,
|
|
|
|
"Animation (*.ani)",
|
|
|
|
ResourceManager::ANIMATION,
|
|
|
|
m_allocator));
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-08-21 01:22:57 +02:00
|
|
|
|
2016-01-20 22:37:00 +01:00
|
|
|
IScene* createScene(Universe& ctx) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-11-11 23:25:44 +01:00
|
|
|
return LUMIX_NEW(m_allocator, AnimationSceneImpl)(
|
2015-08-12 22:57:22 +02:00
|
|
|
*this, m_engine, ctx, m_allocator);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-11-23 22:17:25 +01:00
|
|
|
|
2014-11-07 22:18:47 +01:00
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
void destroyScene(IScene* scene) override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
2015-11-11 23:25:44 +01:00
|
|
|
LUMIX_DELETE(m_allocator, scene);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-08-21 01:22:57 +02:00
|
|
|
|
2014-08-17 17:55:34 +02:00
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
const char* getName() const override { return "animation"; }
|
2014-08-17 17:55:34 +02:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
bool create() override
|
2015-07-23 23:17:51 +02:00
|
|
|
{
|
|
|
|
m_animation_manager.create(ResourceManager::ANIMATION,
|
|
|
|
m_engine.getResourceManager());
|
|
|
|
return true;
|
|
|
|
}
|
2014-08-17 17:55:34 +02:00
|
|
|
|
|
|
|
|
2015-11-20 16:58:10 +01:00
|
|
|
void destroy() override {}
|
2014-08-17 17:55:34 +02:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
BaseProxyAllocator m_allocator;
|
|
|
|
Engine& m_engine;
|
|
|
|
AnimationManager m_animation_manager;
|
2014-11-07 23:20:45 +01:00
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
private:
|
|
|
|
void operator=(const AnimationSystemImpl&);
|
|
|
|
AnimationSystemImpl(const AnimationSystemImpl&);
|
|
|
|
};
|
2014-08-17 17:55:34 +02:00
|
|
|
|
|
|
|
|
2015-07-23 23:17:51 +02:00
|
|
|
extern "C" IPlugin* createPlugin(Engine& engine)
|
|
|
|
{
|
2015-11-11 23:25:44 +01:00
|
|
|
return LUMIX_NEW(engine.getAllocator(), AnimationSystemImpl)(engine);
|
2015-07-23 23:17:51 +02:00
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
} // ~namespace Lumix
|