Skip to content

Commit

Permalink
add skeleton parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Deweh committed Dec 3, 2023
1 parent 12f42a6 commit 4624103
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 181 deletions.
32 changes: 22 additions & 10 deletions Plugin/src/API/API_External.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ namespace NAFAPI
{
struct Timeline
{
std::vector<float> positionTimes;
std::vector<RE::NiPoint3> positions;
std::vector<float> rotationTimes;
std::vector<float> positionTimes;
std::vector<RE::NiPoint3> positions;
std::vector<float> rotationTimes;
std::vector<RE::NiQuaternion> rotations;

struct Data
{
float* positionTimes;
RE::NiPoint3* positions;
unsigned long long positionsSize;
float* rotationTimes;
RE::NiQuaternion* rotations;
unsigned long long rotationsSize;
float* positionTimes;
RE::NiPoint3* positions;
uint64_t positionsSize;
float* rotationTimes;
RE::NiQuaternion* rotations;
uint64_t rotationsSize;
};

Data data()
Expand All @@ -42,7 +42,7 @@ namespace NAFAPI
struct Transform
{
RE::NiQuaternion rotate;
RE::NiPoint3 translate;
RE::NiPoint3 translate;
};

/*
Expand Down Expand Up @@ -90,12 +90,24 @@ namespace NAFAPI
uint64_t size = 0;
};

//Functions similarly to a std::unique_ptr.
//Once a Handle goes out of scope, the underlying pointer(s) will no longer be valid.
//Ownership of a Handle can be transferred across scopes with std::move().
template <typename T>
struct Handle
{
T data;
uint64_t handle = 0;

Handle() {}

Handle(const Handle<T>&& rhs) {
data = rhs.data;
handle = rhs.handle;
rhs.data = T();
rhs.handle = 0;
}

T& operator->()
{
return data;
Expand Down
10 changes: 10 additions & 0 deletions Plugin/src/Animation/Generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ namespace Animation
std::vector<PositionTimelineType> position;
std::vector<RotationTimelineType> rotation;

void InitTimelines()
{
for (auto& tl : rotation) {
tl.Init();
}
for (auto& tl : position) {
tl.Init();
}
}

void SetSize(size_t s)
{
output.resize(s);
Expand Down
1 change: 1 addition & 0 deletions Plugin/src/Animation/GraphManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ namespace Animation
{
originalUpdate(a_graphHolder, a_updateData, a_graph);
static GraphManager& graphManager = *GraphManager::GetSingleton();

std::shared_lock l{ graphManager.stateLock };
auto& m = graphManager.state->graphMap;
if (auto iter = m.find(a_graphHolder); iter != m.end()) {
Expand Down
22 changes: 20 additions & 2 deletions Plugin/src/Commands/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@

namespace Commands
{
RE::NiPointer<RE::TESObjectREFR> GetRefrFromHandle(uint32_t handle)
{
RE::NiPointer<RE::TESObjectREFR> result;
REL::Relocation<void(RE::NiPointer<RE::TESObjectREFR>&, uint32_t*)> func(REL::ID(72399));
func(result, &handle);
return result;
}

RE::NiPointer<RE::TESObjectREFR> GetConsoleRefr()
{
REL::Relocation<uint64_t**> consoleReferencesManager(REL::ID(879512));
REL::Relocation<uint32_t* (uint64_t*, uint32_t*)> GetConsoleHandle(REL::ID(166314));
uint32_t outId = 0;
GetConsoleHandle(*consoleReferencesManager, &outId);
return GetRefrFromHandle(outId);
}

typedef void (*ExecuteCommandFunc)(void*, const char*);

ExecuteCommandFunc OriginalExecuteCommand;
Expand All @@ -21,9 +38,10 @@ namespace Commands
}

std::string_view cmdView(a_cmd);
auto args = Util::String::Split(cmdView, " ");
auto args = Util::String::Split(cmdView, " ", '\"');
if (auto iter = registrations.find(std::string(args[0])); iter != registrations.end()) {
iter->second(args, cmdView);
auto refr = GetConsoleRefr();
iter->second(args, cmdView, refr.get());
} else {
OriginalExecuteCommand(a1, a_cmd);
}
Expand Down
2 changes: 1 addition & 1 deletion Plugin/src/Commands/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Commands
{
typedef std::function<void(const std::vector<std::string_view>&, const std::string_view&)> CommandFunction;
typedef std::function<void(const std::vector<std::string_view>&, const std::string_view&, RE::TESObjectREFR*)> CommandFunction;

void InstallHooks();
void RegisterCommand(const std::string& name, const CommandFunction& func);
Expand Down
64 changes: 45 additions & 19 deletions Plugin/src/Commands/NAFCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,71 @@ namespace Commands::NAFCommand
log->Print("naf stop");
}

void ProcessPlayCommand(const std::vector<std::string_view>& args, RE::ConsoleLog* log)
void ShowNoActor(RE::ConsoleLog* log)
{
log->Print("No actor selected.");
}

void ProcessPlayCommand(const std::vector<std::string_view>& args, RE::ConsoleLog* log, RE::TESObjectREFR* refr)
{
if (args.size() < 3) {
ShowHelp(log);
return;
}

if (!refr) {
ShowNoActor(log);
return;
}

auto actor = starfield_cast<RE::Actor*>(refr);
if (!actor) {
ShowNoActor(log);
return;
}

using clock = std::chrono::high_resolution_clock;
auto start = clock::now();
auto asset = Serialization::GLTFImport::LoadGLTF("Data/NAF/s" + std::string(args[2]));
auto asset = Serialization::GLTFImport::LoadGLTF("Data/NAF/" + std::string(args[2]));
if (!asset) {
log->Print("Failed to load GLTF.");
log->Print("Failed to load GLTF/GLB.");
return;
}
auto humanSkeleton = Settings::GetSkeleton("HumanRace");
auto gen = Serialization::GLTFImport::CreateClipGenerator(asset.get(), &asset->animations[0], humanSkeleton.get());
auto skeleton = Settings::GetSkeleton(actor);
if (Settings::IsDefaultSkeleton(skeleton)) {
log->Print("No configured skeleton for selected actor's race.");
return;
}
auto gen = Serialization::GLTFImport::CreateClipGenerator(asset.get(), &asset->animations[0], skeleton.get());
if (!gen) {
log->Print("Failed to create ClipGenerator.");
log->Print("Failed to create ClipGenerator. Malformed GLTF/GLB?");
return;
}
log->Print(std::format("Finished loading animation in {:.3f}ms", std::chrono::duration<double>(clock::now() - start).count()).c_str());
log->Print(std::format("Loaded animation in {:.3f}ms", std::chrono::duration<double>(clock::now() - start).count() * 1000).c_str());

for (auto& tl : gen->rotation) {
tl.Init();
}
for (auto& tl : gen->position) {
tl.Init();
}
Animation::GraphManager::GetSingleton()->AttachGenerator(RE::PlayerCharacter::GetSingleton(), std::move(gen), 1.0f);
gen->InitTimelines();
Animation::GraphManager::GetSingleton()->AttachGenerator(actor, std::move(gen), 1.0f);
log->Print("Starting animation...");
}

void ProcessStopCommand(RE::ConsoleLog* log)
void ProcessStopCommand(RE::ConsoleLog* log, RE::TESObjectREFR* refr)
{
Animation::GraphManager::GetSingleton()->DetachGenerator(RE::PlayerCharacter::GetSingleton(), 1.0f);
if (!refr) {
ShowNoActor(log);
return;
}

auto actor = starfield_cast<RE::Actor*>(refr);
if (!actor) {
ShowNoActor(log);
return;
}

Animation::GraphManager::GetSingleton()->DetachGenerator(actor, 1.0f);
log->Print("Stopping animation...");
}

void Run(const std::vector<std::string_view>& args, const std::string_view& fullStr)
void Run(const std::vector<std::string_view>& args, const std::string_view& fullStr, RE::TESObjectREFR* refr)
{
auto log = RE::ConsoleLog::GetSingleton();
log->Print(fullStr.data());
Expand All @@ -60,9 +86,9 @@ namespace Commands::NAFCommand
}

if (args[1] == "play") {
ProcessPlayCommand(args, log);
ProcessPlayCommand(args, log, refr);
} else if (args[1] == "stop") {
ProcessStopCommand(log);
ProcessStopCommand(log, refr);
} else {
ShowHelp(log);
}
Expand Down
2 changes: 1 addition & 1 deletion Plugin/src/Commands/NAFCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

namespace Commands::NAFCommand
{
void Run(const std::vector<std::string_view>& args, const std::string_view& fullStr);
void Run(const std::vector<std::string_view>& args, const std::string_view& fullStr, RE::TESObjectREFR* refr);
}
Loading

0 comments on commit 4624103

Please sign in to comment.