Added animation enter / exit events.

This commit is contained in:
Tim Baker 2017-09-07 10:24:24 -07:00 committed by Mikulas Florek
parent d8c9560cd1
commit b139d45afe
7 changed files with 198 additions and 7 deletions

View file

@ -81,7 +81,6 @@ struct InputDecl
if (idx == 0) return i;
--idx;
}
ASSERT(false);
return -1;
}

View file

@ -42,6 +42,7 @@ public:
ANIMATION_SETS,
MAX_ROOT_ROTATION_SPEED,
INPUT_REFACTOR,
ENTER_EXIT_EVENTS,
LAST
};

View file

@ -205,12 +205,12 @@ void Node::removeEvent(int index)
}
static const char* getEventTypeName(const Anim::EventHeader& event, AnimEditor::IAnimationEditor& editor)
static const char* getEventTypeName(u32 type, AnimEditor::IAnimationEditor& editor)
{
int count = editor.getEventTypesCount();
for (int i = 0; i < count; ++i)
{
if (editor.getEventTypeByIdx(i).type == event.type)
if (editor.getEventTypeByIdx(i).type == type)
{
return editor.getEventTypeByIdx(i).label;
}
@ -224,15 +224,19 @@ void Node::onGUI()
u32 set_input_type = crc32("set_input");
ImGui::InputText("Name", name.data, lengthOf(name.data));
if (!engine_cmp) return;
auto* engine_node = ((Anim::Node*)engine_cmp);
onGuiEvents(engine_node->enter_events, "Enter Events");
onGuiEvents(engine_node->exit_events, "Exit Events");
if (!ImGui::CollapsingHeader("Events")) return;
auto* engine_node = ((Anim::Node*)engine_cmp);
auto& events = engine_node->events;
auto& editor = m_controller.getEditor();
for(int i = 0; i < engine_node->events_count; ++i)
{
Anim::EventHeader& header = *(Anim::EventHeader*)&events[sizeof(Anim::EventHeader) * i];
const char* event_type_name = getEventTypeName(header, editor);
const char* event_type_name = getEventTypeName(header.type, editor);
if (ImGui::TreeNode((void*)(uintptr)i, "%s - %fs", event_type_name, header.time))
{
if (ImGui::Button("Remove"))
@ -279,6 +283,49 @@ void Node::onGUI()
}
void Node::onGuiEvents(Anim::EventArray& events, const char* label)
{
if (!ImGui::CollapsingHeader(label)) return;
ImGui::PushID(label);
auto* engine_node = ((Anim::Node*)engine_cmp);
auto& editor = m_controller.getEditor();
for (int i = 0; i < events.count; ++i)
{
auto& header = *(Anim::EnterExitEventHeader*)&events.data[sizeof(Anim::EnterExitEventHeader) * i];
const char* event_type_name = getEventTypeName(header.type, editor);
if (ImGui::TreeNode((void*)(uintptr)i, "%s", event_type_name))
{
if (ImGui::Button("Remove"))
{
events.remove(i);
ImGui::TreePop();
break;
}
int event_offset = header.offset + sizeof(Anim::EnterExitEventHeader) * events.count;
editor.getEventType(header.type).editor.invoke(&events.data[event_offset], *this);
ImGui::TreePop();
}
}
auto getter = [](void* data, int idx, const char** out) -> bool {
auto* node = (Node*)data;
*out = node->m_controller.getEditor().getEventTypeByIdx(idx).label;
return true;
};
static int current = 0;
ImGui::Combo("", &current, getter, this, editor.getEventTypesCount());
ImGui::SameLine();
if (ImGui::Button("Add event"))
{
auto& event_type = editor.getEventTypeByIdx(current);
events.append(event_type.size, event_type.type);
}
ImGui::PopID();
}
void Node::serialize(OutputBlob& blob)
{
blob.write(pos);

View file

@ -11,7 +11,11 @@ namespace Lumix
{
class ResourceManagerBase;
namespace Anim { class ControllerResource; }
namespace Anim
{
class ControllerResource;
struct EventArray;
}
namespace AnimEditor
@ -82,6 +86,9 @@ public:
void removeInEdge(Edge* edge) { m_in_edges.eraseItemFast(edge); }
void removeEvent(int index);
protected:
void onGuiEvents(Anim::EventArray& events, const char* label);
public:
ImVec2 pos;
ImVec2 size;

View file

@ -2,6 +2,7 @@
#include "engine/lumix.h"
#include "engine/array.h"
namespace Lumix
@ -21,6 +22,28 @@ struct EventHeader
};
struct EnterExitEventHeader
{
u32 type;
u16 offset;
u8 size;
};
struct EventArray
{
EventArray(IAllocator& allocator)
: data(allocator)
, count(0)
{}
void remove(int index);
void append(int size, u32 type);
Array<u8> data;
int count;
};
struct SetInputEvent
{
int input_idx;

View file

@ -169,6 +169,8 @@ Node::Node(Component::Type type, IAllocator& _allocator)
, out_edges(_allocator)
, allocator(_allocator)
, events(allocator)
, enter_events(allocator)
, exit_events(allocator)
{
}
@ -182,6 +184,18 @@ void Node::serialize(OutputBlob& blob)
blob.write(events.size());
blob.write(&events[0], events.size());
}
blob.write(enter_events.count);
if (enter_events.count > 0)
{
blob.write(enter_events.data.size());
blob.write(&enter_events.data[0], enter_events.data.size());
}
blob.write(exit_events.count);
if (exit_events.count > 0)
{
blob.write(exit_events.data.size());
blob.write(&exit_events.data[0], exit_events.data.size());
}
}
@ -196,6 +210,25 @@ void Node::deserialize(InputBlob& blob, Container* parent, int version)
events.resize(size);
blob.read(&events[0], size);
}
if (version > (int)ControllerResource::Version::ENTER_EXIT_EVENTS)
{
blob.read(enter_events.count);
if (enter_events.count > 0)
{
int size;
blob.read(size);
enter_events.data.resize(size);
blob.read(&enter_events.data[0], size);
}
blob.read(exit_events.count);
if (exit_events.count > 0)
{
int size;
blob.read(size);
exit_events.data.resize(size);
blob.read(&exit_events.data[0], size);
}
}
}
@ -273,6 +306,7 @@ void Blend1DNodeInstance::onAnimationSetUpdated(AnimSet& anim_set)
void Blend1DNodeInstance::enter(RunningContext& rc, ComponentInstance* from)
{
queueEnterEvents(rc);
time = 0;
if (node.items.size() > lengthOf(instances))
{
@ -412,6 +446,37 @@ void NodeInstance::queueEvents(RunningContext& rc, float old_time, float time, f
}
void NodeInstance::queueEnterEvents(RunningContext& rc)
{
Node& node = (Node&)source;
queueEventArray(rc, node.enter_events);
}
void NodeInstance::queueExitEvents(RunningContext& rc)
{
Node& node = (Node&)source;
queueEventArray(rc, node.exit_events);
}
void NodeInstance::queueEventArray(RunningContext& rc, const EventArray& events)
{
if (events.count <= 0) return;
auto headers = (EnterExitEventHeader*)&events.data[0];
for (int i = 0; i < events.count; ++i)
{
auto& header = headers[i];
rc.event_stream->write(header.type);
rc.event_stream->write(rc.controller);
rc.event_stream->write(header.size);
rc.event_stream->write(
&events.data[0] + header.offset + sizeof(EnterExitEventHeader) * events.count, header.size);
}
}
ComponentInstance* NodeInstance::checkOutEdges(Node& node, RunningContext& rc)
{
rc.current = this;
@ -421,6 +486,7 @@ ComponentInstance* NodeInstance::checkOutEdges(Node& node, RunningContext& rc)
if (edge->condition(rc))
{
ComponentInstance* new_item = edge->createInstance(*rc.allocator);
queueExitEvents(rc);
new_item->enter(rc, this);
return new_item;
}
@ -532,7 +598,8 @@ struct AnimationNodeInstance : public NodeInstance
void enter(RunningContext& rc, ComponentInstance* from) override
{
{
queueEnterEvents(rc);
time = 0;
if (node.animations_hashes.empty()) return;
int idx = Math::rand() % node.animations_hashes.size();
@ -746,6 +813,46 @@ Component* createComponent(Component::Type type, IAllocator& allocator)
}
void EventArray::remove(int index)
{
auto headers = (Anim::EnterExitEventHeader*)&data[0];
auto header = headers[index];
u8* headers_end = (u8*)(headers + count);
u8* end = &data.back() + 1;
u8* event_start = headers_end + header.offset;
u8* event_end = event_start + header.size;
for (int i = index + 1; i < count; ++i)
{
auto& h = headers[i];
h.offset -= header.size;
}
u8* header_start = (u8*)&headers[index];
u8* header_end = header_start + sizeof(Anim::EnterExitEventHeader);
moveMemory(header_start, header_end, event_start - header_end);
moveMemory(event_start - sizeof(Anim::EnterExitEventHeader), event_end, end - event_end);
data.resize(data.size() - sizeof(Anim::EnterExitEventHeader) - header.size);
--count;
}
void EventArray::append(int size, u32 type)
{
int old_payload_size = data.size() - sizeof(Anim::EnterExitEventHeader) * count;
data.resize(data.size() + size + sizeof(Anim::EnterExitEventHeader));
u8* headers_end = &data[count * sizeof(Anim::EnterExitEventHeader)];
moveMemory(headers_end + sizeof(Anim::EnterExitEventHeader), headers_end, old_payload_size);
auto& event_header = *(Anim::EnterExitEventHeader*)&data[sizeof(Anim::EnterExitEventHeader) * count];
event_header.type = type;
event_header.size = size;
event_header.offset = old_payload_size;
++count;
}
} // namespace Anim

View file

@ -2,6 +2,7 @@
#include "condition.h"
#include "events.h"
#include "engine/array.h"
#include "engine/lumix.h"
@ -84,6 +85,8 @@ struct Node : public Component
Array<Edge*> out_edges;
Array<u8> events;
int events_count = 0;
EventArray enter_events;
EventArray exit_events;
};
@ -123,6 +126,10 @@ struct NodeInstance : public ComponentInstance
ComponentInstance* checkOutEdges(Node& node, RunningContext& rc);
void queueEvents(RunningContext& rc, float old_time, float time, float length);
void queueEnterEvents(RunningContext& rc);
void queueExitEvents(RunningContext& rc);
protected:
void queueEventArray(RunningContext& rc, const EventArray& events);
};