Skip to content

Commit

Permalink
Working on animation system
Browse files Browse the repository at this point in the history
  • Loading branch information
tomheeleynz committed Jul 28, 2023
1 parent 53036da commit e1a8aa7
Show file tree
Hide file tree
Showing 13 changed files with 258 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Arcane/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ file(GLOB ASSET_MANAGER_FILES "src/Arcane/Assets/*.h" "src/Arcane/Assets/*.cpp")
file(GLOB SCRIPTING_FILES "src/Arcane/Scripting/*.h" "src/Arcane/Scripting/*.cpp")
file(GLOB PROJECT_SYSTEM_FILES "src/Arcane/Project/*.h" "src/Arcane/Project/*.cpp")
file(GLOB ANIMATION_FILES "src/Arcane/Animation/*.h" "src/Arcane/Animation/*.cpp")
file(GLOB IMGUIZMO_FILES "vendor/ImGuizmo/*.h" "vendor/ImGuizmo/*.cpp")

if (WIN32 OR (UNIX AND NOT APPLE))
# Find Vulkan
Expand Down Expand Up @@ -78,6 +79,7 @@ add_library(
${PROJECT_SYSTEM_FILES}
${PHYSICS_FILES}
${ANIMATION_FILES}
${IMGUIZMO_FILES}
)

# Link Source Directories
Expand Down
3 changes: 2 additions & 1 deletion Arcane/src/Arcane.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@
////////// Animation
/////////////////////////////////////////////////////
#include "Arcane/Animation/Animation.h"
#include "Arcane/Animation/AnimationController.h"
#include "Arcane/Animation/AnimationController.h"
#include "Arcane/Animation/AnimationSerializer.h"
69 changes: 69 additions & 0 deletions Arcane/src/Arcane/Animation/AnimationSerializer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <fstream>
#include <nlohmann/json.hpp>

#include "AnimationSerializer.h"

namespace Arcane
{
AnimationSerializer::AnimationSerializer(Animation* animation)
{
m_Animation = animation;
}

void AnimationSerializer::Serialize(std::filesystem::path path)
{
nlohmann::json jsonObject;

// Set name of animation
jsonObject["name"] = m_Animation->GetName();

nlohmann::json keyframeArray = nlohmann::json::array();

for (auto const& [key, val] : m_Animation->GetKeyFrames())
{
nlohmann::json keyFrameObject = nlohmann::json::array();
KeyFrameType type = val->GetType();

keyFrameObject["type"] = type == KeyFrameType::TWO_DIMENSIONAL ? "2D" : "3D";

if (type == KeyFrameType::TWO_DIMENSIONAL) {
KeyFrame2D* keyFrame2D = static_cast<KeyFrame2D*>(val);

keyFrameObject["ImageIndexX"] = keyFrame2D->GetImageIndexX();
keyFrameObject["ImageIndexY"] = keyFrame2D->GetImageIndexY();
keyFrameObject["KeyframeLength"] = keyFrame2D->GetKeyFrameLength();
}

keyFrameObject["order"] = key;
keyframeArray.push_back(keyFrameObject);
}

jsonObject["Keyframes"] = keyframeArray;

std::ofstream o(path);
o << std::setw(4) << jsonObject << std::endl;
}

void AnimationSerializer::Deserialize(std::filesystem::path path)
{
nlohmann::json jsonObject;
std::ifstream i(path);
i >> jsonObject;

m_Animation->SetName(jsonObject["name"]);

for (auto& element : jsonObject["Keyframes"])
{
KeyFrameType type = element["type"] == "3D" ? KeyFrameType::THREE_DIMENSIONAL : KeyFrameType::TWO_DIMENSIONAL;

if (type == KeyFrameType::TWO_DIMENSIONAL)
{
KeyFrame2D* newKeyFrame = new KeyFrame2D();
newKeyFrame->SetImageIndexX(element["ImageIndexX"]);
newKeyFrame->SetImageIndexY(element["ImageIndexY"]);
newKeyFrame->SetKeyFrameLength(element["KeyframeLength"]);
m_Animation->AddKeyFrame(element["order"], newKeyFrame);
}
}
}
}
17 changes: 17 additions & 0 deletions Arcane/src/Arcane/Animation/AnimationSerializer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "Animation.h"

namespace Arcane
{
class AnimationSerializer
{
public:
AnimationSerializer(Animation* animation);

void Serialize(std::filesystem::path path);
void Deserialize(std::filesystem::path path);
private:
Animation* m_Animation;
};
}
3 changes: 2 additions & 1 deletion Arcane/src/Arcane/Assets/Asset.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ namespace Arcane
SCRIPT,
SHADER,
MATERIAL,
SCENE
SCENE,
ANIMATION
};

