diff --git a/android/src/main/cpp/filament_api.cpp b/android/src/main/cpp/filament_api.cpp index 587c7eb6..e7ac6769 100644 --- a/android/src/main/cpp/filament_api.cpp +++ b/android/src/main/cpp/filament_api.cpp @@ -6,10 +6,11 @@ #include using namespace polyvox; +using namespace std; static AAssetManager* am; -std::vector _assets; +vector _assets; uint64_t id = -1; static polyvox::ResourceBuffer loadResource(const char* name) { @@ -122,30 +123,44 @@ extern "C" { ((FilamentViewer*)viewer)->animateWeights((float*)data, numWeights, numFrames, frameRate); } - void get_target_names(void* viewer, char* meshName, char*** outPtr, int* countPtr ) { - StringList names = ((FilamentViewer*)viewer)->getTargetNames(meshName); - - *countPtr = names.count; - - *outPtr = (char**)malloc(sizeof(char*) * names.count); - - __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Got %d names", names.count); - - for(int i = 0; i < names.count; i++) { - std::string as_str(names.strings[i]); - (*outPtr)[i] = (char*)malloc(sizeof(char) * as_str.length()); - strcpy((*outPtr)[i], as_str.c_str()); - } + void play_animation(void* viewer, int index) { + __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Playing embedded animation %d", index); + ((FilamentViewer*)viewer)->playAnimation(index); } - void free_pointer(char*** ptr, int size) { - __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Freeing %d char pointers", size); - for(int i = 0; i < size; i++) { - __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "%d", i); - // free((*ptr)[i]); + char** get_animation_names(void* viewer, int* countPtr) { + auto names = ((FilamentViewer*)viewer)->getAnimationNames(); + __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Got %d animation names", names->size()); + char** names_c; + names_c = new char*[names->size()]; + for(int i = 0; i < names->size(); i++) { + names_c[i] = (char*) names->at(i).c_str(); + __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Alloced animation name %s ", (char*) names->at(i).c_str()); } - __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Free complete"); - // free(*ptr); + (*countPtr) = names->size(); + return names_c; + } + + char** get_target_names(void* viewer, char* meshName, int* countPtr ) { + StringList names = ((FilamentViewer*)viewer)->getTargetNames(meshName); + + __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Got %d names", names.count); + + *countPtr = names.count; + + char** retval; + retval = new char*[names.count]; + + __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Allocated char* array of size %d", names.count); + + for(int i =0; i < names.count; i++) { + retval[i] = (char*)names.strings[i]; + } + return retval; + } + + void free_pointer(char** ptr, int num) { + free(ptr); } void release_source_assets(void* viewer) { diff --git a/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt b/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt index 1614932c..12ff858c 100644 --- a/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt +++ b/android/src/main/kotlin/app/polyvox/filament/FilamentInterop.kt @@ -54,10 +54,14 @@ interface FilamentInterop : Library { fun animate_weights(viewer:Pointer, frames:FloatArray, numWeights:Int, numFrames:Int, frameRate:Float); - fun get_target_names(viewer:Pointer, meshName:String, outPtr:PointerByReference, outLen:IntByReference); + fun get_target_names(viewer:Pointer, meshName:String, outLen:IntByReference) : Pointer; - fun free_pointer(ptr:PointerByReference, size:Int) + fun get_animation_names(viewer:Pointer, outLen:IntByReference) : Pointer; - fun release_source_assets(viewer:Pointer) + fun play_animation(viewer:Pointer, index:Int); + + fun free_pointer(ptr:Pointer, size:Int); + + fun release_source_assets(viewer:Pointer); } diff --git a/android/src/main/kotlin/app/polyvox/filament/FilamentView.kt b/android/src/main/kotlin/app/polyvox/filament/FilamentView.kt index 60874590..641dfbf2 100644 --- a/android/src/main/kotlin/app/polyvox/filament/FilamentView.kt +++ b/android/src/main/kotlin/app/polyvox/filament/FilamentView.kt @@ -201,19 +201,38 @@ PlatformView { "getTargetNames" -> { if(_viewer == null) return; - val arrPtr = PointerByReference(); + val countPtr = IntByReference(); - _lib.get_target_names(_viewer!!, call.arguments as String, arrPtr, countPtr) + val arrPtr = _lib.get_target_names(_viewer!!, call.arguments as String, countPtr) - val names = arrPtr.value.getStringArray(0, countPtr.value); - - Log.v(TAG, "Got target names $names") + val names = arrPtr.getStringArray(0, countPtr.value); + for(i in 0..countPtr.value-1) { + Log.v(TAG, "Got target names ${names[i]} ${names[i].length}") + } + val namesAsList = names.toCollection(ArrayList()) _lib.free_pointer(arrPtr, countPtr.getValue()) - Log.v(TAG, "Free complete") + result.success(namesAsList) + } + "getAnimationNames" -> { + if(_viewer == null) + return; + + val countPtr = IntByReference(); + val arrPtr = _lib.get_animation_names(_viewer!!, countPtr) + + val names = arrPtr.getStringArray(0, countPtr.value); + + for(i in 0..countPtr.value-1) { + Log.v(TAG, "Got animation names ${names[i]} ${names[i].length}") + } + + val namesAsList = names.toCollection(ArrayList()) + + _lib.free_pointer(arrPtr, 1) result.success(namesAsList) } @@ -281,6 +300,13 @@ PlatformView { "releaseSourceAssets" -> { _lib.release_source_assets(_viewer!!) result.success("OK"); + } + "playAnimation" -> { + _lib.play_animation(_viewer!!, call.arguments as Int) + result.success("OK") + } + else -> { + result.notImplemented() } } } diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index 47f0c569..c56892bc 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -73,37 +73,42 @@ using namespace gltfio; using namespace utils; using namespace std::chrono; -namespace gltfio { - MaterialProvider* createUbershaderLoader(filament::Engine* engine); +namespace gltfio +{ + MaterialProvider *createUbershaderLoader(filament::Engine *engine); } -namespace filament { - class IndirectLight; - class LightManager; +namespace filament +{ + class IndirectLight; + class LightManager; } -namespace gltfio { - MaterialProvider* createGPUMorphShaderLoader( - const void* opaqueData, - uint64_t opaqueDataSize, - const void* fadeData, - uint64_t fadeDataSize, - Engine* engine); - void decomposeMatrix(const filament::math::mat4f& mat, filament::math::float3* translation, - filament::math::quatf* rotation, filament::math::float3* scale); +namespace gltfio +{ + MaterialProvider *createGPUMorphShaderLoader( + const void *opaqueData, + uint64_t opaqueDataSize, + const void *fadeData, + uint64_t fadeDataSize, + Engine *engine); + void decomposeMatrix(const filament::math::mat4f &mat, filament::math::float3 *translation, + filament::math::quatf *rotation, filament::math::float3 *scale); } -namespace polyvox { - -const double kNearPlane = 0.05; // 5 cm -const double kFarPlane = 1000.0; // 1 km -const float kScaleMultiplier = 100.0f; -const float kAperture = 16.0f; -const float kShutterSpeed = 1.0f / 125.0f; -const float kSensitivity = 100.0f; +namespace polyvox +{ -filament::math::mat4f composeMatrix(const filament::math::float3& translation, - const filament::math::quatf& rotation, const filament::math::float3& scale) { + const double kNearPlane = 0.05; // 5 cm + const double kFarPlane = 1000.0; // 1 km + const float kScaleMultiplier = 100.0f; + const float kAperture = 16.0f; + const float kShutterSpeed = 1.0f / 125.0f; + const float kSensitivity = 100.0f; + + filament::math::mat4f composeMatrix(const filament::math::float3 &translation, + const filament::math::quatf &rotation, const filament::math::float3 &scale) + { float tx = translation[0]; float ty = translation[1]; float tz = translation[2]; @@ -115,38 +120,39 @@ filament::math::mat4f composeMatrix(const filament::math::float3& translation, float sy = scale[1]; float sz = scale[2]; return filament::math::mat4f( - (1 - 2 * qy*qy - 2 * qz*qz) * sx, - (2 * qx*qy + 2 * qz*qw) * sx, - (2 * qx*qz - 2 * qy*qw) * sx, + (1 - 2 * qy * qy - 2 * qz * qz) * sx, + (2 * qx * qy + 2 * qz * qw) * sx, + (2 * qx * qz - 2 * qy * qw) * sx, 0.f, - (2 * qx*qy - 2 * qz*qw) * sy, - (1 - 2 * qx*qx - 2 * qz*qz) * sy, - (2 * qy*qz + 2 * qx*qw) * sy, + (2 * qx * qy - 2 * qz * qw) * sy, + (1 - 2 * qx * qx - 2 * qz * qz) * sy, + (2 * qy * qz + 2 * qx * qw) * sy, 0.f, - (2 * qx*qz + 2 * qy*qw) * sz, - (2 * qy*qz - 2 * qx*qw) * sz, - (1 - 2 * qx*qx - 2 * qy*qy) * sz, + (2 * qx * qz + 2 * qy * qw) * sz, + (2 * qy * qz - 2 * qx * qw) * sz, + (1 - 2 * qx * qx - 2 * qy * qy) * sz, 0.f, tx, ty, tz, 1.f); -} + } -FilamentViewer::FilamentViewer( - void* layer, - const char* opaqueShaderPath, - const char* fadeShaderPath, - LoadResource loadResource, - FreeResource freeResource) : _layer(layer), - _loadResource(loadResource), - _freeResource(freeResource), - opaqueShaderResources(nullptr, 0, 0), - fadeShaderResources(nullptr, 0, 0), - _assetBuffer(nullptr, 0, 0) { + FilamentViewer::FilamentViewer( + void *layer, + const char *opaqueShaderPath, + const char *fadeShaderPath, + LoadResource loadResource, + FreeResource freeResource) : _layer(layer), + _loadResource(loadResource), + _freeResource(freeResource), + opaqueShaderResources(nullptr, 0, 0), + fadeShaderResources(nullptr, 0, 0), + _assetBuffer(nullptr, 0, 0) + { _engine = Engine::create(Engine::Backend::OPENGL); _renderer = _engine->createRenderer(); - _renderer->setDisplayInfo({ .refreshRate = 60.0f, + _renderer->setDisplayInfo({.refreshRate = 60.0f, .presentationDeadlineNanos = (uint64_t)0, - .vsyncOffsetNanos = (uint64_t)0 }); + .vsyncOffsetNanos = (uint64_t)0}); _scene = _engine->createScene(); Entity camera = EntityManager::get().create(); _mainCamera = _engine->createCamera(camera); @@ -164,8 +170,9 @@ FilamentViewer::FilamentViewer( // options.homogeneousScaling = homogeneousScaling; // options.minScale = filament::math::float2{ minScale }; // options.maxScale = filament::math::float2{ maxScale }; - //options.sharpness = sharpness; - options.quality = View::QualityLevel::MEDIUM;; + // options.sharpness = sharpness; + options.quality = View::QualityLevel::MEDIUM; + ; _view->setDynamicResolutionOptions(options); View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions; @@ -175,368 +182,449 @@ FilamentViewer::FilamentViewer( _materialProvider = gltfio::createUbershaderLoader(_engine); - EntityManager& em = EntityManager::get(); + EntityManager &em = EntityManager::get(); _ncm = new NameComponentManager(em); _assetLoader = AssetLoader::create({_engine, _materialProvider, _ncm, &em}); _resourceLoader = new ResourceLoader( - {.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = false}); - + {.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = true}); + manipulator = - Manipulator::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, -4.0f).build(Mode::ORBIT); + Manipulator::Builder().orbitHomePosition(0.0f, 0.0f, 0.05f).targetPosition(0.0f, 0.0f, 0.0f).build(Mode::ORBIT); _asset = nullptr; - -} - -FilamentViewer::~FilamentViewer() { - -} - -Renderer* FilamentViewer::getRenderer() { - return _renderer; -} - -void FilamentViewer::createSwapChain(void* surface) { - _swapChain = _engine->createSwapChain(surface); - // Log("swapchain created."); -} - -void FilamentViewer::destroySwapChain() { - if(_swapChain) { - _engine->destroy(_swapChain); - _swapChain = nullptr; } - // Log("swapchain destroyed."); -} -void FilamentViewer::applyWeights(float* weights, int count) { - - for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) { - _asset->setMorphWeights( - _asset->getEntities()[i], - weights, - count - ); + FilamentViewer::~FilamentViewer() + { } -} -void FilamentViewer::loadResources(string relativeResourcePath) { - const char* const* const resourceUris = _asset->getResourceUris(); + Renderer *FilamentViewer::getRenderer() + { + return _renderer; + } + + void FilamentViewer::createSwapChain(void *surface) + { + _swapChain = _engine->createSwapChain(surface); + // Log("swapchain created."); + } + + void FilamentViewer::destroySwapChain() + { + if (_swapChain) + { + _engine->destroy(_swapChain); + _swapChain = nullptr; + } + // Log("swapchain destroyed."); + } + + void FilamentViewer::applyWeights(float *weights, int count) + { + + for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) + { + _asset->setMorphWeights( + _asset->getEntities()[i], + weights, + count); + } + } + + void FilamentViewer::loadResources(string relativeResourcePath) + { + const char *const *const resourceUris = _asset->getResourceUris(); const size_t resourceUriCount = _asset->getResourceUriCount(); Log("Loading %d resources for asset", resourceUriCount); - for (size_t i = 0; i < resourceUriCount; i++) { - string uri = relativeResourcePath + string(resourceUris[i]); - ResourceBuffer buf = _loadResource(uri.c_str()); - - // using FunctionCallback = std::function; + for (size_t i = 0; i < resourceUriCount; i++) + { + string uri = relativeResourcePath + string(resourceUris[i]); + ResourceBuffer buf = _loadResource(uri.c_str()); - // auto cb = [&] (void * ptr, unsigned int len, void * misc) { - - // }; - // FunctionCallback fcb = cb; - ResourceLoader::BufferDescriptor b( - buf.data, buf.size); - _resourceLoader->addResourceData(resourceUris[i], std::move(b)); - _freeResource(buf); + // using FunctionCallback = std::function; + + // auto cb = [&] (void * ptr, unsigned int len, void * misc) { + + // }; + // FunctionCallback fcb = cb; + ResourceLoader::BufferDescriptor b( + buf.data, buf.size); + _resourceLoader->addResourceData(resourceUris[i], std::move(b)); + _freeResource(buf); } _resourceLoader->loadResources(_asset); - const Entity* entities = _asset->getEntities(); - RenderableManager& rm = _engine->getRenderableManager(); - for(int i =0; i< _asset->getEntityCount(); i++) { - Entity e = entities[i]; - auto inst = rm.getInstance(e); - rm.setCulling(inst, false); + const Entity *entities = _asset->getEntities(); + RenderableManager &rm = _engine->getRenderableManager(); + for (int i = 0; i < _asset->getEntityCount(); i++) + { + Entity e = entities[i]; + auto inst = rm.getInstance(e); + rm.setCulling(inst, false); } _animator = _asset->getAnimator(); - _scene->addEntities(_asset->getEntities(), _asset->getEntityCount()); -}; + _scene->addEntities(_asset->getEntities(), _asset->getEntityCount()); + }; -void FilamentViewer::releaseSourceAssets() { - Log("Releasing source data"); - _asset->releaseSourceData(); - // _freeResource(opaqueShaderResources); - // _freeResource(fadeShaderResources); -} + void FilamentViewer::releaseSourceAssets() + { + Log("Releasing source data"); + _asset->releaseSourceData(); + // _freeResource(opaqueShaderResources); + // _freeResource(fadeShaderResources); + } + void FilamentViewer::loadGlb(const char *const uri) + { -void FilamentViewer::loadGlb(const char* const uri) { - - Log("Loading GLB at URI %s", uri); + Log("Loading GLB at URI %s", uri); - if(_asset) { - _asset->releaseSourceData(); - _resourceLoader->evictResourceData(); - _scene->removeEntities(_asset->getEntities(), _asset->getEntityCount()); - _assetLoader->destroyAsset(_asset); - } - _asset = nullptr; - _animator = nullptr; + if (_asset) + { + _asset->releaseSourceData(); + _resourceLoader->evictResourceData(); + _scene->removeEntities(_asset->getEntities(), _asset->getEntityCount()); + _assetLoader->destroyAsset(_asset); + } + _asset = nullptr; + _animator = nullptr; - ResourceBuffer rbuf = _loadResource(uri); + ResourceBuffer rbuf = _loadResource(uri); - _asset = _assetLoader->createAssetFromBinary( - (const uint8_t*)rbuf.data, rbuf.size); + _asset = _assetLoader->createAssetFromBinary( + (const uint8_t *)rbuf.data, rbuf.size); - if (!_asset) { + if (!_asset) + { Log("Unknown error loading GLB asset."); exit(1); - } - - int entityCount = _asset->getEntityCount(); - - _scene->addEntities(_asset->getEntities(), entityCount); + } - Log("Added %d entities to scene", entityCount); - _resourceLoader->loadResources(_asset); - _animator = _asset->getAnimator(); + int entityCount = _asset->getEntityCount(); - const Entity* entities = _asset->getEntities(); - RenderableManager& rm = _engine->getRenderableManager(); - for(int i =0; i< _asset->getEntityCount(); i++) { - Entity e = entities[i]; - auto inst = rm.getInstance(e); - rm.setCulling(inst, false); + _scene->addEntities(_asset->getEntities(), entityCount); + + Log("Added %d entities to scene", entityCount); + _resourceLoader->loadResources(_asset); + _animator = _asset->getAnimator(); + + const Entity *entities = _asset->getEntities(); + RenderableManager &rm = _engine->getRenderableManager(); + for (int i = 0; i < _asset->getEntityCount(); i++) + { + Entity e = entities[i]; + auto inst = rm.getInstance(e); + rm.setCulling(inst, false); } _freeResource(rbuf); - - Log("Successfully loaded GLB."); -} -void FilamentViewer::loadGltf(const char* const uri, const char* const relativeResourcePath) { + _animator->updateBoneMatrices(); + + Log("Successfully loaded GLB."); + } + + void FilamentViewer::loadGltf(const char *const uri, const char *const relativeResourcePath) + { Log("Loading GLTF at URI %s", uri); - if(_asset) { - Log("Asset already exists"); - _resourceLoader->evictResourceData(); - _scene->removeEntities(_asset->getEntities(), _asset->getEntityCount()); - _assetLoader->destroyAsset(_asset); - _freeResource(_assetBuffer); + if (_asset) + { + Log("Asset already exists"); + _resourceLoader->evictResourceData(); + _scene->removeEntities(_asset->getEntities(), _asset->getEntityCount()); + _assetLoader->destroyAsset(_asset); + _freeResource(_assetBuffer); } _asset = nullptr; _animator = nullptr; _assetBuffer = _loadResource(uri); - + // Parse the glTF file and create Filament entities. Log("Creating asset from JSON"); - _asset = _assetLoader->createAssetFromJson((uint8_t*)_assetBuffer.data, _assetBuffer.size); + _asset = _assetLoader->createAssetFromJson((uint8_t *)_assetBuffer.data, _assetBuffer.size); Log("Created asset from JSON"); - - if (!_asset) { - Log("Unable to parse asset"); - exit(1); + + if (!_asset) + { + Log("Unable to parse asset"); + exit(1); } Log("Loading relative resources"); loadResources(string(relativeResourcePath) + string("/")); Log("Loaded relative resources"); -// _asset->releaseSourceData(); + // _asset->releaseSourceData(); Log("Load complete for GLTF at URI %s", uri); // transformToUnitCube(); - -} + } -bool FilamentViewer::setCamera(const char* cameraName) { - FFilamentAsset* asset = (FFilamentAsset*)_asset; + /// + /// Sets the active camera to the GLTF camera specified by [name]. + /// Blender export arranges cameras as follows + /// - parent node with global (?) matrix + /// --- child node with "camera" property set to camera node name + /// - camera node + /// We therefore find the first node where the "camera" property is equal to the requested name, + /// then use the parent transform matrix. + /// + bool FilamentViewer::setCamera(const char *cameraName) + { + FFilamentAsset *asset = (FFilamentAsset *)_asset; - gltfio::NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap - : asset->mNodeMap; - Log("Setting camera to %s", cameraName); - for (auto pair : sourceNodes) { + gltfio::NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap + : asset->mNodeMap; + Log("Setting camera to node %s", cameraName); + for (auto pair : sourceNodes) + { cgltf_node const *node = pair.first; - if(!node->camera) { - if(node->name) { - Log("No camera found under node %s", node->name); - } else { - Log("No camera found under unnamed node."); - } + if (strcmp(cameraName, node->name) != 0) + { continue; } - Log("Found camera under node %s", node->name); + Log("Node %s : Matrix : %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f %03f Translation : %03f %03f %03f Rotation %03f %03f %03f %03f Scale %03f %03f %03f", + node->name, + node->matrix[0], + node->matrix[1], + node->matrix[2], + node->matrix[3], + node->matrix[4], + node->matrix[5], + node->matrix[6], + node->matrix[7], + node->matrix[8], + node->matrix[9], + node->matrix[10], + node->matrix[11], + node->matrix[12], + node->matrix[13], + node->matrix[14], + node->matrix[15], + node->translation[0], + node->translation[1], + node->translation[2], + node->rotation[0], + node->rotation[1], + node->rotation[2], + node->rotation[3], + node->scale[0], + node->scale[1], + node->scale[2] + ); + mat4f t = mat4f::translation(float3 { node->translation[0],node->translation[1],node->translation[2] }); + mat4f r { quatf { node->rotation[3], node->rotation[0], node->rotation[1], node->rotation[2] } }; + mat4f transform = t * r; - if(node->camera->name) { - Log("Checking camera : %s", node->camera->name); + if (!node->camera) + { + cgltf_node* leaf = node->children[0]; + + Log("Child 1 trans : %03f %03f %03f rot : %03f %03f %03f %03f ", leaf->translation[0], leaf->translation[1],leaf->translation[2], leaf->rotation[0],leaf->rotation[1],leaf->rotation[2],leaf->rotation[3]); + + if (!leaf->camera) { + leaf = leaf->children[0]; + Log("Child 2 %03f %03f %03f %03f %03f %03f %03f ", leaf->translation[0], leaf->translation[1],leaf->translation[2], leaf->rotation[0],leaf->rotation[1],leaf->rotation[2],leaf->rotation[3]); + if (!leaf->camera) { + Log("Could not find GLTF camera under node or its ssecond or third child nodes."); + exit(-1); + } + } + + Log("Using rotation from leaf node."); + + mat4f child_rot { quatf { leaf->rotation[3], leaf->rotation[0], leaf->rotation[1], leaf->rotation[2] } }; + + transform *= child_rot; } + + Entity cameraEntity = EntityManager::get().create(); + Camera *cam = _engine->createCamera(cameraEntity); - if(strcmp(cameraName, node->camera->name) == 0) { - Log("Found camera."); - filament::math::mat4 mat( - node->matrix[0], - node->matrix[1], - node->matrix[2], - node->matrix[3], - node->matrix[4], - node->matrix[5], - node->matrix[6], - node->matrix[7], - node->matrix[8], - node->matrix[9], - node->matrix[10], - node->matrix[11], - node->parent->translation[0], - node->parent->translation[1], - node->parent->translation[2], - 1 + const Viewport &vp = _view->getViewport(); + + const double aspect = (double)vp.width / vp.height; + + // todo - pull focal length from gltf node + + cam->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane); + + if (!cam) + { + Log("Couldn't create camera"); + } + else + { + _engine->getTransformManager().setTransform( + _engine->getTransformManager().getInstance(cameraEntity), transform ); - quatf rot1(node->parent->rotation[0],node->parent->rotation[1], node->parent->rotation[2], node->parent->rotation[3]); - quatf rot2(node->rotation[0],node->rotation[1], node->rotation[2], node->rotation[3]); - quatf rot3 = rot1 * rot2; - filament::math::mat4 rotm(rot3); - - filament::math::mat4 result = mat * rotm; - - Entity cameraEntity = EntityManager::get().create(); - Camera* cam = _engine->createCamera(cameraEntity); - - const Viewport& vp = _view->getViewport(); - - const double aspect = (double)vp.width / vp.height; - - cam->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane); - - if(!cam) { - Log("Couldn't create camera"); - } else { - _engine->getTransformManager().setTransform( - _engine->getTransformManager().getInstance(cameraEntity), result); - - _view->setCamera(cam); - return true; - } + _view->setCamera(cam); + return true; } + } + return false; } - return false; -} -StringList FilamentViewer::getTargetNames(const char* meshName) { - FFilamentAsset* asset = (FFilamentAsset*)_asset; - NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap : asset->mNodeMap; + unique_ptr> FilamentViewer::getAnimationNames() + { - if(sourceNodes.empty()) { + size_t count = _animator->getAnimationCount(); + + Log("Found %d animations in asset.", count); + + unique_ptr> names = make_unique>(); + + for (size_t i = 0; i < count; i++) + { + names->push_back(_animator->getAnimationName(i)); + } + + return names; + } + + StringList FilamentViewer::getTargetNames(const char *meshName) + { + FFilamentAsset *asset = (FFilamentAsset *)_asset; + NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap : asset->mNodeMap; + + if (sourceNodes.empty()) + { Log("Asset source nodes empty?"); return StringList(nullptr, 0); - } - Log("Fetching morph target names for mesh %s", meshName); + } + Log("Fetching morph target names for mesh %s", meshName); - for (auto pair : sourceNodes) { + for (auto pair : sourceNodes) + { cgltf_node const *node = pair.first; cgltf_mesh const *mesh = node->mesh; - if (mesh) { - Log("Mesh : %s ",mesh->name); - if(strcmp(meshName, mesh->name) == 0) { - return StringList((const char**)mesh->target_names, (int) mesh->target_names_count); - } - } + if (mesh) + { + Log("Mesh : %s ", mesh->name); + if (strcmp(meshName, mesh->name) == 0) + { + return StringList((const char **)mesh->target_names, (int)mesh->target_names_count); + } + } + } + return StringList(nullptr, 0); } - return StringList(nullptr, 0); -} + void FilamentViewer::loadSkybox(const char *const skyboxPath, const char *const iblPath, AAssetManager *am) + { -void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath, AAssetManager* am) { - ResourceBuffer skyboxBuffer = _loadResource(skyboxPath); - image::KtxBundle* skyboxBundle = - new image::KtxBundle(static_cast(skyboxBuffer.data), static_cast(skyboxBuffer.size)); + image::KtxBundle *skyboxBundle = + new image::KtxBundle(static_cast(skyboxBuffer.data), static_cast(skyboxBuffer.size)); _skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false); _skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine); - + _scene->setSkybox(_skybox); _freeResource(skyboxBuffer); - - Log("Loading IBL from %s", iblPath); + + Log("Loading IBL from %s", iblPath); // Load IBL. ResourceBuffer iblBuffer = _loadResource(iblPath); - image::KtxBundle* iblBundle = new image::KtxBundle( - static_cast(iblBuffer.data), static_cast(iblBuffer.size)); + image::KtxBundle *iblBundle = new image::KtxBundle( + static_cast(iblBuffer.data), static_cast(iblBuffer.size)); math::float3 harmonics[9]; iblBundle->getSphericalHarmonics(harmonics); _iblTexture = image::ktx::createTexture(_engine, iblBundle, false); _indirectLight = IndirectLight::Builder() - .reflections(_iblTexture) - .irradiance(3, harmonics) - .intensity(30000.0f) - .build(*_engine); + .reflections(_iblTexture) + .irradiance(3, harmonics) + .intensity(30000.0f) + .build(*_engine); _scene->setIndirectLight(_indirectLight); - + _freeResource(iblBuffer); // Always add a direct light source since it is required for shadowing. _sun = EntityManager::get().create(); LightManager::Builder(LightManager::Type::DIRECTIONAL) - .color(Color::cct(6500.0f)) - .intensity(100000.0f) - .direction(math::float3(0.0f, 1.0f, 0.0f)) - .castShadows(true) - .build(*_engine, _sun); + .color(Color::cct(6500.0f)) + .intensity(100000.0f) + .direction(math::float3(0.0f, 1.0f, 0.0f)) + .castShadows(true) + .build(*_engine, _sun); _scene->addEntity(_sun); - + Log("Skybox/IBL load complete."); + } -} + void FilamentViewer::transformToUnitCube() + { + if (!_asset) + { + Log("No asset, cannot transform."); + return; + } + auto &tm = _engine->getTransformManager(); + auto aabb = _asset->getBoundingBox(); + auto center = aabb.center(); + auto halfExtent = aabb.extent(); + auto maxExtent = max(halfExtent) * 2; + auto scaleFactor = 2.0f / maxExtent; + auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); + tm.setTransform(tm.getInstance(_asset->getRoot()), transform); + } -void FilamentViewer::transformToUnitCube() { - if (!_asset) { - Log("No asset, cannot transform."); - return; - } - auto& tm = _engine->getTransformManager(); - auto aabb = _asset->getBoundingBox(); - auto center = aabb.center(); - auto halfExtent = aabb.extent(); - auto maxExtent = max(halfExtent) * 2; - auto scaleFactor = 2.0f / maxExtent; - auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); - tm.setTransform(tm.getInstance(_asset->getRoot()), transform); -} - -void FilamentViewer::cleanup() { + void FilamentViewer::cleanup() + { _resourceLoader->asyncCancelLoad(); _assetLoader->destroyAsset(_asset); _materialProvider->destroyMaterials(); AssetLoader::destroy(&_assetLoader); _freeResource(_assetBuffer); -}; + }; -void FilamentViewer::render() { - if (!_view || !_mainCamera || !_swapChain) { - Log("Not ready for rendering"); - return; + void FilamentViewer::render() + { + if (!_view || !_mainCamera || !_swapChain) + { + Log("Not ready for rendering"); + return; } - if(morphAnimationBuffer) { + if (morphAnimationBuffer) + { updateMorphAnimation(); } + if(embeddedAnimationBuffer) { + updateEmbeddedAnimation(); + } + math::float3 eye, target, upward; manipulator->getLookAt(&eye, &target, &upward); _mainCamera->lookAt(eye, target, upward); // Render the scene, unless the renderer wants to skip the frame. - if (_renderer->beginFrame(_swapChain)) { - _renderer->render(_view); - _renderer->endFrame(); - } -} + if (_renderer->beginFrame(_swapChain)) + { + _renderer->render(_view); + _renderer->endFrame(); + } + } - -void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor) { - if (!_view || !_mainCamera) { - Log("Skipping camera update, no view or camrea"); - return; + void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor) + { + if (!_view || !_mainCamera) + { + Log("Skipping camera update, no view or camrea"); + return; } const uint32_t _width = width * contentScaleFactor; @@ -546,58 +634,65 @@ void FilamentViewer::updateViewportAndCameraProjection(int width, int height, fl const double aspect = (double)width / height; _mainCamera->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane); Log("Set viewport to %d %d", _width, _height); -} - -void FilamentViewer::animateWeights(float* data, int numWeights, int numFrames, float frameRate) { - morphAnimationBuffer = std::make_unique(data, numWeights, numFrames, 1000 / frameRate ); -} - -void FilamentViewer::updateMorphAnimation() { - - if(morphAnimationBuffer->frameIndex >= morphAnimationBuffer->numFrames) { - morphAnimationBuffer = nullptr; - return; } - - if(morphAnimationBuffer->frameIndex == -1) { - morphAnimationBuffer->frameIndex++; - morphAnimationBuffer->startTime = std::chrono::high_resolution_clock::now(); - applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights); - } else { - std::chrono::duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->startTime; - int frameIndex = dur.count() / morphAnimationBuffer->frameLength; - if(frameIndex != morphAnimationBuffer->frameIndex) { + + void FilamentViewer::animateWeights(float *data, int numWeights, int numFrames, float frameRate) + { + morphAnimationBuffer = std::make_unique(data, numWeights, numFrames, 1000 / frameRate); + } + + void FilamentViewer::updateMorphAnimation() + { + + if (morphAnimationBuffer->frameIndex >= morphAnimationBuffer->numFrames) + { + morphAnimationBuffer = nullptr; + return; + } + + if (morphAnimationBuffer->frameIndex == -1) + { + morphAnimationBuffer->frameIndex++; + morphAnimationBuffer->startTime = std::chrono::high_resolution_clock::now(); + applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights); + } + else + { + std::chrono::duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->startTime; + int frameIndex = dur.count() / morphAnimationBuffer->frameLength; + if (frameIndex != morphAnimationBuffer->frameIndex) + { morphAnimationBuffer->frameIndex = frameIndex; applyWeights(morphAnimationBuffer->frameData + (morphAnimationBuffer->frameIndex * morphAnimationBuffer->numWeights), morphAnimationBuffer->numWeights); + } } } - -} + void FilamentViewer::playAnimation(int index) { + embeddedAnimationBuffer = make_unique(index, _animator->getAnimationDuration(index)); + } + void FilamentViewer::updateEmbeddedAnimation() { + duration dur = duration_cast>(std::chrono::high_resolution_clock::now() - embeddedAnimationBuffer->lastTime); + float startTime = 0; + if(!embeddedAnimationBuffer->hasStarted) { + embeddedAnimationBuffer->hasStarted = true; + embeddedAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); + } else if(dur.count() >= embeddedAnimationBuffer->duration) { + embeddedAnimationBuffer = nullptr; + return; + } else { + startTime = dur.count(); + } + _animator->applyAnimation(embeddedAnimationBuffer->animationIndex, startTime); + _animator->updateBoneMatrices(); + + } } - -// void FilamentViewer::updateEmbeddedAnimation() { -// duration dur = duration_cast>(std::chrono::high_resolution_clock::now() - embeddedAnimationBuffer->lastTime); -// float startTime = 0; -// if(!embeddedAnimationBuffer->hasStarted) { -// embeddedAnimationBuffer->hasStarted = true; -// embeddedAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); -// } else if(dur.count() >= embeddedAnimationBuffer->duration) { -// embeddedAnimationBuffer = nullptr; -// return; -// } else { -// startTime = dur.count(); -// } - -// _animator->applyAnimation(embeddedAnimationBuffer->animationIndex, startTime); -// _animator->updateBoneMatrices(); - -// } // // // //if(morphAnimationBuffer.frameIndex >= morphAnimationBuffer.numFrames) { // // this.morphAnimationBuffer = null; @@ -617,9 +712,6 @@ void FilamentViewer::updateMorphAnimation() { // // morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); // // } // //} -// void FilamentViewer::playAnimation(int index) { -// embeddedAnimationBuffer = make_unique(index, _animator->getAnimationDuration(index)); -// } // void FilamentViewer::createMorpher(const char* meshName, int* primitives, int numPrimitives) { @@ -656,7 +748,7 @@ void FilamentViewer::updateMorphAnimation() { // this.animation = null; // return; // } - + // if(animation.frameIndex == -1) { // animation->frameIndex++; // animation->lastTime = std::chrono::high_resolution_clock::now(); @@ -670,4 +762,4 @@ void FilamentViewer::updateMorphAnimation() { // callback(); // applyWeights(frameData + (frameIndex * numWeights), numWeights); // } // } -// } \ No newline at end of file +// } diff --git a/ios/src/FilamentViewer.hpp b/ios/src/FilamentViewer.hpp index 71c19062..5ba3a189 100644 --- a/ios/src/FilamentViewer.hpp +++ b/ios/src/FilamentViewer.hpp @@ -54,6 +54,16 @@ namespace polyvox { const int count; }; + struct EmbeddedAnimationBuffer { + EmbeddedAnimationBuffer(int animationIndex, float duration) : animationIndex(animationIndex), duration(duration) {} + bool hasStarted = false; + int animationIndex; + float duration = 0; + time_point_t lastTime; + }; + + + struct ResourceBuffer { ResourceBuffer(const void* data, const uint32_t size, const uint32_t id) : data(data), size(size), id(id) {}; @@ -102,6 +112,7 @@ namespace polyvox { // void createMorpher(const char* meshName, int* primitives, int numPrimitives); void releaseSourceAssets(); StringList getTargetNames(const char* meshName); + unique_ptr> getAnimationNames(); Manipulator* manipulator; void applyWeights(float* weights, int count); void animateWeights(float* data, int numWeights, int length, float frameRate); @@ -158,27 +169,16 @@ namespace polyvox { float _cameraFocalLength = 0.0f; void updateMorphAnimation(); - // void updateEmbeddedAnimation(); + void updateEmbeddedAnimation(); // animation flags; bool isAnimating; unique_ptr morphAnimationBuffer; - // unique_ptr embeddedAnimationBuffer; - - - + unique_ptr embeddedAnimationBuffer; }; + + } - // struct EmbeddedAnimationBuffer { - - // EmbeddedAnimationBuffer(int animationIndex, float duration) : animationIndex(animationIndex), duration(duration) {} - // bool hasStarted = false; - // int animationIndex; - // float duration = 0; - // time_point_t lastTime; - // }; - - \ No newline at end of file diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 27423482..bfd8cf5d 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -15,6 +15,7 @@ abstract class FilamentController { Future rotateEnd(); Future applyWeights(List weights); Future> getTargetNames(String meshName); + Future> getAnimationNames(); Future releaseSourceAssets(); Future playAnimation(int index); Future setCamera(String name); @@ -102,6 +103,12 @@ class PolyvoxFilamentController extends FilamentController { return result; } + Future> getAnimationNames() async { + var result = (await _channel.invokeMethod("getAnimationNames")) + .cast(); + return result; + } + Future animate(List weights, int numWeights, double frameRate) async { await _channel .invokeMethod("animateWeights", [weights, numWeights, frameRate]);