#include "SceneAsset.hpp" #include "Log.hpp" #include "SceneResources.hpp" #include #include #include #include #include #include #include using namespace std::chrono; namespace polyvox { using namespace std; using namespace filament; using namespace filament::gltfio; using namespace utils; SceneAsset::SceneAsset(FilamentAsset *asset, Engine *engine, NameComponentManager *ncm) : _asset(asset), _engine(engine), _ncm(ncm) { _animator = _asset->getAnimator(); for (int i = 0; i < _animator->getAnimationCount(); i++) { _embeddedAnimationStatus.push_back( EmbeddedAnimationStatus(i, _animator->getAnimationDuration(i), false)); } Log("Created animation buffers for %d", _embeddedAnimationStatus.size()); } SceneAsset::~SceneAsset() { // we defer all destructor work to SceneAssetLoader so we don't need to do anything here } void SceneAsset::applyWeights(float *weights, int count) { RenderableManager &rm = _engine->getRenderableManager(); for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) { auto inst = rm.getInstance(_asset->getEntities()[i]); rm.setMorphWeights(inst, weights, count); } } void SceneAsset::animateWeights(float *data, int numWeights, int numFrames, float frameLengthInMs) { Log("Making morph animation buffer with %d weights across %d frames and " "frame length %f ms ", numWeights, numFrames, frameLengthInMs); _morphAnimationBuffer = std::make_unique( data, numWeights, numFrames, frameLengthInMs); } void SceneAsset::updateAnimations() { updateMorphAnimation(); updateEmbeddedAnimations(); } void SceneAsset::updateMorphAnimation() { if (!_morphAnimationBuffer) { return; } if (_morphAnimationBuffer->frameIndex == -1) { _morphAnimationBuffer->frameIndex++; _morphAnimationBuffer->startTime = high_resolution_clock::now(); applyWeights(_morphAnimationBuffer->frameData, _morphAnimationBuffer->numWeights); } else { duration dur = high_resolution_clock::now() - _morphAnimationBuffer->startTime; int frameIndex = static_cast(dur.count() / _morphAnimationBuffer->frameLengthInMs); if (frameIndex > _morphAnimationBuffer->numFrames - 1) { duration dur = high_resolution_clock::now() - _morphAnimationBuffer->startTime; Log("Morph animation completed in %f ms (%d frames at framerate %f), " "final frame was %d", dur.count(), _morphAnimationBuffer->numFrames, 1000 / _morphAnimationBuffer->frameLengthInMs, _morphAnimationBuffer->frameIndex); _morphAnimationBuffer = nullptr; } else if (frameIndex != _morphAnimationBuffer->frameIndex) { Log("Rendering frame %d (of a total %d)", frameIndex, _morphAnimationBuffer->numFrames); _morphAnimationBuffer->frameIndex = frameIndex; auto framePtrOffset = frameIndex * _morphAnimationBuffer->numWeights; applyWeights(_morphAnimationBuffer->frameData + framePtrOffset, _morphAnimationBuffer->numWeights); } } } void SceneAsset::playAnimation(int index, bool loop) { Log("Playing animation at index %d", index); if (index > _animator->getAnimationCount() - 1) { Log("Asset does not contain an animation at index %d", index); } else if (_embeddedAnimationStatus[index].started) { Log("Animation already playing, call stop first."); } else { Log("Starting animation at index %d", index); _embeddedAnimationStatus[index].play = true; _embeddedAnimationStatus[index].loop = loop; } } void SceneAsset::stopAnimation(int index) { // TODO - does this need to be threadsafe? _embeddedAnimationStatus[index].play = false; _embeddedAnimationStatus[index].started = false; } // void SceneAsset:swapTexture() { // materialInstance = material2.createInstance() // baseColor = loadTexture(filament.engine, context.resources, R.drawable.wall_tex_at, TextureType.COLOR) // normal = loadTexture(filament.engine, context.resources,R.drawable.wall_tex_n,TextureType.NORMAL) // ao = loadTexture(filament.engine, context.resources,R.drawable.wall_tex_ao,TextureType.DATA) // roughnessMetallic = loadTexture(filament.engine, context.resources,R.drawable.wall_tex_ms,TextureType.DATA) // val rm = filament.engine.renderableManager // val sampler = TextureSampler() // sampler.anisotropy = 8.0f // material.setParameter("baseColorIndex",0) // material.setParameter("baseColorMap",baseColor,sampler) // } void SceneAsset::updateEmbeddedAnimations() { auto now = high_resolution_clock::now(); for (auto &status : _embeddedAnimationStatus) { if (!status.play) { // Log("Skipping animation %d", status.animationIndex); continue; } duration dur = duration_cast>(now - status.startedAt); float animationTimeOffset = 0; bool finished = false; if (!status.started) { status.started = true; status.startedAt = now; } else if (dur.count() >= status.duration) { if (status.loop) { status.startedAt = now; } else { finished = true; } } else { animationTimeOffset = dur.count(); } // Log("time offset %f", animationTimeOffset); if (!finished) { _animator->applyAnimation(status.animationIndex, animationTimeOffset); } else { Log("Animation %d finished", status.animationIndex); status.play = false; status.started = false; } } _animator->updateBoneMatrices(); } unique_ptr> SceneAsset::getAnimationNames() { 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; } unique_ptr> SceneAsset::getTargetNames(const char *meshName) { if (!_asset) { Log("No asset, ignoring call."); return nullptr; } Log("Retrieving morph target names for mesh %s", meshName); unique_ptr> names = make_unique>(); const Entity *entities = _asset->getEntities(); RenderableManager &rm = _engine->getRenderableManager(); for (int i = 0; i < _asset->getEntityCount(); i++) { Entity e = entities[i]; auto inst = _ncm->getInstance(e); const char *name = _ncm->getName(inst); Log("Got entity instance name %s", name); if (strcmp(name, meshName) == 0) { size_t count = _asset->getMorphTargetCountAt(e); for (int j = 0; j < count; j++) { const char *morphName = _asset->getMorphTargetNameAt(e, j); names->push_back(morphName); } break; } } return names; } void SceneAsset::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); } const utils::Entity *SceneAsset::getCameraEntities() { return _asset->getCameraEntities(); } size_t SceneAsset::getCameraEntityCount() { return _asset->getCameraEntityCount(); } } // namespace polyvox