class Asset
Expand Down
13 changes: 13 additions & 0 deletions Arcane/src/Arcane/Assets/AssetDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Arcane/Scripting/Script.h"
#include "Arcane/Renderer/MaterialDeserializer.h"
#include "Arcane/Scene/SceneDeserializer.h"
#include "Arcane/Animation/AnimationSerializer.h"

namespace Arcane
{
Expand Down Expand Up @@ -171,6 +172,18 @@ namespace Arcane
m_Assets[assetID] = scene;
}
}
else if (currentAssetPath.extension() == ".arcaneanim")
{
Animation* newAnimation = new Animation();
AnimationSerializer deserializer(newAnimation);

deserializer.Deserialize(currentAssetPath);
newAnimation->SetAssetType(AssetType::ANIMATION);
newAnimation->SetPath(currentAssetPath);
newAnimation->SetID(Arcane::Core::UUID(assetID));

m_Assets[assetID] = newAnimation;
}
return true;
}

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions EnchantingTable/src/EditorLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ void EditorLayer::OnAttach()
m_MaterialViewerPanel = new MaterialViewerPanel();
m_EnviromentPanel = new EnvironmentPanel();
m_SpriteEditor = new SpriteEditor();
m_AnimationPanel = new AnimationPanel();

m_FileBrowserPanel->SetMaterialViewPanel(m_MaterialViewerPanel);

Expand Down Expand Up @@ -170,6 +171,14 @@ void EditorLayer::OnImGuiRender()
ImGui::EndMenu();
}

if (ImGui::BeginMenu("Animation"))
{
if (ImGui::MenuItem("Animation"))
m_ShowAnimationPanel = true;

ImGui::EndMenu();
}

ImGui::EndMenuBar();
}

Expand All @@ -191,6 +200,9 @@ void EditorLayer::OnImGuiRender()
if (m_ShowSpriteEditor)
m_SpriteEditor->OnImGuiRender();

if (m_ShowAnimationPanel)
m_AnimationPanel->OnImGuiRender();

ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));

ImGui::Begin("Viewport");
Expand Down
3 changes: 3 additions & 0 deletions EnchantingTable/src/EditorLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Panels/MaterialViewerPanel.h"
#include "Panels/EnvironmentPanel.h"
#include "Panels/SpriteEditor.h"
#include "Panels/AnimationPanel.h"

#include "Controllers/PerspectiveController.h"
#include "Controllers/OrthographicController.h"
Expand Down Expand Up @@ -57,6 +58,7 @@ class EditorLayer : public Arcane::Layer
MaterialViewerPanel* m_MaterialViewerPanel;
EnvironmentPanel* m_EnviromentPanel;
SpriteEditor* m_SpriteEditor;
AnimationPanel* m_AnimationPanel;

// Editor Camera
Arcane::Camera* m_EditorCamera;
Expand All @@ -68,4 +70,5 @@ class EditorLayer : public Arcane::Layer
// Panel States
bool m_ShowEnvironmentPanel = false;
bool m_ShowSpriteEditor = false;
bool m_ShowAnimationPanel = false;
};
68 changes: 68 additions & 0 deletions EnchantingTable/src/Panels/AnimationPanel.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,81 @@
#include "AnimationPanel.h"
#include "PanelStructs.h"

AnimationPanel::AnimationPanel()
{
m_AnimationSequencer = AnimationSequencer();
m_AnimationSequencer.m_FrameMin = 0;
m_AnimationSequencer.m_FrameMax = 100;
}

void AnimationPanel::OnImGuiRender()
{
ImGui::Begin("Animation");
{
if (ImGui::BeginDragDropTarget())
{
const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CURRENT_SELECTED_ASSET");

if (payload != nullptr) {
// Get Asset Id
AssetInfo assetInfo = *static_cast<AssetInfo*>(payload->Data);
Arcane::Asset* animationAsset = Arcane::Application::Get().GetAssetDatabase().GetAsset(assetInfo.id);

if (animationAsset != nullptr && animationAsset->GetAssetType() == Arcane::AssetType::ANIMATION) {
Arcane::Animation* animation = static_cast<Arcane::Animation*>(animationAsset);
m_Animation = animation;
}
}
ImGui::EndDragDropTarget();
}

if (m_Animation == nullptr) {
if (ImGui::Button("Create Animation"))
CreateAnimation();
}
else {
for (const auto& [key, val] : m_Animation->GetKeyFrames())
{
if (val->GetType() == Arcane::KeyFrameType::TWO_DIMENSIONAL)
{
Arcane::KeyFrame2D* keyFrame2D = static_cast<Arcane::KeyFrame2D*>(val);
AnimationSequencer::KeyFrameItem newItem;
if (key != 0) {
AnimationSequencer::KeyFrameItem prevItem = m_AnimationSequencer.keyFrameItems[key - 1];
newItem.frameStart = prevItem.frameEnd;
newItem.frameEnd = newItem.frameStart + keyFrame2D->GetKeyFrameLength();
}
else {
newItem.frameStart = 0;
newItem.frameEnd = keyFrame2D->GetKeyFrameLength();
}

m_AnimationSequencer.keyFrameItems.push_back(newItem);
}
}

int currentFrame = 0;
int selectedEntry = -1;
bool expanded = true;
ImSequencer::Sequencer(&m_AnimationSequencer, &currentFrame, &expanded, &selectedEntry, 0, ImSequencer::SEQUENCER_EDIT_STARTEND | ImSequencer::SEQUENCER_ADD | ImSequencer::SEQUENCER_DEL | ImSequencer::SEQUENCER_COPYPASTE | ImSequencer::SEQUENCER_CHANGE_FRAME);
}
}
ImGui::End();
}

