669 lines
24 KiB
C++
669 lines
24 KiB
C++
#include "stdafx.h"
|
|
#include "HumanoidWindow.h"
|
|
#include "ModelImporter.h"
|
|
|
|
using namespace wi::ecs;
|
|
using namespace wi::scene;
|
|
|
|
void HumanoidWindow::Create(EditorComponent* _editor)
|
|
{
|
|
editor = _editor;
|
|
|
|
wi::gui::Window::Create(ICON_HUMANOID " Humanoid", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE | wi::gui::Window::WindowControls::FIT_ALL_WIDGETS_VERTICAL);
|
|
SetSize(XMFLOAT2(670, 620));
|
|
|
|
closeButton.SetTooltip("Delete HumanoidComponent");
|
|
OnClose([this](wi::gui::EventArgs args) {
|
|
|
|
wi::Archive& archive = editor->AdvanceHistory();
|
|
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
editor->GetCurrentScene().humanoids.Remove(entity);
|
|
|
|
editor->RecordEntity(archive, entity);
|
|
|
|
editor->componentsWnd.RefreshEntityTree();
|
|
});
|
|
|
|
infoLabel.Create("");
|
|
infoLabel.SetText("This window will stay open even if you select other entities until it is collapsed, so you can select other bone entities.");
|
|
infoLabel.SetFitTextEnabled(true);
|
|
AddWidget(&infoLabel);
|
|
|
|
auto forEachSelected = [this] (auto func) {
|
|
return [this, func] (auto args) {
|
|
wi::scene::Scene& scene = editor->GetCurrentScene();
|
|
HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity);
|
|
if (humanoid != nullptr) {
|
|
func(humanoid, args);
|
|
}
|
|
};
|
|
};
|
|
|
|
lookatCheckBox.Create("Look At: ");
|
|
lookatCheckBox.SetTooltip("Enable updating the lookAt direction. If enabled, head will turn to face the lookAt point.\nA sample lookAt point can be generated by the editor if you enable the Follow mouse option.");
|
|
lookatCheckBox.OnClick(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->SetLookAtEnabled(args.bValue);
|
|
}));
|
|
AddWidget(&lookatCheckBox);
|
|
|
|
lookatMouseCheckBox.Create("Follow mouse: ");
|
|
lookatMouseCheckBox.SetTooltip("Generates a sample lookAt point at the mouse position. If LookAt is enabled, the character's head will try to face in the direction of the mouse");
|
|
AddWidget(&lookatMouseCheckBox);
|
|
lookatMouseCheckBox.SetCheck(true);
|
|
|
|
lookatEntityCombo.Create("Look At Entity: ");
|
|
lookatEntityCombo.SetTooltip("If this is set to an entity with TransformComponent, it will override the lookAt position that was set directly and it will also be saved with the scene.");
|
|
lookatEntityCombo.OnSelect(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->lookAtEntity = (Entity)args.userdata;
|
|
}));
|
|
AddWidget(&lookatEntityCombo);
|
|
|
|
ragdollDisabledCheckBox.Create("Ragdoll Disabled: ");
|
|
ragdollDisabledCheckBox.SetTooltip("Completely disable ragdoll physics creation for this humanoid.\nUseful for cases where the humanoid skeleton should not have any physics interaction.");
|
|
ragdollDisabledCheckBox.OnClick(forEachSelected([this] (auto humanoid, auto args) {
|
|
humanoid->SetRagdollDisabled(args.bValue);
|
|
if (args.bValue)
|
|
{
|
|
humanoid->ragdoll = {}; // immediately delete ragdoll if disabled
|
|
}
|
|
ragdollCheckBox.SetEnabled(!args.bValue);
|
|
}));
|
|
AddWidget(&ragdollDisabledCheckBox);
|
|
|
|
ragdollCheckBox.Create("Ragdoll Physics Enabled: ");
|
|
ragdollCheckBox.SetTooltip("Activate dynamic ragdoll physics.\nNote that kinematic ragdoll physics is always active (ragdoll is animation-driven/kinematic by default).\nNote that scaling humanoid will disable ragdoll physics and you need to re-enable if you want to.");
|
|
ragdollCheckBox.OnClick(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->SetRagdollPhysicsEnabled(args.bValue);
|
|
}));
|
|
AddWidget(&ragdollCheckBox);
|
|
|
|
capsuleShadowCheckBox.Create("Capsule Shadow Disabled: ");
|
|
capsuleShadowCheckBox.SetTooltip("Disable capsule shadow for this specific humanoid.");
|
|
capsuleShadowCheckBox.OnClick(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->SetCapsuleShadowDisabled(args.bValue);
|
|
}));
|
|
AddWidget(&capsuleShadowCheckBox);
|
|
|
|
headRotMaxXSlider.Create(0, 90, 60, 180, "Head horizontal: ");
|
|
headRotMaxXSlider.SetTooltip("Limit horizontal head movement (input in degrees)");
|
|
headRotMaxXSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->head_rotation_max.x = wi::math::DegreesToRadians(args.fValue);
|
|
}));
|
|
AddWidget(&headRotMaxXSlider);
|
|
|
|
headRotMaxYSlider.Create(0, 60, 30, 60, "Head vertical: ");
|
|
headRotMaxYSlider.SetTooltip("Limit vertical head movement (input in degrees)");
|
|
headRotMaxYSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->head_rotation_max.y = wi::math::DegreesToRadians(args.fValue);
|
|
}));
|
|
AddWidget(&headRotMaxYSlider);
|
|
|
|
headRotSpeedSlider.Create(0.05f, 1, 0.1f, 1000, "Head speed: ");
|
|
headRotSpeedSlider.SetTooltip("Adjust head turning speed.");
|
|
headRotSpeedSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->head_rotation_speed = args.fValue;
|
|
}));
|
|
AddWidget(&headRotSpeedSlider);
|
|
|
|
|
|
eyeRotMaxXSlider.Create(0, 40, 20, 40, "Eye horizontal: ");
|
|
eyeRotMaxXSlider.SetTooltip("Limit horizontal eye movement (input in degrees)");
|
|
eyeRotMaxXSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->eye_rotation_max.x = wi::math::DegreesToRadians(args.fValue);
|
|
}));
|
|
AddWidget(&eyeRotMaxXSlider);
|
|
|
|
eyeRotMaxYSlider.Create(0, 30, 15, 30, "Eye vertical: ");
|
|
eyeRotMaxYSlider.SetTooltip("Limit vertical eye movement (input in degrees)");
|
|
eyeRotMaxYSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->eye_rotation_max.y = wi::math::DegreesToRadians(args.fValue);
|
|
}));
|
|
AddWidget(&eyeRotMaxYSlider);
|
|
|
|
eyeRotSpeedSlider.Create(0.05f, 1, 0.2f, 1000, "Eye speed: ");
|
|
eyeRotSpeedSlider.SetTooltip("Adjust eye turning speed.");
|
|
eyeRotSpeedSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->eye_rotation_speed = args.fValue;
|
|
}));
|
|
AddWidget(&eyeRotSpeedSlider);
|
|
|
|
headSizeSlider.Create(0.5f, 2, 1, 1000, "Head size: ");
|
|
headSizeSlider.SetTooltip("Adjust head size.");
|
|
headSizeSlider.OnSlide(forEachSelected([this] (auto humanoid, auto args) {
|
|
Entity bone = humanoid->bones[size_t(HumanoidComponent::HumanoidBone::Head)];
|
|
wi::scene::Scene& scene = editor->GetCurrentScene();
|
|
TransformComponent* transform = scene.transforms.GetComponent(bone);
|
|
if (transform != nullptr)
|
|
{
|
|
transform->SetDirty();
|
|
transform->scale_local.x = args.fValue;
|
|
transform->scale_local.y = args.fValue;
|
|
transform->scale_local.z = args.fValue;
|
|
}
|
|
}));
|
|
AddWidget(&headSizeSlider);
|
|
|
|
ragdollFatnessSlider.Create(0.5f, 2, 1, 1000, "Ragdoll fatness: ");
|
|
ragdollFatnessSlider.SetTooltip("Adjust overall fatness of ragdoll physics skeleton.");
|
|
ragdollFatnessSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->ragdoll_fatness = args.fValue;
|
|
humanoid->ragdoll = {}; // request recreate
|
|
}));
|
|
AddWidget(&ragdollFatnessSlider);
|
|
|
|
ragdollHeadSizeSlider.Create(0.5f, 2, 1, 1000, "Ragdoll head: ");
|
|
ragdollHeadSizeSlider.SetTooltip("Adjust overall size of ragdoll physics head.");
|
|
ragdollHeadSizeSlider.OnSlide(forEachSelected([] (auto humanoid, auto args) {
|
|
humanoid->ragdoll_headsize = args.fValue;
|
|
humanoid->ragdoll = {}; // request recreate
|
|
}));
|
|
AddWidget(&ragdollHeadSizeSlider);
|
|
|
|
armSpacingSlider.Create(-1, 1, 0, 100, "Arm spacing: ");
|
|
armSpacingSlider.SetTooltip("Adjust distance between arms.");
|
|
armSpacingSlider.OnSlide(forEachSelected([](auto humanoid, auto args) {
|
|
humanoid->arm_spacing = args.fValue;
|
|
}));
|
|
AddWidget(&armSpacingSlider);
|
|
|
|
legSpacingSlider.Create(-1, 1, 0, 100, "Leg spacing: ");
|
|
legSpacingSlider.SetTooltip("Adjust distance between legs.");
|
|
legSpacingSlider.OnSlide(forEachSelected([](auto humanoid, auto args) {
|
|
humanoid->leg_spacing = args.fValue;
|
|
}));
|
|
AddWidget(&legSpacingSlider);
|
|
|
|
boneList.Create("Bones: ");
|
|
boneList.OnSelect([this](wi::gui::EventArgs args) {
|
|
|
|
if (args.iValue < 0)
|
|
return;
|
|
|
|
wi::Archive& archive = editor->AdvanceHistory(true);
|
|
archive << EditorComponent::HISTORYOP_SELECTION;
|
|
// record PREVIOUS selection state...
|
|
editor->RecordSelection(archive);
|
|
|
|
editor->translator.selected.clear();
|
|
|
|
for (int i = 0; i < boneList.GetItemCount(); ++i)
|
|
{
|
|
const wi::gui::TreeList::Item& item = boneList.GetItem(i);
|
|
if (item.selected)
|
|
{
|
|
wi::scene::PickResult pick;
|
|
pick.entity = (Entity)item.userdata;
|
|
if (pick.entity != INVALID_ENTITY)
|
|
{
|
|
editor->AddSelected(pick);
|
|
}
|
|
}
|
|
}
|
|
|
|
// record NEW selection state...
|
|
editor->RecordSelection(archive);
|
|
|
|
editor->componentsWnd.RefreshEntityTree();
|
|
|
|
});
|
|
AddWidget(&boneList);
|
|
|
|
|
|
|
|
importAnimationsButton.Create(ICON_ANIMATION " Import animations");
|
|
importAnimationsButton.SetTooltip("Import animations from a scene or model file and retarget them to this humanoid.");
|
|
importAnimationsButton.OnClick([=](wi::gui::EventArgs args) {
|
|
wi::helper::FileDialogParams params;
|
|
params.type = wi::helper::FileDialogParams::OPEN;
|
|
params.description = "Animated models (wiscene, gltf, fbx, vrm, vrma)";
|
|
params.extensions = { "WISCENE", "GLTF", "GLB", "FBX", "VRM", "VRMA" };
|
|
wi::helper::FileDialog(params, [this](std::string fileName) {
|
|
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
|
|
std::string ext = wi::helper::toUpper(wi::helper::GetExtensionFromFileName(fileName));
|
|
|
|
Scene animscene;
|
|
if (!ext.compare("WISCENE"))
|
|
{
|
|
wi::scene::LoadModel(animscene, fileName);
|
|
}
|
|
else if (!ext.compare("GLTF") || !ext.compare("GLB") || !ext.compare("VRM") || !ext.compare("VRMA"))
|
|
{
|
|
ImportModel_GLTF(fileName, animscene);
|
|
}
|
|
else if (!ext.compare("FBX"))
|
|
{
|
|
ImportModel_FBX(fileName, animscene);
|
|
}
|
|
|
|
wilog("Started importing animations from file: %s", fileName.c_str());
|
|
int import_count = 0;
|
|
|
|
Scene& scene = editor->GetCurrentScene();
|
|
for (auto& x : editor->translator.selected)
|
|
{
|
|
if (!scene.humanoids.Contains(x.entity))
|
|
continue;
|
|
Entity humanoidentity = x.entity;
|
|
const NameComponent* name_dest = scene.names.GetComponent(humanoidentity);
|
|
std::string humanoidname = name_dest == nullptr ? std::to_string(humanoidentity) : name_dest->name;
|
|
scene.ResetPose(humanoidentity);
|
|
for (size_t j = 0; j < animscene.animations.GetCount(); ++j)
|
|
{
|
|
Entity animentity = animscene.animations.GetEntity(j);
|
|
Entity retarget_entity = scene.RetargetAnimation(humanoidentity, animentity, true, &animscene);
|
|
if (retarget_entity != INVALID_ENTITY)
|
|
{
|
|
NameComponent name;
|
|
const NameComponent* name_source = animscene.names.GetComponent(animentity);
|
|
if (name_source != nullptr)
|
|
{
|
|
name.name += name_source->name;
|
|
}
|
|
scene.names.Create(retarget_entity) = name;
|
|
wilog("\tFound a humanoid animation and successfully retargetted: %s -> %s", name.name.c_str(), humanoidname.c_str());
|
|
import_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
wilog("Finished importing %d animations from file.", import_count);
|
|
|
|
editor->componentsWnd.RefreshEntityTree();
|
|
});
|
|
});
|
|
});
|
|
AddWidget(&importAnimationsButton);
|
|
|
|
animationTesterCombo.Create("Animation tester: ");
|
|
animationTesterCombo.SetTooltip("Select an animation from the list of children to this humanoid.\nThe selected animation will be played instantly and others will be stopped.");
|
|
animationTesterCombo.OnSelect([this](wi::gui::EventArgs args){
|
|
Scene& scene = editor->GetCurrentScene();
|
|
for (size_t i = 0; i < scene.animations.GetCount(); ++i)
|
|
{
|
|
if (!scene.Entity_IsDescendant(scene.animations.GetEntity(i), entity))
|
|
continue;
|
|
scene.animations[i].Stop();
|
|
}
|
|
if (scene.Entity_IsDescendant((Entity)args.userdata, entity))
|
|
{
|
|
AnimationComponent* anim = scene.animations.GetComponent((Entity)args.userdata);
|
|
if (anim != nullptr)
|
|
{
|
|
anim->Play();
|
|
}
|
|
}
|
|
else if (args.userdata == INVALID_ENTITY)
|
|
{
|
|
scene.ResetPose(entity);
|
|
}
|
|
});
|
|
AddWidget(&animationTesterCombo);
|
|
|
|
|
|
SetMinimized(true);
|
|
SetVisible(false);
|
|
|
|
SetEntity(INVALID_ENTITY);
|
|
}
|
|
|
|
void HumanoidWindow::SetEntity(Entity entity)
|
|
{
|
|
Scene& scene = editor->GetCurrentScene();
|
|
|
|
const HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity);
|
|
|
|
if (humanoid != nullptr)
|
|
{
|
|
ragdollCheckBox.SetCheck(humanoid->IsRagdollPhysicsEnabled()); // this is always force updated
|
|
}
|
|
|
|
if (humanoid != nullptr || IsCollapsed())
|
|
{
|
|
if (this->entity != entity)
|
|
{
|
|
this->entity = entity;
|
|
RefreshBoneList();
|
|
}
|
|
|
|
if (humanoid != nullptr)
|
|
{
|
|
lookatCheckBox.SetCheck(humanoid->IsLookAtEnabled());
|
|
ragdollDisabledCheckBox.SetCheck(humanoid->IsRagdollDisabled());
|
|
ragdollCheckBox.SetCheck(humanoid->IsRagdollPhysicsEnabled());
|
|
ragdollCheckBox.SetEnabled(!humanoid->IsRagdollDisabled());
|
|
capsuleShadowCheckBox.SetCheck(humanoid->IsCapsuleShadowDisabled());
|
|
headRotMaxXSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.x));
|
|
headRotMaxYSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.y));
|
|
headRotSpeedSlider.SetValue(humanoid->head_rotation_speed);
|
|
eyeRotMaxXSlider.SetValue(wi::math::RadiansToDegrees(humanoid->eye_rotation_max.x));
|
|
eyeRotMaxYSlider.SetValue(wi::math::RadiansToDegrees(humanoid->eye_rotation_max.y));
|
|
eyeRotSpeedSlider.SetValue(humanoid->eye_rotation_speed);
|
|
ragdollFatnessSlider.SetValue(humanoid->ragdoll_fatness);
|
|
ragdollHeadSizeSlider.SetValue(humanoid->ragdoll_headsize);
|
|
armSpacingSlider.SetValue(humanoid->arm_spacing);
|
|
legSpacingSlider.SetValue(humanoid->leg_spacing);
|
|
|
|
Entity bone = humanoid->bones[size_t(HumanoidComponent::HumanoidBone::Head)];
|
|
const TransformComponent* transform = scene.transforms.GetComponent(bone);
|
|
if (transform != nullptr)
|
|
{
|
|
headSizeSlider.SetValue(transform->scale_local.x);
|
|
}
|
|
|
|
lookatEntityCombo.ClearItems();
|
|
lookatEntityCombo.AddItem("NONE " ICON_DISABLED, INVALID_ENTITY);
|
|
for (size_t i = 0; i < scene.transforms.GetCount(); ++i)
|
|
{
|
|
Entity transformEntity = scene.transforms.GetEntity(i);
|
|
const NameComponent* name = scene.names.GetComponent(transformEntity);
|
|
lookatEntityCombo.AddItem((name == nullptr || name->name.empty()) ? std::to_string(transformEntity) : name->name, transformEntity);
|
|
if (humanoid->lookAtEntity == transformEntity)
|
|
{
|
|
lookatEntityCombo.SetSelectedWithoutCallback((int)lookatEntityCombo.GetItemCount() - 1);
|
|
}
|
|
}
|
|
|
|
Entity prevselectedanim = animationTesterCombo.GetSelectedUserdata();
|
|
animationTesterCombo.ClearItems();
|
|
animationTesterCombo.AddItem("NONE " ICON_DISABLED, INVALID_ENTITY);
|
|
for (size_t i = 0; i < scene.animations.GetCount(); ++i)
|
|
{
|
|
Entity animationentity = scene.animations.GetEntity(i);
|
|
if (!scene.Entity_IsDescendant(animationentity, entity))
|
|
continue;
|
|
const NameComponent* name = scene.names.GetComponent(animationentity);
|
|
animationTesterCombo.AddItem((name == nullptr || name->name.empty()) ? std::to_string(animationentity) : name->name, (uint64_t)animationentity);
|
|
if (prevselectedanim == animationentity)
|
|
{
|
|
animationTesterCombo.SetSelectedWithoutCallback((int)animationTesterCombo.GetItemCount() - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void HumanoidWindow::RefreshBoneList()
|
|
{
|
|
Scene& scene = editor->GetCurrentScene();
|
|
|
|
const HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity);
|
|
|
|
if (humanoid != nullptr)
|
|
{
|
|
boneList.ClearItems();
|
|
for (int i = 0; i < arraysize(humanoid->bones); ++i)
|
|
{
|
|
HumanoidComponent::HumanoidBone type = (HumanoidComponent::HumanoidBone)i;
|
|
Entity bone = humanoid->bones[i];
|
|
|
|
wi::gui::TreeList::Item item;
|
|
item.userdata = bone;
|
|
item.level = 1;
|
|
|
|
item.name += ICON_BONE " [";
|
|
|
|
switch (type)
|
|
{
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Hips:
|
|
boneList.AddItem("Torso"); // grouping item
|
|
item.name += "Hips";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Spine:
|
|
item.name += "Spine";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Chest:
|
|
item.name += "Chest";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::UpperChest:
|
|
item.name += "UpperChest";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Neck:
|
|
item.name += "Neck";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Head:
|
|
boneList.AddItem("Head"); // grouping item
|
|
item.name += "Head";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftEye:
|
|
item.name += "LeftEye";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightEye:
|
|
item.name += "RightEye";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::Jaw:
|
|
item.name += "Jaw";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftUpperLeg:
|
|
boneList.AddItem("Legs"); // grouping item
|
|
item.name += "LeftUpperLeg";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftLowerLeg:
|
|
item.name += "LeftLowerLeg";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftFoot:
|
|
item.name += "LeftFoot";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftToes:
|
|
item.name += "LeftToes";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightUpperLeg:
|
|
item.name += "RightUpperLeg";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightLowerLeg:
|
|
item.name += "RightLowerLeg";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightFoot:
|
|
item.name += "RightFoot";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightToes:
|
|
item.name += "RightToes";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftShoulder:
|
|
boneList.AddItem("Arms"); // grouping item
|
|
item.name += "LeftShoulder";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftUpperArm:
|
|
item.name += "LeftUpperArm";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftLowerArm:
|
|
item.name += "LeftLowerArm";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftHand:
|
|
item.name += "LeftHand";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightShoulder:
|
|
item.name += "RightShoulder";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightUpperArm:
|
|
item.name += "RightUpperArm";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightLowerArm:
|
|
item.name += "RightLowerArm";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightHand:
|
|
item.name += "RightHand";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftThumbMetacarpal:
|
|
boneList.AddItem("Fingers"); // grouping item
|
|
item.name += "LeftThumbMetacarpal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftThumbProximal:
|
|
item.name += "LeftThumbProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftThumbDistal:
|
|
item.name += "LeftThumbDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftIndexProximal:
|
|
item.name += "LeftIndexProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftIndexIntermediate:
|
|
item.name += "LeftIndexIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftIndexDistal:
|
|
item.name += "LeftIndexDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftMiddleProximal:
|
|
item.name += "LeftMiddleProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftMiddleIntermediate:
|
|
item.name += "LeftMiddleIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftMiddleDistal:
|
|
item.name += "LeftMiddleDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftRingProximal:
|
|
item.name += "LeftRingProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftRingIntermediate:
|
|
item.name += "LeftRingIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftRingDistal:
|
|
item.name += "LeftRingDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftLittleProximal:
|
|
item.name += "LeftLittleProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftLittleIntermediate:
|
|
item.name += "LeftLittleIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::LeftLittleDistal:
|
|
item.name += "LeftLittleDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightThumbMetacarpal:
|
|
item.name += "RightThumbMetacarpal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightThumbProximal:
|
|
item.name += "RightThumbProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightThumbDistal:
|
|
item.name += "RightThumbDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightIndexIntermediate:
|
|
item.name += "RightIndexIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightIndexDistal:
|
|
item.name += "RightIndexDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightIndexProximal:
|
|
item.name += "RightIndexProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightMiddleProximal:
|
|
item.name += "RightMiddleProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightMiddleIntermediate:
|
|
item.name += "RightMiddleIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightMiddleDistal:
|
|
item.name += "RightMiddleDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightRingProximal:
|
|
item.name += "RightRingProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightRingIntermediate:
|
|
item.name += "RightRingIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightRingDistal:
|
|
item.name += "RightRingDistal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightLittleProximal:
|
|
item.name += "RightLittleProximal";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightLittleIntermediate:
|
|
item.name += "RightLittleIntermediate";
|
|
break;
|
|
case wi::scene::HumanoidComponent::HumanoidBone::RightLittleDistal:
|
|
item.name += "RightLittleDistal";
|
|
break;
|
|
default:
|
|
assert(0); // unhandled type
|
|
break;
|
|
}
|
|
item.name += "] ";
|
|
|
|
if (bone == INVALID_ENTITY)
|
|
{
|
|
item.name += ICON_DISABLED;
|
|
}
|
|
else
|
|
{
|
|
const NameComponent* name = scene.names.GetComponent(bone);
|
|
if (name == nullptr)
|
|
{
|
|
item.name += "[no_name] " + std::to_string(bone);
|
|
}
|
|
else if (name->name.empty())
|
|
{
|
|
item.name += "[name_empty] " + std::to_string(bone);
|
|
}
|
|
else
|
|
{
|
|
item.name += name->name;
|
|
}
|
|
}
|
|
|
|
boneList.AddItem(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HumanoidWindow::ResizeLayout()
|
|
{
|
|
wi::gui::Window::ResizeLayout();
|
|
layout.margin_left = 110;
|
|
|
|
layout.add_fullwidth(infoLabel);
|
|
layout.add_right(lookatCheckBox);
|
|
lookatMouseCheckBox.SetPos(XMFLOAT2(lookatCheckBox.GetPos().x - 120, lookatCheckBox.GetPos().y));
|
|
layout.add(lookatEntityCombo);
|
|
layout.add_right(ragdollDisabledCheckBox);
|
|
layout.add_right(ragdollCheckBox);
|
|
layout.add_right(capsuleShadowCheckBox);
|
|
layout.add(headRotMaxXSlider);
|
|
layout.add(headRotMaxYSlider);
|
|
layout.add(headRotSpeedSlider);
|
|
layout.add(eyeRotMaxXSlider);
|
|
layout.add(eyeRotMaxYSlider);
|
|
layout.add(eyeRotSpeedSlider);
|
|
layout.add(headSizeSlider);
|
|
layout.add(ragdollFatnessSlider);
|
|
layout.add(ragdollHeadSizeSlider);
|
|
layout.add(armSpacingSlider);
|
|
layout.add(legSpacingSlider);
|
|
|
|
layout.jump();
|
|
|
|
layout.add_fullwidth(importAnimationsButton);
|
|
layout.add_fullwidth(animationTesterCombo);
|
|
|
|
layout.jump();
|
|
|
|
layout.add_fullwidth(boneList);
|
|
|
|
}
|
|
|
|
void HumanoidWindow::UpdateHumanoids()
|
|
{
|
|
// Update humanoids to look at mouse:
|
|
if (lookatMouseCheckBox.GetCheck())
|
|
{
|
|
Scene& scene = editor->GetCurrentScene();
|
|
const CameraComponent& camera = editor->GetCurrentEditorScene().camera;
|
|
wi::primitive::Ray ray = editor->pickRay;
|
|
|
|
for (size_t i = 0; i < scene.humanoids.GetCount(); ++i)
|
|
{
|
|
HumanoidComponent& humanoid = scene.humanoids[i];
|
|
|
|
Entity bone = humanoid.bones[size_t(HumanoidComponent::HumanoidBone::Head)];
|
|
const TransformComponent* transform = scene.transforms.GetComponent(bone);
|
|
if (transform != nullptr)
|
|
{
|
|
float dist = wi::math::Distance(transform->GetPosition(), ray.origin);
|
|
dist = std::min(1.0f, dist);
|
|
XMStoreFloat3(&humanoid.lookAt, camera.GetEye() + XMLoadFloat3(&ray.direction) * dist); // look at near plane position
|
|
}
|
|
}
|
|
}
|
|
}
|