ANIMATION: configure more values via lua
parent
99abef4d13
commit
1a688e8d87
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "voxelformat/MeshCache.h"
|
||||
#include "AnimationSettings.h"
|
||||
#include "core/Assert.h"
|
||||
#include <string>
|
||||
|
||||
namespace animation {
|
||||
|
||||
/**
|
||||
* @brief Cache @c voxel::Mesh instances for @c AnimationEntity
|
||||
*/
|
||||
template<typename T>
|
||||
class AnimationCache : public voxelformat::MeshCache {
|
||||
protected:
|
||||
bool load(const std::string& filename, size_t meshIndex, const voxel::Mesh* (&meshes)[std::enum_value(T::Max)]) {
|
||||
voxel::Mesh& mesh = cacheEntry(filename.c_str());
|
||||
if (mesh.getNoOfVertices() > 0) {
|
||||
meshes[meshIndex] = &mesh;
|
||||
return true;
|
||||
}
|
||||
if (loadMesh(filename.c_str(), mesh)) {
|
||||
meshes[meshIndex] = &mesh;
|
||||
return true;
|
||||
}
|
||||
meshes[meshIndex] = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getMeshes(const AnimationSettings<T>& settings, const voxel::Mesh* (&meshes)[std::enum_value(T::Max)],
|
||||
std::function<bool()> loadAdditional = {}) {
|
||||
for (size_t i = 0; i < settings.paths.size(); ++i) {
|
||||
if (settings.paths[i].empty()) {
|
||||
meshes[i] = nullptr;
|
||||
continue;
|
||||
}
|
||||
const std::string& fullPath = settings.fullPath((T)i);
|
||||
if (!load(fullPath, i, meshes)) {
|
||||
Log::error("Failed to load %s", fullPath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (loadAdditional && !loadAdditional()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
bool getModel(const char *fullPath, BoneId bid, Vertices& vertices, Indices& indices) {
|
||||
voxel::Mesh& mesh = cacheEntry(fullPath);
|
||||
if (mesh.getNoOfVertices() <= 0) {
|
||||
if (!loadMesh(fullPath, mesh)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
const uint8_t boneIdInt = std::enum_value(bid);
|
||||
vertices.reserve(mesh.getNoOfVertices());
|
||||
for (const voxel::VoxelVertex& v : mesh.getVertexVector()) {
|
||||
vertices.emplace_back(Vertex{v.position, v.colorIndex, boneIdInt, v.ambientOcclusion});
|
||||
}
|
||||
//vertices.resize(mesh.getNoOfVertices());
|
||||
|
||||
indices.reserve(mesh.getNoOfIndices());
|
||||
for (voxel::IndexType idx : mesh.getIndexVector()) {
|
||||
indices.push_back((IndexType)idx);
|
||||
}
|
||||
//indices.resize(mesh.getNoOfIndices());
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/String.h"
|
||||
#include "core/Common.h"
|
||||
#include "Animation.h"
|
||||
#include "BoneId.h"
|
||||
#include <array>
|
||||
|
||||
namespace animation {
|
||||
|
||||
static inline std::string luaFilename(const char *character) {
|
||||
return core::string::format("%s.lua", character);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct AnimationSettings {
|
||||
std::array<std::string, std::enum_value(T::Max)> paths;
|
||||
std::string basePath;
|
||||
BoneIds boneIdsArray[std::enum_value(T::Max)] {};
|
||||
|
||||
std::string fullPath(T type, const char* name) const {
|
||||
const std::string& p = path(type, name);
|
||||
return core::string::format("%s/%s.vox", basePath.c_str(), p.c_str());
|
||||
}
|
||||
|
||||
std::string fullPath(T type) const {
|
||||
const std::string& p = path(type);
|
||||
return core::string::format("%s/%s.vox", basePath.c_str(), p.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the original path the settings were loaded with
|
||||
*/
|
||||
const std::string& path(T type) const {
|
||||
if (paths[std::enum_value(type)].empty()) {
|
||||
static const std::string EMPTY;
|
||||
return EMPTY;
|
||||
}
|
||||
return paths[std::enum_value(type)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the default path for the mesh type, but with a new name
|
||||
*/
|
||||
std::string path(T type, const char *name) const {
|
||||
return core::string::format("%s/%s", animation::toString(type), name);
|
||||
}
|
||||
|
||||
inline void setPath(T type, const char *str) {
|
||||
paths[std::enum_value(type)] = str;
|
||||
}
|
||||
|
||||
inline BoneIds* boneIds(const char *name) {
|
||||
T id = toEnum(name);
|
||||
if (id == T::Max) {
|
||||
return nullptr;
|
||||
}
|
||||
return &boneIdsArray[(int)id];
|
||||
}
|
||||
|
||||
inline const BoneIds& boneIds(T id) const {
|
||||
core_assert(id != T::Max);
|
||||
return boneIdsArray[(int)id];
|
||||
}
|
||||
|
||||
inline const BoneIds& boneIds(size_t id) const {
|
||||
return boneIdsArray[id];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BoneId.h"
|
||||
#include "core/Array.h"
|
||||
#include "core/Common.h"
|
||||
|
||||
namespace animation {
|
||||
|
||||
static const char *boneId_strings[] = { "head", "chest", "belt", "pants",
|
||||
"lefthand", "righthand", "leftfoot", "rightfoot", "tool",
|
||||
"leftshoulder", "rightshoulder", "glider", "torso",
|
||||
"leftwing", "rightwing", "tail" };
|
||||
static_assert(lengthof(boneId_strings) == std::enum_value(BoneId::Max), "Invalid bone array dimensions");
|
||||
|
||||
BoneId toBoneId(const char *name) {
|
||||
for (int i = 0; i < lengthof(boneId_strings); ++i) {
|
||||
if (!strcmp(name, boneId_strings[i])) {
|
||||
return (BoneId)i;
|
||||
}
|
||||
}
|
||||
return BoneId::Max;
|
||||
}
|
||||
|
||||
const char* toBoneId(const BoneId id) {
|
||||
return boneId_strings[std::enum_value(id)];
|
||||
}
|
||||
|
||||
}
|
|
@ -30,10 +30,13 @@ enum class BoneId : uint8_t {
|
|||
Max
|
||||
};
|
||||
|
||||
extern BoneId toBoneId(const char *name);
|
||||
extern const char* toBoneId(const BoneId id);
|
||||
|
||||
struct BoneIds {
|
||||
uint8_t bones[2];
|
||||
uint8_t bones[2] { 0, 0 };
|
||||
bool mirrored[2] { false, false };
|
||||
uint8_t num;
|
||||
uint8_t num = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,10 +14,11 @@ set(SRCS
|
|||
chr/LUAFunctions.h
|
||||
|
||||
Animation.cpp Animation.h
|
||||
AnimationCache.h
|
||||
AnimationRenderer.cpp AnimationRenderer.h
|
||||
AnimationEntity.h
|
||||
Bone.cpp Bone.h
|
||||
BoneId.h
|
||||
BoneId.cpp BoneId.h
|
||||
BoneUtil.h
|
||||
Skeleton.h Skeleton.cpp
|
||||
SkeletonAttribute.h
|
||||
|
@ -87,6 +88,8 @@ set(FILES
|
|||
voxel/models/items/sword-2.vox
|
||||
)
|
||||
set(LUA_SRCS
|
||||
chr/bones.lua
|
||||
|
||||
chr/dwarf-male-blacksmith.lua
|
||||
|
||||
chr/human-male-blacksmith.lua
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BoneId.h"
|
||||
#include "commonlua/LUAFunctions.h"
|
||||
#include "AnimationCache.h"
|
||||
|
||||
template<> struct clua_meta<animation::BoneIds> { static char const *name() {return "__meta_boneids";} };
|
||||
|
||||
namespace animation {
|
||||
|
||||
static int luaanim_boneidstostring(lua_State* s) {
|
||||
BoneIds** a = clua_get<BoneIds*>(s, 1);
|
||||
BoneIds& boneIds = **a;
|
||||
if (boneIds.num == 0) {
|
||||
lua_pushstring(s, "empty");
|
||||
return 1;
|
||||
}
|
||||
if (boneIds.num == 1) {
|
||||
lua_pushfstring(s, "num bones: 1, bone[0]: %i", (int)boneIds.bones[0]);
|
||||
return 1;
|
||||
}
|
||||
if (boneIds.num == 2) {
|
||||
lua_pushfstring(s, "num bones: 2, bone[0]: %i, bone[1]: %i", (int)boneIds.bones[0], (int)boneIds.bones[1]);
|
||||
return 1;
|
||||
}
|
||||
lua_pushfstring(s, "error: num bones: %i", (*a)->num);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaanim_boneidsadd(lua_State* s) {
|
||||
BoneIds** boneIdsPtrPtr = clua_get<BoneIds*>(s, 1);
|
||||
BoneIds* boneIds = *boneIdsPtrPtr;
|
||||
const char* boneName = luaL_checkstring(s, 2);
|
||||
BoneId id = toBoneId(boneName);
|
||||
if (id == BoneId::Max) {
|
||||
return luaL_error(s, "Failed to resolve bone: '%s'", boneName);
|
||||
}
|
||||
if (boneIds->num > lengthof(boneIds->bones)) {
|
||||
lua_pushboolean(s, 0);
|
||||
return 1;
|
||||
}
|
||||
boneIds->bones[boneIds->num] = (uint8_t)id;
|
||||
boneIds->mirrored[boneIds->num] = clua_optboolean(s, 3, false);
|
||||
boneIds->num++;
|
||||
lua_pushboolean(s, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void luaanim_boneidsregister(lua_State* s) {
|
||||
std::vector<luaL_Reg> funcs = {
|
||||
{"__tostring", luaanim_boneidstostring},
|
||||
{"add", luaanim_boneidsadd},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
clua_registerfuncs(s, &funcs.front(), clua_meta<BoneIds>::name());
|
||||
}
|
||||
|
||||
int luaanim_pushboneids(lua_State* s, BoneIds* b) {
|
||||
return clua_push(s, b);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int luaanim_bonesetup(lua_State* l) {
|
||||
T* settings = lua::LUA::globalData<T>(l, "Settings");
|
||||
const char* meshType = luaL_checkstring(l, 1);
|
||||
BoneIds* b = settings->boneIds(meshType);
|
||||
if (b == nullptr) {
|
||||
return luaL_error(l, "Failed to resolve mesh type: '%s'", meshType);
|
||||
}
|
||||
*b = BoneIds {};
|
||||
if (luaanim_pushboneids(l, b) != 1) {
|
||||
return luaL_error(l, "Failed to push the bonesids");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -31,7 +31,7 @@ bool Character::init(const CharacterCachePtr& cache, const std::string& luaStrin
|
|||
bool Character::initSettings(const std::string& luaString) {
|
||||
CharacterSettings settings;
|
||||
if (loadCharacterSettings(luaString, settings)) {
|
||||
_settings.copyFrom(settings);
|
||||
_settings = settings;
|
||||
return true;
|
||||
}
|
||||
Log::warn("Failed to load the character settings");
|
||||
|
|
|
@ -12,60 +12,6 @@
|
|||
|
||||
namespace animation {
|
||||
|
||||
/**
|
||||
* @return The used bones for a given mesh type.
|
||||
* @note If you have mirrored bones like right, left hand, make sure that you set the mirrored
|
||||
* boolean properly. Otherwise the winding order is not fixed while assembling the ibo
|
||||
*/
|
||||
static inline BoneIds boneIds(CharacterMeshType type) {
|
||||
BoneIds b;
|
||||
switch (type) {
|
||||
case CharacterMeshType::Head:
|
||||
b.num = 1;
|
||||
b.bones[0] = std::enum_value(BoneId::Head);
|
||||
break;
|
||||
case CharacterMeshType::Chest:
|
||||
b.num = 1;
|
||||
b.bones[0] = std::enum_value(BoneId::Chest);
|
||||
break;
|
||||
case CharacterMeshType::Belt:
|
||||
b.num = 1;
|
||||
b.bones[0] = std::enum_value(BoneId::Belt);
|
||||
break;
|
||||
case CharacterMeshType::Pants:
|
||||
b.num = 1;
|
||||
b.bones[0] = std::enum_value(BoneId::Pants);
|
||||
break;
|
||||
case CharacterMeshType::Hand:
|
||||
b.num = 2;
|
||||
b.bones[0] = std::enum_value(BoneId::RightHand);
|
||||
b.bones[1] = std::enum_value(BoneId::LeftHand);
|
||||
b.mirrored[1] = true;
|
||||
break;
|
||||
case CharacterMeshType::Foot:
|
||||
b.num = 2;
|
||||
b.bones[0] = std::enum_value(BoneId::RightFoot);
|
||||
b.bones[1] = std::enum_value(BoneId::LeftFoot);
|
||||
b.mirrored[1] = true;
|
||||
break;
|
||||
case CharacterMeshType::Shoulder:
|
||||
b.num = 2;
|
||||
b.bones[0] = std::enum_value(BoneId::RightShoulder);
|
||||
b.bones[1] = std::enum_value(BoneId::LeftShoulder);
|
||||
b.mirrored[1] = true;
|
||||
break;
|
||||
case CharacterMeshType::Glider:
|
||||
b.num = 1;
|
||||
b.bones[0] = std::enum_value(BoneId::Glider);
|
||||
break;
|
||||
case CharacterMeshType::Max:
|
||||
core_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool CharacterCache::loadGlider(const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]) {
|
||||
const char *fullPath = "models/glider.vox";
|
||||
voxel::Mesh& mesh = cacheEntry(fullPath);
|
||||
|
@ -78,33 +24,16 @@ bool CharacterCache::loadGlider(const voxel::Mesh* (&meshes)[std::enum_value(Cha
|
|||
return true;
|
||||
}
|
||||
meshes[std::enum_value(CharacterMeshType::Glider)] = nullptr;
|
||||
Log::error("Failed to load glider");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterCache::getCharacterMeshes(const CharacterSettings& settings, const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]) {
|
||||
for (size_t i = 0; i < settings.paths.size(); ++i) {
|
||||
if (settings.paths[i] == nullptr || settings.paths[i]->empty()) {
|
||||
meshes[i] = nullptr;
|
||||
continue;
|
||||
}
|
||||
const std::string& fullPath = settings.fullPath((CharacterMeshType)i);
|
||||
if (!load(fullPath, (CharacterMeshType)i, meshes)) {
|
||||
Log::error("Failed to load %s", fullPath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!loadGlider(meshes)) {
|
||||
Log::error("Failed to load glider");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CharacterCache::getCharacterModel(const CharacterSettings& settings, Vertices& vertices, Indices& indices) {
|
||||
const voxel::Mesh* meshes[std::enum_value(CharacterMeshType::Max)] {};
|
||||
if (!getCharacterMeshes(settings, meshes)) {
|
||||
return false;
|
||||
}
|
||||
getMeshes(settings, meshes, [&] () {
|
||||
return loadGlider(meshes);
|
||||
});
|
||||
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
vertices.reserve(3000);
|
||||
|
@ -117,13 +46,15 @@ bool CharacterCache::getCharacterModel(const CharacterSettings& settings, Vertic
|
|||
if (mesh == nullptr) {
|
||||
continue;
|
||||
}
|
||||
const CharacterMeshType meshType = (CharacterMeshType)i;
|
||||
const BoneIds& bids = boneIds(meshType);
|
||||
const BoneIds& bids = settings.boneIds(i);
|
||||
core_assert_msg(bids.num >= 0 && bids.num <= 2,
|
||||
"number of bone ids is invalid: %i (for mesh type %i)q",
|
||||
(int)bids.num, i);
|
||||
for (uint8_t b = 0u; b < bids.num; ++b) {
|
||||
const uint8_t boneId = bids.bones[b];
|
||||
const std::vector<voxel::VoxelVertex>& meshVertices = mesh->getVertexVector();
|
||||
for (voxel::VoxelVertex v : meshVertices) {
|
||||
if (meshType == CharacterMeshType::Foot) {
|
||||
if ((CharacterMeshType)i == CharacterMeshType::Foot) {
|
||||
v.position.y -= settings.skeletonAttr.hipOffset;
|
||||
}
|
||||
vertices.emplace_back(Vertex{v.position, v.colorIndex, boneId, v.ambientOcclusion});
|
||||
|
@ -151,51 +82,13 @@ bool CharacterCache::getCharacterModel(const CharacterSettings& settings, Vertic
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CharacterCache::load(const std::string& filename, CharacterMeshType meshType, const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]) {
|
||||
voxel::Mesh& mesh = cacheEntry(filename.c_str());
|
||||
if (mesh.getNoOfVertices() > 0) {
|
||||
meshes[std::enum_value(meshType)] = &mesh;
|
||||
return true;
|
||||
}
|
||||
if (loadMesh(filename.c_str(), mesh)) {
|
||||
meshes[std::enum_value(meshType)] = &mesh;
|
||||
return true;
|
||||
}
|
||||
meshes[std::enum_value(meshType)] = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterCache::getItemModel(const char *itemName, Vertices& vertices, Indices& indices) {
|
||||
char fullPath[128];
|
||||
if (!core::string::formatBuf(fullPath, sizeof(fullPath), "models/items/%s.vox", itemName)) {
|
||||
Log::error("Failed to initialize the item path buffer. Can't load item %s.", itemName);
|
||||
return false;
|
||||
}
|
||||
|
||||
voxel::Mesh& mesh = cacheEntry(fullPath);
|
||||
if (mesh.getNoOfVertices() <= 0) {
|
||||
if (!loadMesh(fullPath, mesh)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
constexpr uint8_t boneId = std::enum_value(BoneId::Tool);
|
||||
vertices.reserve(mesh.getNoOfVertices());
|
||||
for (const voxel::VoxelVertex& v : mesh.getVertexVector()) {
|
||||
vertices.emplace_back(Vertex{v.position, v.colorIndex, boneId, v.ambientOcclusion});
|
||||
}
|
||||
//vertices.resize(mesh.getNoOfVertices());
|
||||
|
||||
indices.reserve(mesh.getNoOfIndices());
|
||||
for (voxel::IndexType idx : mesh.getIndexVector()) {
|
||||
indices.push_back((IndexType)idx);
|
||||
}
|
||||
//indices.resize(mesh.getNoOfIndices());
|
||||
|
||||
return true;
|
||||
return getModel(fullPath, BoneId::Tool, vertices, indices);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,24 +4,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "voxelformat/MeshCache.h"
|
||||
#include "animation/AnimationCache.h"
|
||||
#include "animation/Vertex.h"
|
||||
#include "CharacterSettings.h"
|
||||
#include "CharacterMeshType.h"
|
||||
#include "voxel/Mesh.h"
|
||||
#include <memory>
|
||||
|
||||
namespace animation {
|
||||
|
||||
/**
|
||||
* @brief Cache @c voxel::Mesh instances for @c Character
|
||||
*/
|
||||
class CharacterCache : public voxelformat::MeshCache {
|
||||
class CharacterCache : public AnimationCache<CharacterMeshType> {
|
||||
private:
|
||||
bool load(const std::string& filename, CharacterMeshType meshType, const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]);
|
||||
bool loadGlider(const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]);
|
||||
public:
|
||||
bool getCharacterMeshes(const CharacterSettings& settings, const voxel::Mesh* (&meshes)[std::enum_value(CharacterMeshType::Max)]);
|
||||
bool getCharacterModel(const CharacterSettings& settings, Vertices& vertices, Indices& indices);
|
||||
bool getItemModel(const char *itemName, Vertices& vertices, Indices& indices);
|
||||
};
|
||||
|
|
|
@ -8,10 +8,21 @@
|
|||
|
||||
namespace animation {
|
||||
|
||||
static const char *_strings[] = { "head", "chest", "belt", "pants", "hand", "foot", "shoulder", "glider" };
|
||||
static_assert(lengthof(_strings) == std::enum_value(CharacterMeshType::Max), "Invalid animation array dimensions");
|
||||
|
||||
const char *toString(CharacterMeshType type) {
|
||||
static const char *_strings[] = { "head", "chest", "belt", "pants", "hand", "foot", "shoulder", "glider" };
|
||||
static_assert(lengthof(_strings) == std::enum_value(CharacterMeshType::Max), "Invalid animation array dimensions");
|
||||
return _strings[std::enum_value(type)];
|
||||
}
|
||||
|
||||
CharacterMeshType toEnum(const char *type) {
|
||||
for (int i = 0; i < lengthof(_strings); ++i) {
|
||||
if (!strcmp(type, _strings[i])) {
|
||||
return (CharacterMeshType)i;
|
||||
}
|
||||
}
|
||||
return CharacterMeshType::Max;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ enum class CharacterMeshType : uint8_t {
|
|||
};
|
||||
|
||||
extern const char *toString(CharacterMeshType type);
|
||||
extern CharacterMeshType toEnum(const char *type);
|
||||
|
||||
}
|
||||
|
|
|
@ -11,17 +11,13 @@
|
|||
|
||||
namespace animation {
|
||||
|
||||
std::string luaFilename(const char *character) {
|
||||
return core::string::format("%s.lua", character);
|
||||
}
|
||||
|
||||
bool loadCharacterSettings(const std::string& luaString, CharacterSettings& settings) {
|
||||
if (luaString.empty()) {
|
||||
Log::warn("empty character settings can't get loaded");
|
||||
return false;
|
||||
}
|
||||
// also change the voxel editor lua script saving
|
||||
static const luaL_Reg funcs[] = {
|
||||
static const luaL_Reg chrFuncs[] = {
|
||||
{ "setRace", luaChr_SetRace },
|
||||
{ "setGender", luaChr_SetGender },
|
||||
{ "setChest", luaChr_SetChest },
|
||||
|
@ -59,10 +55,17 @@ bool loadCharacterSettings(const std::string& luaString, CharacterSettings& sett
|
|||
{ "setIdleTimeFactor", luaChr_SetIdleTimeFactor },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
static_assert(lengthof(funcs) - 9 == lengthof(ChrSkeletonAttributeMetaArray), "Array sizes should match");
|
||||
static_assert(lengthof(chrFuncs) - 9 == lengthof(ChrSkeletonAttributeMetaArray), "Array sizes should match");
|
||||
|
||||
static const luaL_Reg boneFuncs[] = {
|
||||
{ "setup", luaanim_bonesetup<CharacterSettings> },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
lua::LUA lua;
|
||||
lua.reg("chr", funcs);
|
||||
lua.reg("chr", chrFuncs);
|
||||
lua.reg("bone", boneFuncs);
|
||||
luaanim_boneidsregister(lua.state());
|
||||
|
||||
if (!lua.load(luaString)) {
|
||||
Log::error("%s", lua.error().c_str());
|
||||
|
@ -86,104 +89,8 @@ bool CharacterSettings::update() {
|
|||
}
|
||||
const char* racePath = race.c_str();
|
||||
const char* genderPath = gender.c_str();
|
||||
|
||||
if (!core::string::formatBuf(basePath, sizeof(basePath), "models/characters/%s/%s", racePath, genderPath)) {
|
||||
Log::error("Failed to initialize the character path buffer. Can't load models.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: integrate a static_assert here
|
||||
paths[std::enum_value(CharacterMeshType::Head)] = &head;
|
||||
paths[std::enum_value(CharacterMeshType::Chest)] = &chest;
|
||||
paths[std::enum_value(CharacterMeshType::Belt)] = &belt;
|
||||
paths[std::enum_value(CharacterMeshType::Pants)] = &pants;
|
||||
paths[std::enum_value(CharacterMeshType::Hand)] = &hand;
|
||||
paths[std::enum_value(CharacterMeshType::Foot)] = &foot;
|
||||
paths[std::enum_value(CharacterMeshType::Shoulder)] = &shoulder;
|
||||
paths[std::enum_value(CharacterMeshType::Glider)] = nullptr;
|
||||
|
||||
basePath = core::string::format("models/characters/%s/%s", racePath, genderPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
CharacterSettings::CharacterSettings() {
|
||||
for (size_t i = 0; i < paths.size(); ++i) {
|
||||
paths[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CharacterSettings::fullPath(CharacterMeshType type, const char* name) const {
|
||||
const std::string& p = path(type, name);
|
||||
return core::string::format("%s/%s.vox", basePath, p.c_str());
|
||||
}
|
||||
|
||||
std::string CharacterSettings::fullPath(CharacterMeshType type) const {
|
||||
return core::string::format("%s/%s.vox", basePath, path(type));
|
||||
}
|
||||
|
||||
const char* CharacterSettings::path(CharacterMeshType type) const {
|
||||
if (paths[std::enum_value(type)] == nullptr) {
|
||||
return "";
|
||||
}
|
||||
return paths[std::enum_value(type)]->c_str();
|
||||
}
|
||||
|
||||
std::string CharacterSettings::path(CharacterMeshType type, const char *name) const {
|
||||
return core::string::format("%s/%s", animation::toString(type), name);
|
||||
}
|
||||
|
||||
void CharacterSettings::copyFrom(const CharacterSettings& other) {
|
||||
skeletonAttr = other.skeletonAttr;
|
||||
race = other.race;
|
||||
gender = other.gender;
|
||||
chest = other.chest;
|
||||
belt = other.belt;
|
||||
pants = other.pants;
|
||||
hand = other.hand;
|
||||
foot = other.foot;
|
||||
head = other.head;
|
||||
shoulder = other.shoulder;
|
||||
for (size_t i = 0; i < paths.size(); ++i) {
|
||||
paths[i] = nullptr;
|
||||
}
|
||||
memcpy(basePath, other.basePath, sizeof(basePath));
|
||||
update();
|
||||
}
|
||||
|
||||
void CharacterSettings::setRace(const char *str) {
|
||||
race = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setGender(const char *str) {
|
||||
gender = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setChest(const char *str) {
|
||||
chest = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setBelt(const char *str) {
|
||||
belt = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setPants(const char *str) {
|
||||
pants = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setHand(const char *str) {
|
||||
hand = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setFoot(const char *str) {
|
||||
foot = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setHead(const char *str) {
|
||||
head = str;
|
||||
}
|
||||
|
||||
void CharacterSettings::setShoulder(const char *str) {
|
||||
shoulder = str;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "CharacterSkeletonAttribute.h"
|
||||
#include "CharacterMeshType.h"
|
||||
#include "core/NonCopyable.h"
|
||||
#include "animation/AnimationSettings.h"
|
||||
#include "core/String.h"
|
||||
#include "core/Common.h"
|
||||
#include <string>
|
||||
|
@ -19,51 +19,14 @@ namespace animation {
|
|||
* @brief Attributes for the character meshes
|
||||
* @sa SkeletonAttribute
|
||||
*/
|
||||
struct CharacterSettings : public core::NonCopyable {
|
||||
struct CharacterSettings : public AnimationSettings<CharacterMeshType> {
|
||||
CharacterSkeletonAttribute skeletonAttr;
|
||||
std::string race;
|
||||
std::string gender;
|
||||
std::string chest;
|
||||
std::string belt;
|
||||
std::string pants;
|
||||
std::string hand;
|
||||
std::string foot;
|
||||
std::string head;
|
||||
std::string shoulder;
|
||||
|
||||
std::array<const std::string*, std::enum_value(CharacterMeshType::Max)> paths;
|
||||
char basePath[64] {};
|
||||
|
||||
CharacterSettings();
|
||||
|
||||
std::string fullPath(CharacterMeshType type, const char* name) const;
|
||||
std::string fullPath(CharacterMeshType type) const;
|
||||
|
||||
/**
|
||||
* @brief Get the original path the settings were loaded with
|
||||
*/
|
||||
const char* path(CharacterMeshType type) const;
|
||||
/**
|
||||
* @brief Get the default path for the mesh type, but with a new name
|
||||
*/
|
||||
std::string path(CharacterMeshType type, const char *name) const;
|
||||
|
||||
void copyFrom(const CharacterSettings& other);
|
||||
|
||||
void setRace(const char *str);
|
||||
void setGender(const char *str);
|
||||
void setChest(const char *str);
|
||||
void setBelt(const char *str);
|
||||
void setPants(const char *str);
|
||||
void setHand(const char *str);
|
||||
void setFoot(const char *str);
|
||||
void setHead(const char *str);
|
||||
void setShoulder(const char *str);
|
||||
|
||||
bool update();
|
||||
};
|
||||
|
||||
extern std::string luaFilename(const char *character);
|
||||
extern bool loadCharacterSettings(const std::string& luaString, CharacterSettings& settings);
|
||||
|
||||
}
|
||||
|
|
|
@ -7,213 +7,214 @@
|
|||
#include "CharacterSettings.h"
|
||||
#include "commonlua/LUA.h"
|
||||
#include "core/String.h"
|
||||
#include "animation/LUAShared.h"
|
||||
|
||||
namespace animation {
|
||||
|
||||
static CharacterSettings* luaGetCharacterSettings(lua_State * l) {
|
||||
static CharacterSettings* luaGetAnimationSettings(lua_State * l) {
|
||||
return lua::LUA::globalData<CharacterSettings>(l, "Settings");
|
||||
}
|
||||
|
||||
static int luaChr_SetRace(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setRace(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->race = luaL_checkstring(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetGender(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setGender(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->gender = luaL_checkstring(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetChest(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setChest(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Chest, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetBelt(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setBelt(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Belt, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetPants(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setPants(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Pants, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHand(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setHand(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Hand, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetFoot(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setFoot(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Foot, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHead(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setHead(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Head, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetShoulder(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
settings->setShoulder(luaL_checkstring(l, 1));
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->setPath(CharacterMeshType::Shoulder, luaL_checkstring(l, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetScaler(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.scaler = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHeadScale(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.headScale = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetNeckHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.neckHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetNeckForward(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.neckForward = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetNeckRight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.neckRight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHandForward(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.handForward = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHandRight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.handRight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetShoulderForward(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.shoulderForward = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetShoulderRight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.shoulderRight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetToolForward(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.toolForward = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetToolRight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.toolRight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetToolScale(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.toolScale = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetShoulderScale(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.shoulderScale = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHeadHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.headHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetFootRight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.footRight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetChestHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.chestHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetBeltHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.beltHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetPantsHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.pantsHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetInvisibleLegHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.invisibleLegHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetFootHeight(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.footHeight = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetOrigin(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.origin = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetHipOffset(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.hipOffset = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetJumpTimeFactor(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.jumpTimeFactor = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetIdleTimeFactor(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.idleTimeFactor = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int luaChr_SetRunTimeFactor(lua_State * l) {
|
||||
CharacterSettings *settings = luaGetCharacterSettings(l);
|
||||
CharacterSettings *settings = luaGetAnimationSettings(l);
|
||||
settings->skeletonAttr.runTimeFactor = luaL_checknumber(l, 1);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
-- bone.setup("meshtype")
|
||||
-- bone.add("bonename", <mirrored>)
|
||||
|
||||
function setupBones()
|
||||
local head = bone.setup("head")
|
||||
head:add("head")
|
||||
|
||||
local torso = bone.setup("chest")
|
||||
torso:add("chest")
|
||||
|
||||
local foot = bone.setup("belt")
|
||||
foot:add("belt")
|
||||
|
||||
local pants = bone.setup("pants")
|
||||
pants:add("pants")
|
||||
|
||||
local hand = bone.setup("hand")
|
||||
hand:add("righthand")
|
||||
hand:add("lefthand", true)
|
||||
|
||||
local foot = bone.setup("foot")
|
||||
foot:add("rightfoot")
|
||||
foot:add("leftfoot", true)
|
||||
|
||||
local shoulder = bone.setup("shoulder")
|
||||
shoulder:add("rightshoulder")
|
||||
shoulder:add("leftshoulder", true)
|
||||
|
||||
local glider = bone.setup("glider")
|
||||
glider:add("glider")
|
||||
end
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("dwarf")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/blacksmith")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("human")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/blacksmith")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("human")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/knight")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("human")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/shepherd")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("human")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/worker")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("undead")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/skeleton")
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'chr.bones'
|
||||
|
||||
function init()
|
||||
setupBones()
|
||||
chr.setRace("undead")
|
||||
chr.setGender("male")
|
||||
chr.setHead("head/default")
|
||||
|
|
|
@ -47,12 +47,12 @@ TEST_F(CharacterSettingsTest, testLUA) {
|
|||
|
||||
EXPECT_EQ("testrace", settings.race);
|
||||
EXPECT_EQ("testgender", settings.gender);
|
||||
EXPECT_EQ("heads/test", settings.head);
|
||||
EXPECT_EQ("belts/test", settings.belt);
|
||||
EXPECT_EQ("chests/test", settings.chest);
|
||||
EXPECT_EQ("pants/test", settings.pants);
|
||||
EXPECT_EQ("hands/test", settings.hand);
|
||||
EXPECT_EQ("feet/test", settings.foot);
|
||||
EXPECT_EQ("heads/test", settings.path(CharacterMeshType::Head));
|
||||
EXPECT_EQ("belts/test", settings.path(CharacterMeshType::Belt));
|
||||
EXPECT_EQ("chests/test", settings.path(CharacterMeshType::Chest));
|
||||
EXPECT_EQ("pants/test", settings.path(CharacterMeshType::Pants));
|
||||
EXPECT_EQ("hands/test", settings.path(CharacterMeshType::Hand));
|
||||
EXPECT_EQ("feet/test", settings.path(CharacterMeshType::Foot));
|
||||
|
||||
EXPECT_FLOAT_EQ( 42.0f, settings.skeletonAttr.scaler);
|
||||
EXPECT_FLOAT_EQ(1337.0f, settings.skeletonAttr.headScale);
|
||||
|
|
|
@ -51,19 +51,6 @@ bool CheckboxVar(const char* label, const char* varName) {
|
|||
return CheckboxVar(label, var);
|
||||
}
|
||||
|
||||
bool Combo(const char* label, int* current_item, const std::vector<std::string>& items, int height_in_items) {
|
||||
return Combo(label, current_item,
|
||||
[](void* data, int idx, const char** out_text) {
|
||||
const std::vector<std::string>* vec = (const std::vector<std::string>*)data;
|
||||
if (idx < 0 || idx >= (int)vec->size()) {
|
||||
return false;
|
||||
}
|
||||
*out_text = (*vec)[idx].c_str();
|
||||
return true;
|
||||
},
|
||||
(void*) &items, (int)items.size(), height_in_items);
|
||||
}
|
||||
|
||||
void TooltipText(const char* text) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
|
@ -72,5 +59,4 @@ void TooltipText(const char* text) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "IMGUIInternal.h"
|
||||
#include "core/Var.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
|
@ -16,8 +17,22 @@ IMGUI_API bool InputVarFloat(const char* label, core::VarPtr& var, float step =
|
|||
IMGUI_API bool InputVarInt(const char* label, core::VarPtr& var, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0);
|
||||
IMGUI_API bool CheckboxVar(const char* label, core::VarPtr& var);
|
||||
IMGUI_API bool CheckboxVar(const char* label, const char* varName);
|
||||
IMGUI_API bool Combo(const char* label, int* current_item, const std::vector<std::string>& items, int height_in_items = -1);
|
||||
|
||||
template<class Collection>
|
||||
static bool ComboStl(const char* label, int* current_item, const Collection& items, int height_in_items = -1) {
|
||||
return Combo(label, current_item,
|
||||
[](void* data, int idx, const char** out_text) {
|
||||
const Collection* vec = (const Collection*)data;
|
||||
if (idx < 0 || idx >= (int)vec->size()) {
|
||||
return false;
|
||||
}
|
||||
*out_text = (*vec)[idx].c_str();
|
||||
return true;
|
||||
},
|
||||
(void*) &items, (int)items.size(), height_in_items);
|
||||
}
|
||||
IMGUI_API void TooltipText(const char* text);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
|
||||
static bool reloadCharacter = false;
|
||||
|
||||
static constexpr int32_t cnt = /*(int)network::EntityType::MAX_ANIMAL - ((int)network::EntityType::BEGIN_ANIMAL + 1) +*/
|
||||
(int)network::EntityType::MAX_CHARACTERS - ((int)network::EntityType::BEGIN_CHARACTERS + 1);
|
||||
static std::array<const char*, cnt> validCharacters;
|
||||
static constexpr int32_t cnt = (int)network::EntityType::MAX_CHARACTERS - ((int)network::EntityType::BEGIN_CHARACTERS + 1);
|
||||
static std::array<std::string, cnt> validCharacters {};
|
||||
|
||||
TestAnimation::TestAnimation(const metric::MetricPtr& metric, const stock::StockDataProviderPtr& stockDataProvider,
|
||||
const io::FilesystemPtr& filesystem,
|
||||
|
@ -25,22 +24,19 @@ TestAnimation::TestAnimation(const metric::MetricPtr& metric, const stock::Stock
|
|||
characterCache), _stockDataProvider(stockDataProvider) {
|
||||
init(ORGANISATION, "testanimation");
|
||||
setCameraMotion(true);
|
||||
//setRenderPlane(true);
|
||||
setRenderAxis(true);
|
||||
|
||||
int index = 0;
|
||||
//for (int i = ((int)network::EntityType::BEGIN_ANIMAL) + 1; i < (int)network::EntityType::MAX_ANIMAL; ++i) {
|
||||
// validCharacters[index++] = network::EnumNameEntityType((network::EntityType)i);
|
||||
//}
|
||||
for (int i = ((int)network::EntityType::BEGIN_CHARACTERS) + 1; i < (int)network::EntityType::MAX_CHARACTERS; ++i) {
|
||||
validCharacters[index++] = network::EnumNameEntityType((network::EntityType)i);
|
||||
const char *entityName = network::EnumNameEntityType((network::EntityType)i);
|
||||
std::string lower = core::string::toLower(core::string::format("chr/%s", entityName));
|
||||
core::string::replaceAllChars(lower, '_', '-');
|
||||
validCharacters[index++] = lower;
|
||||
}
|
||||
}
|
||||
|
||||
std::string TestAnimation::currentCharacter() const {
|
||||
std::string name = validCharacters[_currentCharacterIndex];
|
||||
core::string::replaceAllChars(name, '_', '-');
|
||||
return core::string::toLower(name);
|
||||
return validCharacters[_currentCharacterIndex];
|
||||
}
|
||||
|
||||
core::AppState TestAnimation::onConstruct() {
|
||||
|
@ -209,13 +205,13 @@ void TestAnimation::doRender() {
|
|||
}
|
||||
|
||||
void TestAnimation::onRenderUI() {
|
||||
if (ImGui::Combo("Animation", &_animationIdx, _animations)) {
|
||||
if (ImGui::ComboStl("Animation", &_animationIdx, _animations)) {
|
||||
_character.setAnimation((animation::Animation)_animationIdx);
|
||||
}
|
||||
if (ImGui::Combo("Item/Tool", &_itemIdx, _items)) {
|
||||
if (ImGui::ComboStl("Item/Tool", &_itemIdx, _items)) {
|
||||
addItem(_itemIdx);
|
||||
}
|
||||
if (ImGui::Combo("Character", &_currentCharacterIndex, validCharacters.front(), validCharacters.size())) {
|
||||
if (ImGui::ComboStl("Character", &_currentCharacterIndex, validCharacters)) {
|
||||
loadCharacter();
|
||||
}
|
||||
Super::onRenderUI();
|
||||
|
|
|
@ -715,8 +715,8 @@ void SceneManager::renderAnimation(const video::Camera& camera) {
|
|||
continue;
|
||||
}
|
||||
const int characterMeshTypeId = core::string::toInt(value);
|
||||
const std::string* path = _characterSettings.paths[characterMeshTypeId];
|
||||
if (path == nullptr) {
|
||||
const std::string& path = _characterSettings.paths[characterMeshTypeId];
|
||||
if (path.empty()) {
|
||||
Log::debug("No path found for layer %i", (int)i);
|
||||
continue;
|
||||
}
|
||||
|
@ -1480,7 +1480,7 @@ bool SceneManager::loadCharacter(const std::string& luaFile) {
|
|||
Log::warn("Failed to load character settings from %s", luaFile.c_str());
|
||||
return false;
|
||||
}
|
||||
_characterSettings.copyFrom(settings);
|
||||
_characterSettings = settings;
|
||||
|
||||
voxel::VoxelVolumes volumes;
|
||||
if (!_volumeCache.getCharacterVolumes(_characterSettings, volumes)) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
namespace voxedit {
|
||||
|
||||
// TODO: use AnimationSettings
|
||||
extern bool saveCharacterLua(const animation::CharacterSettings& characterSettings, const char *name, const io::FilePtr& file);
|
||||
|
||||
}
|
||||
|
|
|
@ -14,29 +14,7 @@
|
|||
namespace voxedit {
|
||||
namespace anim {
|
||||
|
||||
bool VolumeCache::getCharacterVolumes(const animation::CharacterSettings& settings, voxel::VoxelVolumes& volumes) {
|
||||
volumes.resize(std::enum_value(animation::CharacterMeshType::Max));
|
||||
|
||||
for (size_t i = 0; i < settings.paths.size(); ++i) {
|
||||
if (settings.paths[i] == nullptr || settings.paths[i]->empty()) {
|
||||
continue;
|
||||
}
|
||||
const std::string& fullPath = settings.fullPath((animation::CharacterMeshType)i);
|
||||
if (!load(fullPath, (animation::CharacterMeshType)i, volumes)) {
|
||||
Log::error("Failed to load %s", settings.paths[i]->c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < std::enum_value(animation::CharacterMeshType::Max); ++i) {
|
||||
if (volumes[i].volume == nullptr) {
|
||||
continue;
|
||||
}
|
||||
volumes[i].name = toString((animation::CharacterMeshType)i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VolumeCache::load(const std::string& fullPath, animation::CharacterMeshType meshType, voxel::VoxelVolumes& volumes) {
|
||||
bool VolumeCache::load(const std::string& fullPath, size_t volumeIndex, voxel::VoxelVolumes& volumes) {
|
||||
Log::info("Loading volume from %s", fullPath.c_str());
|
||||
const io::FilesystemPtr& fs = io::filesystem();
|
||||
const io::FilePtr& file = fs->open(fullPath);
|
||||
|
@ -50,7 +28,7 @@ bool VolumeCache::load(const std::string& fullPath, animation::CharacterMeshType
|
|||
Log::error("More than one volume/layer found in %s", file->name().c_str());
|
||||
return false;
|
||||
}
|
||||
volumes[std::enum_value(meshType)] = localVolumes[0];
|
||||
volumes[volumeIndex] = localVolumes[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,13 +14,34 @@ namespace voxedit {
|
|||
namespace anim {
|
||||
|
||||
/**
|
||||
* @brief Cache volume instances for @c Character
|
||||
* @brief Cache volume instances for @c AnimationEntity
|
||||
*/
|
||||
class VolumeCache : public voxelformat::VolumeCache {
|
||||
private:
|
||||
bool load(const std::string& fullPath, animation::CharacterMeshType meshType, voxel::VoxelVolumes& volumes);
|
||||
bool load(const std::string& fullPath, size_t volumeIndex, voxel::VoxelVolumes& volumes);
|
||||
public:
|
||||
bool getCharacterVolumes(const animation::CharacterSettings& settings, voxel::VoxelVolumes& volumes);
|
||||
template<class T>
|
||||
bool getCharacterVolumes(const animation::AnimationSettings<T>& settings, voxel::VoxelVolumes& volumes) {
|
||||
volumes.resize(std::enum_value(T::Max));
|
||||
|
||||
for (size_t i = 0; i < settings.paths.size(); ++i) {
|
||||
if (settings.paths[i].empty()) {
|
||||
continue;
|
||||
}
|
||||
const std::string& fullPath = settings.fullPath((T)i);
|
||||
if (!load(fullPath, i, volumes)) {
|
||||
Log::error("Failed to load %s", settings.paths[i].c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < std::enum_value(T::Max); ++i) {
|
||||
if (volumes[i].volume == nullptr) {
|
||||
continue;
|
||||
}
|
||||
volumes[i].name = toString((T)i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using VolumeCachePtr = std::shared_ptr<VolumeCache>;
|
||||
|
|
Loading…
Reference in New Issue