void AnimationPanel::CreateAnimation()
{
std::string filename = Arcane::FileDialog::SaveFile();

if (!filename.empty()) {
m_Animation = new Arcane::Animation();
Arcane::AnimationSerializer serializer(m_Animation);
std::filesystem::path animationPath(filename);

std::string name = animationPath.stem().string();
m_Animation->SetName(name);

serializer.Serialize(animationPath);

}
}
54 changes: 54 additions & 0 deletions EnchantingTable/src/Panels/AnimationPanel.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,56 @@
#pragma once

#include <Arcane.h>
#include <imgui.h>
#include <ImSequencer.h>
#include <vector>

static const char* SequencerTypeNames[] = { "Animation" };

struct AnimationSequencer : public ImSequencer::SequenceInterface
{
// Inherited via SequenceInterface
virtual int GetFrameMin() const override
{
return m_FrameMin;
}

virtual int GetFrameMax() const override
{
return m_FrameMax;
}

virtual int GetItemCount() const override
{
return (int)keyFrameItems.size();
}

virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) override
{
KeyFrameItem& item = keyFrameItems[index];
if (color)
*color = 0xFF0000; // same color for everyone, return color based on type
if (start)
*start = &item.frameStart;
if (end)
*end = &item.frameEnd;
if (type)
*type = 0;
}

virtual void Add(int type) { keyFrameItems.push_back(KeyFrameItem{ 0, 10 }); };

AnimationSequencer() : m_FrameMin(0), m_FrameMax(0) {}
int m_FrameMin, m_FrameMax;

struct KeyFrameItem
{
int frameStart;
int frameEnd;
};

std::vector<KeyFrameItem> keyFrameItems;
};

class AnimationPanel
{
Expand All @@ -10,4 +59,9 @@ class AnimationPanel

void OnImGuiRender();
private:
Arcane::Animation* m_Animation = nullptr;
bool m_CreateAnimation = false;
AnimationSequencer m_AnimationSequencer;
private:
void CreateAnimation();
};
12 changes: 9 additions & 3 deletions EnchantingTable/src/Panels/EntityPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,23 +544,29 @@ void EntityPanel::InitComponent<Arcane::Animator>()
Arcane::KeyFrame2D* firstKeyFrame = new Arcane::KeyFrame2D();
firstKeyFrame->SetImageIndexX(1);
firstKeyFrame->SetImageIndexY(1);
firstKeyFrame->SetKeyFrameLength(10);
firstKeyFrame->SetKeyFrameLength(30);

Arcane::KeyFrame2D* secondKeyFrame = new Arcane::KeyFrame2D();
secondKeyFrame->SetImageIndexX(2);
secondKeyFrame->SetImageIndexY(1);
secondKeyFrame->SetKeyFrameLength(10);
secondKeyFrame->SetKeyFrameLength(30);


Arcane::KeyFrame2D* thirdKeyFrame = new Arcane::KeyFrame2D();
secondKeyFrame->SetImageIndexX(3);
secondKeyFrame->SetImageIndexY(1);
secondKeyFrame->SetKeyFrameLength(10);
secondKeyFrame->SetKeyFrameLength(30);

Arcane::KeyFrame2D* fourthKeyFrame = new Arcane::KeyFrame2D();
secondKeyFrame->SetImageIndexX(4);
secondKeyFrame->SetImageIndexY(1);
secondKeyFrame->SetKeyFrameLength(30);

// Add to animation
idleAnimation->AddKeyFrame(0, firstKeyFrame);
idleAnimation->AddKeyFrame(1, secondKeyFrame);
idleAnimation->AddKeyFrame(2, thirdKeyFrame);
idleAnimation->AddKeyFrame(3, fourthKeyFrame);

// Add Animation to animation controller
newController = new Arcane::AnimationController();
Expand Down

0 comments on commit e1a8aa7

Please sign in to comment.