merge in changes from web/js branch by hand (bone animation updates)
This commit is contained in:
@@ -83,7 +83,9 @@ namespace polyvox
|
||||
const char *const boneName,
|
||||
const char **const meshName,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs);
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace);
|
||||
void resetBones(EntityId entityId);
|
||||
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f);
|
||||
void stopAnimation(EntityId e, int index);
|
||||
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
|
||||
@@ -95,6 +97,8 @@ namespace polyvox
|
||||
utils::Entity findChildEntityByName(
|
||||
EntityId entityId,
|
||||
const char *entityName);
|
||||
int getEntityCount(EntityId entity, bool renderableOnly);
|
||||
const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly);
|
||||
|
||||
private:
|
||||
AssetLoader *_assetLoader = nullptr;
|
||||
@@ -117,11 +121,5 @@ namespace polyvox
|
||||
|
||||
inline void updateTransform(SceneAsset &asset);
|
||||
|
||||
void updateBoneTransformFromAnimationBuffer(
|
||||
const BoneAnimation& animation,
|
||||
int frameNumber,
|
||||
FilamentAsset *asset
|
||||
);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ namespace polyvox
|
||||
|
||||
void loadIbl(const char *const iblUri, float intensity);
|
||||
void removeIbl();
|
||||
void rotateIbl(const math::mat3f & matrix);
|
||||
|
||||
|
||||
void removeAsset(EntityId asset);
|
||||
void clearAssets();
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
#endif /* __STDBOOL_H */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__EMSCRIPTEN__)
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
@@ -67,6 +67,7 @@ extern "C"
|
||||
FLUTTER_PLUGIN_EXPORT void set_bloom(const void *const viewer, float strength);
|
||||
FLUTTER_PLUGIN_EXPORT void load_skybox(const void *const viewer, const char *skyboxPath);
|
||||
FLUTTER_PLUGIN_EXPORT void load_ibl(const void *const viewer, const char *iblPath, float intensity);
|
||||
FLUTTER_PLUGIN_EXPORT void rotate_ibl(const void *const viewer, float* rotationMatrix);
|
||||
FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer);
|
||||
FLUTTER_PLUGIN_EXPORT void remove_ibl(const void *const viewer);
|
||||
FLUTTER_PLUGIN_EXPORT EntityId add_light(const void *const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows);
|
||||
@@ -113,6 +114,10 @@ extern "C"
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose(
|
||||
void *assetManager,
|
||||
EntityId asset);
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
@@ -121,7 +126,8 @@ extern "C"
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs);
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace);
|
||||
FLUTTER_PLUGIN_EXPORT bool set_bone_transform(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
@@ -171,6 +177,8 @@ extern "C"
|
||||
FLUTTER_PLUGIN_EXPORT void pick(void *const viewer, int x, int y, EntityId *entityId);
|
||||
FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const assetManager, const EntityId entityId);
|
||||
FLUTTER_PLUGIN_EXPORT const EntityId find_child_entity_by_name(void *const assetManager, const EntityId parent, const char* name);
|
||||
FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const assetManager, const EntityId target, bool renderableOnly);
|
||||
FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const assetManager, const EntityId target, int index, bool renderableOnly);
|
||||
FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording);
|
||||
FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory);
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy();
|
||||
|
||||
@@ -64,14 +64,34 @@ FLUTTER_PLUGIN_EXPORT void set_morph_target_weights_ffi(void* const assetManager
|
||||
const float *const morphData,
|
||||
int numWeights
|
||||
);
|
||||
FLUTTER_PLUGIN_EXPORT bool set_morph_animation_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
const char *entityName,
|
||||
const float *const transform,
|
||||
const char *boneName);
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace);
|
||||
FLUTTER_PLUGIN_EXPORT void set_post_processing_ffi(void* const viewer, bool enabled);
|
||||
FLUTTER_PLUGIN_EXPORT void pick_ffi(void* const viewer, int x, int y, EntityId* entityId);
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId);
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -62,17 +62,17 @@ namespace polyvox {
|
||||
// Use this to construct a dynamic (i.e. non-glTF embedded) bone/joint animation.
|
||||
//
|
||||
struct BoneAnimation : AnimationStatus {
|
||||
uint8_t boneIndex;
|
||||
size_t boneIndex;
|
||||
vector<utils::Entity> meshTargets;
|
||||
size_t skinIndex = 0;
|
||||
int lengthInFrames;
|
||||
float frameLengthInMs = 0;
|
||||
vector<math::quatf> frameData;
|
||||
vector<math::mat4f> frameData;
|
||||
};
|
||||
|
||||
struct SceneAsset {
|
||||
FilamentAsset* asset = nullptr;
|
||||
|
||||
vector<math::mat4f> initialJointTransforms;
|
||||
vector<GltfAnimation> gltfAnimations;
|
||||
vector<MorphAnimation> morphAnimations;
|
||||
vector<BoneAnimation> boneAnimations;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace polyvox
|
||||
EntityManager &em = EntityManager::get();
|
||||
|
||||
_assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em});
|
||||
_gltfResourceLoader->addTextureProvider("image/ktx2", _ktxDecoder);
|
||||
_gltfResourceLoader->addTextureProvider ("image/ktx2", _ktxDecoder);
|
||||
_gltfResourceLoader->addTextureProvider("image/png", _stbDecoder);
|
||||
_gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder);
|
||||
}
|
||||
@@ -121,17 +121,31 @@ namespace polyvox
|
||||
_gltfResourceLoader->addResourceData(resourceUris[i], std::move(b));
|
||||
}
|
||||
|
||||
// load resources synchronously
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glTF asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
for (auto &rb : resourceBuffers)
|
||||
{
|
||||
_resourceLoaderWrapper->free(rb);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (!_gltfResourceLoader->asyncBeginLoad(asset)) {
|
||||
Log("Unknown error loading glTF asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
for(auto& rb : resourceBuffers) {
|
||||
_resourceLoaderWrapper->free(rb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
while(_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) {
|
||||
_gltfResourceLoader->asyncUpdateLoad();
|
||||
}
|
||||
#else
|
||||
// load resources synchronously
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glTF asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
for (auto &rb : resourceBuffers)
|
||||
{
|
||||
_resourceLoaderWrapper->free(rb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
_scene->addEntities(asset->getEntities(), asset->getEntityCount());
|
||||
|
||||
@@ -142,7 +156,18 @@ namespace polyvox
|
||||
asset->releaseSourceData();
|
||||
|
||||
SceneAsset sceneAsset(asset);
|
||||
|
||||
const auto joints = inst->getJointsAt(0);
|
||||
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
for(int i = 0; i < inst->getJointCountAt(0); i++) {
|
||||
const auto joint = joints[i];
|
||||
const auto& jointTransformInstance = transformManager.getInstance(joint);
|
||||
const auto& jointTransform = transformManager.getTransform(jointTransformInstance);
|
||||
sceneAsset.initialJointTransforms.push_back(jointTransform);
|
||||
}
|
||||
|
||||
utils::Entity e = EntityManager::get().create();
|
||||
|
||||
EntityId eid = Entity::smuggle(e);
|
||||
@@ -166,7 +191,7 @@ namespace polyvox
|
||||
|
||||
ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri);
|
||||
|
||||
Log("Loaded GLB of size %d at URI %s", rbuf.size, uri);
|
||||
Log("Loaded GLB data (%d bytes) from URI %s", rbuf.size, uri);
|
||||
|
||||
FilamentAsset *asset = _assetLoader->createAsset(
|
||||
(const uint8_t *)rbuf.data, rbuf.size);
|
||||
@@ -181,12 +206,23 @@ namespace polyvox
|
||||
|
||||
_scene->addEntities(asset->getEntities(), entityCount);
|
||||
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
return 0;
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (!_gltfResourceLoader->asyncBeginLoad(asset)) {
|
||||
Log("Unknown error loading glb asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
return 0;
|
||||
}
|
||||
while(_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) {
|
||||
_gltfResourceLoader->asyncUpdateLoad();
|
||||
}
|
||||
#else
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto lights = asset->getLightEntities();
|
||||
_scene->addEntities(lights, asset->getLightEntityCount());
|
||||
@@ -202,6 +238,17 @@ namespace polyvox
|
||||
_resourceLoaderWrapper->free(rbuf);
|
||||
|
||||
SceneAsset sceneAsset(asset);
|
||||
|
||||
const auto joints = inst->getJointsAt(0);
|
||||
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
for(int i = 0; i < inst->getJointCountAt(0); i++) {
|
||||
const auto joint = joints[i];
|
||||
const auto& jointTransformInstance = transformManager.getInstance(joint);
|
||||
const auto& jointTransform = transformManager.getTransform(jointTransformInstance);
|
||||
sceneAsset.initialJointTransforms.push_back(jointTransform);
|
||||
}
|
||||
|
||||
utils::Entity e = EntityManager::get().create();
|
||||
EntityId eid = Entity::smuggle(e);
|
||||
@@ -278,7 +325,6 @@ namespace polyvox
|
||||
|
||||
void AssetManager::updateAnimations()
|
||||
{
|
||||
|
||||
std::lock_guard lock(_animationMutex);
|
||||
RenderableManager &rm = _engine->getRenderableManager();
|
||||
|
||||
@@ -287,7 +333,7 @@ namespace polyvox
|
||||
for (auto &asset : _assets)
|
||||
{
|
||||
|
||||
for (int i = asset.gltfAnimations.size() - 1; i >= 0; i--) {
|
||||
for (int i = ((int)asset.gltfAnimations.size()) - 1; i >= 0; i--) {
|
||||
|
||||
auto animationStatus = asset.gltfAnimations[i];
|
||||
|
||||
@@ -295,12 +341,15 @@ namespace polyvox
|
||||
|
||||
if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
|
||||
{
|
||||
asset.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, animationStatus.durationInSecs - 0.001);
|
||||
asset.asset->getInstance()->getAnimator()->updateBoneMatrices();
|
||||
asset.gltfAnimations.erase(asset.gltfAnimations.begin() + i);
|
||||
asset.fadeGltfAnimationIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
asset.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, elapsedInSecs);
|
||||
|
||||
if (asset.fadeGltfAnimationIndex != -1 && elapsedInSecs < asset.fadeDuration)
|
||||
{
|
||||
// cross-fade
|
||||
@@ -353,21 +402,47 @@ namespace polyvox
|
||||
asset.boneAnimations.erase(asset.boneAnimations.begin() + i);
|
||||
continue;
|
||||
}
|
||||
|
||||
float frameLengthInMs = animationStatus.frameLengthInMs;
|
||||
|
||||
int frameNumber = static_cast<int>(elapsedInSecs * 1000.0f / frameLengthInMs) % animationStatus.lengthInFrames;
|
||||
float elapsedFrames = elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs;
|
||||
|
||||
int currFrame = static_cast<int>(elapsedFrames) % animationStatus.lengthInFrames;
|
||||
float delta = elapsedFrames - currFrame;
|
||||
int nextFrame = currFrame;
|
||||
auto restLocalTransform = asset.initialJointTransforms[animationStatus.boneIndex];
|
||||
|
||||
// offset from the end if reverse
|
||||
if (animationStatus.reverse)
|
||||
{
|
||||
frameNumber = animationStatus.lengthInFrames - frameNumber;
|
||||
currFrame = animationStatus.lengthInFrames - currFrame;
|
||||
if(currFrame > 0) {
|
||||
nextFrame = currFrame - 1;
|
||||
} else {
|
||||
nextFrame = 0;
|
||||
}
|
||||
} else {
|
||||
if(currFrame < animationStatus.lengthInFrames - 1) {
|
||||
nextFrame = currFrame + 1;
|
||||
} else {
|
||||
nextFrame = currFrame;
|
||||
}
|
||||
}
|
||||
updateBoneTransformFromAnimationBuffer(
|
||||
animationStatus,
|
||||
frameNumber,
|
||||
asset.asset);
|
||||
|
||||
|
||||
// simple linear interpolation
|
||||
math::mat4f curr = (1 - delta) * (restLocalTransform * animationStatus.frameData[currFrame]);
|
||||
math::mat4f next = delta * (restLocalTransform * animationStatus.frameData[nextFrame]);
|
||||
math::mat4f localTransform = curr + next;
|
||||
|
||||
auto filamentInstance = asset.asset->getInstance();
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
const Entity joint = filamentInstance->getJointsAt(animationStatus.skinIndex)[animationStatus.boneIndex];
|
||||
|
||||
auto jointTransform = transformManager.getInstance(joint);
|
||||
|
||||
transformManager.setTransform(jointTransform, localTransform);
|
||||
|
||||
asset.asset->getInstance()->getAnimator()->updateBoneMatrices();
|
||||
|
||||
if (animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
|
||||
{
|
||||
animationStatus.start = now;
|
||||
@@ -381,7 +456,6 @@ namespace polyvox
|
||||
// - or is it better to add an option for "streaming" mode where we can just return a reference to a mat4 and then update the values directly?
|
||||
bool AssetManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, const char* boneName, math::mat4f localTransform)
|
||||
{
|
||||
|
||||
std::lock_guard lock(_animationMutex);
|
||||
|
||||
const auto &pos = _entityIdLookup.find(entityId);
|
||||
@@ -436,7 +510,6 @@ namespace polyvox
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex];
|
||||
|
||||
if (joint.isNull())
|
||||
@@ -447,8 +520,8 @@ namespace polyvox
|
||||
|
||||
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[boneIndex];
|
||||
|
||||
auto jointTransformInstance = transformManager.getInstance(joint);
|
||||
auto globalJointTransform = transformManager.getWorldTransform(jointTransformInstance);
|
||||
auto jointTransform = transformManager.getInstance(joint);
|
||||
auto globalJointTransform = transformManager.getWorldTransform(jointTransform);
|
||||
|
||||
auto inverseGlobalTransform = inverse(
|
||||
transformManager.getWorldTransform(
|
||||
@@ -467,47 +540,6 @@ namespace polyvox
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetManager::updateBoneTransformFromAnimationBuffer(
|
||||
const BoneAnimation& animation,
|
||||
int frameNumber,
|
||||
FilamentAsset *asset)
|
||||
{
|
||||
auto filamentInstance = asset->getInstance();
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
RenderableManager &rm = _engine->getRenderableManager();
|
||||
|
||||
auto boneIndex = animation.boneIndex;
|
||||
|
||||
math::mat4f localTransform(animation.frameData[frameNumber]);
|
||||
|
||||
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(animation.skinIndex)[boneIndex];
|
||||
|
||||
for(const auto& meshTarget : animation.meshTargets) {
|
||||
|
||||
const Entity joint = filamentInstance->getJointsAt(animation.skinIndex)[animation.boneIndex];
|
||||
|
||||
auto jointInstance = transformManager.getInstance(joint);
|
||||
auto globalJointTransform = transformManager.getWorldTransform(jointInstance);
|
||||
|
||||
|
||||
auto inverseGlobalTransform = inverse(
|
||||
transformManager.getWorldTransform(
|
||||
transformManager.getInstance(meshTarget)
|
||||
)
|
||||
);
|
||||
const auto boneTransform = inverseGlobalTransform * globalJointTransform * localTransform * inverseBindMatrix;
|
||||
const auto &renderableInstance = rm.getInstance(meshTarget);
|
||||
rm.setBones(
|
||||
renderableInstance,
|
||||
&boneTransform,
|
||||
1,
|
||||
boneIndex
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AssetManager::remove(EntityId entityId)
|
||||
{
|
||||
std::lock_guard lock(_animationMutex);
|
||||
@@ -716,13 +748,45 @@ namespace polyvox
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetManager::resetBones(EntityId entityId) {
|
||||
std::lock_guard lock(_animationMutex);
|
||||
|
||||
const auto &pos = _entityIdLookup.find(entityId);
|
||||
if (pos == _entityIdLookup.end())
|
||||
{
|
||||
Log("ERROR: asset not found for entity.");
|
||||
return;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
|
||||
auto filamentInstance = asset.asset->getInstance();
|
||||
filamentInstance->getAnimator()->resetBoneMatrices();
|
||||
|
||||
auto skinCount = filamentInstance->getSkinCount();
|
||||
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
for(int skinIndex = 0; skinIndex < skinCount; skinIndex++) {
|
||||
for(int i =0; i < filamentInstance->getJointCountAt(skinIndex);i++) {
|
||||
const Entity joint = filamentInstance->getJointsAt(skinIndex)[i];
|
||||
auto restLocalTransform = asset.initialJointTransforms[i];
|
||||
auto jointTransform = transformManager.getInstance(joint);
|
||||
transformManager.setTransform(jointTransform, restLocalTransform);
|
||||
}
|
||||
}
|
||||
filamentInstance->getAnimator()->updateBoneMatrices();
|
||||
filamentInstance->getAnimator()->resetBoneMatrices();
|
||||
|
||||
}
|
||||
|
||||
bool AssetManager::addBoneAnimation(EntityId entityId,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs)
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace)
|
||||
{
|
||||
std::lock_guard lock(_animationMutex);
|
||||
|
||||
@@ -734,8 +798,6 @@ namespace polyvox
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
|
||||
asset.asset->getInstance()->getAnimator()->resetBoneMatrices();
|
||||
|
||||
auto filamentInstance = asset.asset->getInstance();
|
||||
|
||||
size_t skinCount = filamentInstance->getSkinCount();
|
||||
@@ -768,15 +830,51 @@ namespace polyvox
|
||||
}
|
||||
|
||||
animation.frameData.clear();
|
||||
const auto& tm = _engine->getTransformManager();
|
||||
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[animation.boneIndex];
|
||||
const auto& bindMatrix = inverse(inverseBindMatrix);
|
||||
math::float3 trans;
|
||||
math::quatf rot;
|
||||
math::float3 scale;
|
||||
decomposeMatrix(inverseBindMatrix, &trans, &rot, &scale);
|
||||
math::float3 btrans;
|
||||
math::quatf brot;
|
||||
math::float3 bscale;
|
||||
decomposeMatrix(bindMatrix, &btrans, &brot, &bscale);
|
||||
// Log("Bind matrix for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName, bindMatrix[0][0],bindMatrix[1][0],bindMatrix[2][0],bindMatrix[3][0],
|
||||
// bindMatrix[0][1],bindMatrix[1][1],bindMatrix[2][1],bindMatrix[3][1],
|
||||
// bindMatrix[0][2],bindMatrix[1][2],bindMatrix[2][2],bindMatrix[3][2],
|
||||
// bindMatrix[0][3],bindMatrix[1][3],bindMatrix[2][3],bindMatrix[3][3]);
|
||||
for(int i = 0; i < numFrames; i++) {
|
||||
animation.frameData.push_back(math::quatf(
|
||||
frameData[i*4],
|
||||
frameData[(i*4)+1],
|
||||
frameData[(i*4)+2],
|
||||
frameData[(i*4)+3]
|
||||
));
|
||||
|
||||
}
|
||||
math::mat4f frame(
|
||||
frameData[i*16],
|
||||
frameData[(i*16)+1],
|
||||
frameData[(i*16)+2],
|
||||
frameData[(i*16)+3],
|
||||
frameData[(i*16)+4],
|
||||
frameData[(i*16)+5],
|
||||
frameData[(i*16)+6],
|
||||
frameData[(i*16)+7],
|
||||
frameData[(i*16)+8],
|
||||
frameData[(i*16)+9],
|
||||
frameData[(i*16)+10],
|
||||
frameData[(i*16)+11],
|
||||
frameData[(i*16)+12],
|
||||
frameData[(i*16)+13],
|
||||
frameData[(i*16)+14],
|
||||
frameData[(i*16)+15]);
|
||||
// if(i == numFrames - 1) { Log("Model transform for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName,
|
||||
// frame[0][0],frame[1][0],frame[2][0],frame[3][0],
|
||||
// frame[0][1],frame[1][1],frame[2][1],frame[3][1],
|
||||
// frame[0][2],frame[1][2],frame[2][2],frame[3][2],
|
||||
// frame[0][3],frame[1][3],frame[2][3],frame[3][3]);
|
||||
// }
|
||||
|
||||
if(isModelSpace) {
|
||||
frame = (math::mat4f(rot) * frame) * math::mat4f(brot);
|
||||
}
|
||||
animation.frameData.push_back(frame);
|
||||
}
|
||||
|
||||
animation.frameLengthInMs = frameLengthInMs;
|
||||
|
||||
@@ -789,7 +887,6 @@ namespace polyvox
|
||||
Log("Mesh target %s for bone animation could not be found", meshNames[i]);
|
||||
return false;
|
||||
}
|
||||
Log("Added mesh target %s", meshNames[i]);
|
||||
animation.meshTargets.push_back(entity);
|
||||
}
|
||||
|
||||
@@ -798,6 +895,7 @@ namespace polyvox
|
||||
animation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
|
||||
animation.lengthInFrames = numFrames;
|
||||
animation.frameLengthInMs = frameLengthInMs;
|
||||
animation.skinIndex = 0;
|
||||
asset.boneAnimations.push_back(animation);
|
||||
|
||||
return true;
|
||||
@@ -1172,4 +1270,63 @@ namespace polyvox
|
||||
return _ncm->getName(nameInstance);
|
||||
}
|
||||
|
||||
int AssetManager::getEntityCount(EntityId entityId, bool renderableOnly) {
|
||||
const auto &pos = _entityIdLookup.find(entityId);
|
||||
if (pos == _entityIdLookup.end())
|
||||
{
|
||||
Log("ERROR: asset not found for entity.");
|
||||
return 0;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
if(renderableOnly) {
|
||||
int count = 0;
|
||||
const auto& rm = _engine->getRenderableManager();
|
||||
const Entity *entities = asset.asset->getEntities();
|
||||
for(int i=0; i < asset.asset->getEntityCount(); i++) {
|
||||
if(rm.hasComponent(entities[i])) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return asset.asset->getEntityCount();
|
||||
}
|
||||
|
||||
const char* AssetManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) {
|
||||
const auto &pos = _entityIdLookup.find(entityId);
|
||||
if (pos == _entityIdLookup.end())
|
||||
{
|
||||
Log("ERROR: asset not found for entity.");
|
||||
return nullptr;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
int found = -1;
|
||||
|
||||
if(renderableOnly) {
|
||||
int count = 0;
|
||||
const auto& rm = _engine->getRenderableManager();
|
||||
const Entity *entities = asset.asset->getEntities();
|
||||
for(int i=0; i < asset.asset->getEntityCount(); i++) {
|
||||
if(rm.hasComponent(entities[i])) {
|
||||
if(count == index) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found = index;
|
||||
}
|
||||
|
||||
if(found >= asset.asset->getEntityCount()) {
|
||||
Log("ERROR: index %d greater than number of child entities.", found);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const utils::Entity entity = asset.asset->getEntities()[found];
|
||||
auto inst = _ncm->getInstance(entity);
|
||||
return _ncm->getName(inst);
|
||||
}
|
||||
|
||||
} // namespace polyvox
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/OpenGLPlatform.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <backend/platforms/PlatformWebGL.h>
|
||||
#endif
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
@@ -131,6 +134,8 @@ namespace polyvox
|
||||
#elif TARGET_OS_OSX
|
||||
ASSERT_POSTCONDITION(platform == nullptr, "Custom Platform not supported on macOS");
|
||||
_engine = Engine::create(Engine::Backend::METAL);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
_engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)new filament::backend::PlatformWebGL(), (void *)sharedContext, nullptr);
|
||||
#else
|
||||
_engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)platform, (void *)sharedContext, nullptr);
|
||||
#endif
|
||||
@@ -154,11 +159,27 @@ namespace polyvox
|
||||
Log("View created");
|
||||
|
||||
setToneMapping(ToneMapping::ACES);
|
||||
|
||||
Log("Set tone mapping");
|
||||
|
||||
setBloom(0.6f);
|
||||
Log("Set bloom");
|
||||
#ifdef __EMSCRIPTEN__
|
||||
Log("Bloom is disabled on WebGL builds as it causes instability with certain drivers");
|
||||
decltype(_view->getBloomOptions()) opts;
|
||||
opts.enabled = false;
|
||||
_view->setBloomOptions(opts);
|
||||
|
||||
_view->setAmbientOcclusionOptions({.enabled=false});
|
||||
|
||||
_view->setDynamicResolutionOptions({.enabled=false});
|
||||
|
||||
_view->setDithering(filament::Dithering::NONE);
|
||||
_view->setAntiAliasing(filament::AntiAliasing::NONE);
|
||||
_view->setShadowingEnabled(false);
|
||||
_view->setScreenSpaceRefractionEnabled(false);
|
||||
|
||||
#else
|
||||
setBloom(0.6f);
|
||||
Log("Set bloom");
|
||||
#endif
|
||||
|
||||
_view->setScene(_scene);
|
||||
_view->setCamera(_mainCamera);
|
||||
@@ -215,7 +236,7 @@ namespace polyvox
|
||||
.package(IMAGE_IMAGE_DATA, IMAGE_IMAGE_SIZE)
|
||||
.build(*_engine);
|
||||
_imageMaterial->setDefaultParameter("showImage", 0);
|
||||
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(1.0f, 1.0f, 1.0f, 0.0f));
|
||||
_imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler);
|
||||
}
|
||||
catch (...)
|
||||
@@ -265,10 +286,14 @@ namespace polyvox
|
||||
|
||||
void FilamentViewer::setBloom(float strength)
|
||||
{
|
||||
decltype(_view->getBloomOptions()) opts;
|
||||
opts.enabled = true;
|
||||
opts.strength = strength;
|
||||
_view->setBloomOptions(opts);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
Log("Bloom is disabled on WebGL builds as it causes instability with certain drivers. setBloom will be ignored");
|
||||
#else
|
||||
decltype(_view->getBloomOptions()) opts;
|
||||
opts.enabled = true;
|
||||
opts.strength = strength;
|
||||
_view->setBloomOptions(opts);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FilamentViewer::setToneMapping(ToneMapping toneMapping)
|
||||
@@ -481,6 +506,7 @@ namespace polyvox
|
||||
|
||||
void FilamentViewer::setBackgroundColor(const float r, const float g, const float b, const float a)
|
||||
{
|
||||
Log("Setting background color to rgba(%f,%f,%f,%f)", r, g, b, a);
|
||||
_imageMaterial->setDefaultParameter("showImage", 0);
|
||||
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(r, g, b, a));
|
||||
_imageMaterial->setDefaultParameter("transform", _imageScale);
|
||||
@@ -926,6 +952,11 @@ namespace polyvox
|
||||
_scene->setIndirectLight(nullptr);
|
||||
}
|
||||
|
||||
void FilamentViewer::rotateIbl(const math::mat3f & matrix) {
|
||||
_indirectLight->setRotation(matrix);
|
||||
}
|
||||
|
||||
|
||||
void FilamentViewer::loadIbl(const char *const iblPath, float intensity)
|
||||
{
|
||||
removeIbl();
|
||||
@@ -994,9 +1025,10 @@ namespace polyvox
|
||||
if (_frameCount == 60)
|
||||
{
|
||||
// Log("1 sec average for asset animation update %f", _elapsed / 60);
|
||||
Log("Skipped frames : %d", _skippedFrames);
|
||||
_elapsed = 0;
|
||||
_frameCount = 0;
|
||||
Log("Skipped frames : %d", _skippedFrames);
|
||||
_skippedFrames = 0;
|
||||
}
|
||||
|
||||
Timer tmr;
|
||||
@@ -1007,53 +1039,71 @@ namespace polyvox
|
||||
_frameCount++;
|
||||
|
||||
// if a manipulator is active, update the active camera orientation
|
||||
if (_manipulator)
|
||||
{
|
||||
if(_manipulator) {
|
||||
math::double3 eye, target, upward;
|
||||
Camera &cam = _view->getCamera();
|
||||
Camera& cam =_view->getCamera();
|
||||
_manipulator->getLookAt(&eye, &target, &upward);
|
||||
cam.lookAt(eye, target, upward);
|
||||
}
|
||||
|
||||
// Render the scene, unless the renderer wants to skip the frame.
|
||||
if (_renderer->beginFrame(_swapChain, frameTimeInNanos))
|
||||
{
|
||||
_renderer->render(_view);
|
||||
// // TODO - this was an experiment but probably useful to keep for debugging
|
||||
// // if pixelBuffer is provided, we will copy the framebuffer into the pixelBuffer.
|
||||
// if (pixelBuffer)
|
||||
// {
|
||||
// auto pbd = Texture::PixelBufferDescriptor(
|
||||
// pixelBuffer, size_t(1024 * 768 * 4),
|
||||
// Texture::Format::RGBA,
|
||||
// Texture::Type::BYTE, nullptr, callback, data);
|
||||
|
||||
if(_recording) {
|
||||
Viewport const &vp = _view->getViewport();
|
||||
size_t pixelBufferSize = vp.width * vp.height * 4;
|
||||
auto* pixelBuffer = new uint8_t[pixelBufferSize];
|
||||
auto callback = [](void *buf, size_t size, void *data) {
|
||||
auto frameCallbackData = (FrameCallbackData*)data;
|
||||
auto viewer = (FilamentViewer*)frameCallbackData->viewer;
|
||||
viewer->savePng(buf, size, frameCallbackData->frameNumber);
|
||||
delete frameCallbackData;
|
||||
};
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - _startTime).count());
|
||||
|
||||
auto frameNumber = uint32_t(floor(elapsed / _frameInterval));
|
||||
|
||||
auto userData = new FrameCallbackData { this, frameNumber };
|
||||
|
||||
auto pbd = Texture::PixelBufferDescriptor(
|
||||
pixelBuffer, pixelBufferSize,
|
||||
Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE, nullptr, callback, userData);
|
||||
|
||||
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
|
||||
}
|
||||
// _renderer->beginFrame(_swapChain, 0);
|
||||
// _renderer->render(_view);
|
||||
// _renderer->readPixels(0, 0, 1024, 768, std::move(pbd));
|
||||
// _renderer->endFrame();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Render the scene, unless the renderer wants to skip the frame.
|
||||
bool beginFrame = _renderer->beginFrame(_swapChain, frameTimeInNanos);
|
||||
|
||||
_renderer->endFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
_skippedFrames++;
|
||||
}
|
||||
if (beginFrame)
|
||||
{
|
||||
_renderer->render(_view);
|
||||
|
||||
if(_recording) {
|
||||
Viewport const &vp = _view->getViewport();
|
||||
size_t pixelBufferSize = vp.width * vp.height * 4;
|
||||
auto* pixelBuffer = new uint8_t[pixelBufferSize];
|
||||
auto callback = [](void *buf, size_t size, void *data) {
|
||||
auto frameCallbackData = (FrameCallbackData*)data;
|
||||
auto viewer = (FilamentViewer*)frameCallbackData->viewer;
|
||||
viewer->savePng(buf, size, frameCallbackData->frameNumber);
|
||||
delete frameCallbackData;
|
||||
};
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - _startTime).count());
|
||||
|
||||
auto frameNumber = uint32_t(floor(elapsed / _frameInterval));
|
||||
|
||||
auto userData = new FrameCallbackData { this, frameNumber };
|
||||
|
||||
auto pbd = Texture::PixelBufferDescriptor(
|
||||
pixelBuffer, pixelBufferSize,
|
||||
Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE, nullptr, callback, userData);
|
||||
|
||||
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
|
||||
}
|
||||
_renderer->endFrame();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_engine->execute();
|
||||
#endif
|
||||
} else {
|
||||
_skippedFrames++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FilamentViewer::savePng(void* buf, size_t size, int frameNumber) {
|
||||
std::lock_guard lock(_recordingMutex);
|
||||
if(!_recording) {
|
||||
|
||||
@@ -76,6 +76,19 @@ extern "C"
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void rotate_ibl(const void *const viewer, float* rotationMatrix) {
|
||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||
rotationMatrix[2],
|
||||
rotationMatrix[3],
|
||||
rotationMatrix[4],
|
||||
rotationMatrix[5],
|
||||
rotationMatrix[6],
|
||||
rotationMatrix[7],
|
||||
rotationMatrix[8]);
|
||||
|
||||
((FilamentViewer*)viewer)->rotateIbl(matrix);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeSkybox();
|
||||
@@ -330,6 +343,10 @@ extern "C"
|
||||
return ((AssetManager *)assetManager)->setMorphAnimationBuffer(asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose(void *assetManager, EntityId entityId) {
|
||||
((AssetManager*)assetManager)->resetBones(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
@@ -338,9 +355,10 @@ extern "C"
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs)
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace)
|
||||
{
|
||||
((AssetManager *)assetManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs);
|
||||
((AssetManager *)assetManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled)
|
||||
@@ -492,6 +510,15 @@ extern "C"
|
||||
return ((AssetManager *)assetManager)->getNameForEntity(entityId);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const assetManager, const EntityId target, bool renderableOnly) {
|
||||
return ((AssetManager *)assetManager)->getEntityCount(target, renderableOnly);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const assetManager, const EntityId target, int index, bool renderableOnly) {
|
||||
return ((AssetManager *)assetManager)->getEntityNameAt(target, index, renderableOnly);
|
||||
}
|
||||
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording) {
|
||||
((FilamentViewer*)viewer)->setRecording(recording);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,31 @@
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
using namespace polyvox;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern FLUTTER_PLUGIN_EXPORT EMSCRIPTEN_WEBGL_CONTEXT_HANDLE flutter_filament_web_create_gl_context();
|
||||
}
|
||||
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
class RenderLoop {
|
||||
public:
|
||||
@@ -63,8 +86,20 @@ public:
|
||||
void (*renderCallback)(void *), void *const owner) {
|
||||
_renderCallback = renderCallback;
|
||||
_renderCallbackOwner = owner;
|
||||
std::packaged_task<FilamentViewer *()> lambda([&]() mutable {
|
||||
return new FilamentViewer(context, loader, platform, uberArchivePath);
|
||||
std::packaged_task<FilamentViewer *()> lambda([=]() mutable {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
auto emContext = flutter_filament_web_create_gl_context();
|
||||
|
||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)emContext);
|
||||
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
std::cout << "Failed to make context current." << std::endl;
|
||||
return (FilamentViewer*)nullptr;
|
||||
}
|
||||
_viewer = new FilamentViewer((void* const) emContext, loader, platform, uberArchivePath);
|
||||
#else
|
||||
_viewer = new FilamentViewer(context, loader, platform, uberArchivePath);
|
||||
#endif
|
||||
return _viewer;
|
||||
});
|
||||
auto fut = add_task(lambda);
|
||||
fut.wait();
|
||||
@@ -90,10 +125,17 @@ public:
|
||||
}
|
||||
|
||||
void doRender() {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||
_lastRenderTime = std::chrono::high_resolution_clock::now();
|
||||
if(_renderCallback) {
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_webgl_commit_frame();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds) {
|
||||
@@ -121,6 +163,7 @@ private:
|
||||
std::thread *_t = nullptr;
|
||||
std::condition_variable _cond;
|
||||
std::deque<std::function<void()>> _tasks;
|
||||
std::chrono::steady_clock::time_point _lastRenderTime = std::chrono::high_resolution_clock::now();
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
@@ -453,6 +496,25 @@ void set_morph_target_weights_ffi(void *const assetManager,
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
bool set_morph_animation_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs) {
|
||||
std::packaged_task<bool()> lambda(
|
||||
[&] {
|
||||
return set_morph_animation(assetManager, asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
fut.wait();
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
@@ -466,5 +528,31 @@ FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
|
||||
return fut.get();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[&] { return reset_to_rest_pose(assetManager, entityId); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi(
|
||||
void *assetManager,
|
||||
EntityId asset,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
const char *const boneName,
|
||||
const char **const meshNames,
|
||||
int numMeshTargets,
|
||||
float frameLengthInMs,
|
||||
bool isModelSpace) {
|
||||
|
||||
std::packaged_task<void()> lambda(
|
||||
[=] {
|
||||
add_bone_animation(assetManager, asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi() { Log("Dummy called"); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user