From 494d2bad439079b942028d86d279591ddf05a205 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Tue, 14 Feb 2023 16:11:21 +0800 Subject: [PATCH] more Linux plugin work, separate out MorphAnimation and require entity name --- example/linux/CMakeLists.txt | 2 +- ios/include/PolyvoxFilamentApi.h | 6 +- ios/include/SceneAsset.hpp | 6 +- ios/include/SceneAssetAnimation.hpp | 10 +++- ios/src/PolyvoxFilamentApi.cpp | 6 +- ios/src/SceneAsset.cpp | 49 ++++++++++----- ios/src/SceneAssetLoader.cpp | 14 ++++- lib/animations/animation_builder.dart | 9 ++- lib/animations/animations.dart | 86 ++++++++++++--------------- lib/filament_controller.dart | 9 +-- linux/CMakeLists.txt | 2 +- linux/polyvox_filament_plugin.cc | 79 +++++++++++++++++------- 12 files changed, 172 insertions(+), 106 deletions(-) diff --git a/example/linux/CMakeLists.txt b/example/linux/CMakeLists.txt index fbc9b02e..b0ff3c37 100644 --- a/example/linux/CMakeLists.txt +++ b/example/linux/CMakeLists.txt @@ -41,7 +41,7 @@ endif() # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-unused-function) target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() diff --git a/ios/include/PolyvoxFilamentApi.h b/ios/include/PolyvoxFilamentApi.h index 80cc80e9..32b51d22 100644 --- a/ios/include/PolyvoxFilamentApi.h +++ b/ios/include/PolyvoxFilamentApi.h @@ -8,9 +8,10 @@ typedef struct ResourceBuffer ResourceBuffer; /// -/// A wrapper for a single set of frame-data that may animate multiples bones/mesh nodes. +/// Frame data for animating multiples bones for multiple meshes. /// [data] /// + struct BoneAnimation { const char* const* const boneNames; const char* const* const meshNames; @@ -52,10 +53,11 @@ void grab_begin(void* viewer, float x, float y, bool pan); void grab_update(void* viewer, float x, float y); void grab_end(void* viewer); -void apply_weights(void* asset, float* const weights, int count); +void apply_weights(void* asset, const char* const entityName, float* const weights, int count); void set_animation( void* asset, + const char* const entityName, const float* const morphData, int numMorphWeights, const BoneAnimation* const boneAnimations, diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp index 9028fea6..3d4cb892 100644 --- a/ios/include/SceneAsset.hpp +++ b/ios/include/SceneAsset.hpp @@ -61,10 +61,10 @@ namespace polyvox { void playAnimation(int index, bool loop, bool reverse); /// - /// Manually set the weights for all morph targets in the assets to the provided values. + /// Set the weights for all [count] morph targets in this asset's entity named [inst] to [weights]. /// See [setAnimation] if you want to do the same across a number of frames (and extended to bone transforms). /// - void setMorphTargetWeights(float* weights, int count); + void setMorphTargetWeights(const char* const entityName, float* weights, int count); /// /// Animates the asset's morph targets/bone transforms according to the frame weights/transforms specified in [morphData]/[boneData]. @@ -74,6 +74,7 @@ namespace polyvox { /// [morphData] and [boneData] will both be copied, so remember to free these after calling this function. /// void setAnimation( + const char* entityName, const float* const morphData, int numMorphWeights, const BoneAnimation* const targets, @@ -82,7 +83,6 @@ namespace polyvox { float frameLengthInMs ); - void fillEntitiesByName(const char** name, int count, vector& out); size_t getBoneIndex(const char* name); Entity getNode(const char* name); diff --git a/ios/include/SceneAssetAnimation.hpp b/ios/include/SceneAssetAnimation.hpp index ff2d1826..901f06fc 100644 --- a/ios/include/SceneAssetAnimation.hpp +++ b/ios/include/SceneAssetAnimation.hpp @@ -2,10 +2,13 @@ #define SCENE_ASSET_ANIMATION_H_ #include "utils/Entity.h" +#include namespace polyvox { using namespace std; + + using Instance = utils::EntityInstance; typedef std::chrono::time_point time_point_t; @@ -73,21 +76,26 @@ namespace polyvox { // struct RuntimeAnimation { + Instance mInstance; + int frameNumber = -1; int mNumFrames = -1; float mFrameLengthInMs = 0; time_point_t startTime; + float* mMorphFrameData = nullptr; int mNumMorphWeights = 0; unique_ptr> mTargets; - RuntimeAnimation(const float* const morphData, + RuntimeAnimation(Instance instance, + const float* const morphData, int numMorphWeights, unique_ptr>& targets, int numFrames, float frameLengthInMs) : + mInstance(instance), mNumFrames(numFrames), mFrameLengthInMs(frameLengthInMs), mNumMorphWeights(numMorphWeights), diff --git a/ios/src/PolyvoxFilamentApi.cpp b/ios/src/PolyvoxFilamentApi.cpp index 314f3c6a..3a7c79d6 100644 --- a/ios/src/PolyvoxFilamentApi.cpp +++ b/ios/src/PolyvoxFilamentApi.cpp @@ -141,12 +141,13 @@ extern "C" { ((FilamentViewer*)viewer)->grabEnd(); } - void apply_weights(void* asset, float* const weights, int count) { - ((SceneAsset*)asset)->setMorphTargetWeights(weights, count); + void apply_weights(void* asset, const char* const entityName, float* const weights, int count) { + ((SceneAsset*)asset)->setMorphTargetWeights(entityName, weights, count); } void set_animation( void* asset, + const char* const entityName, const float* const morphData, int numMorphWeights, const BoneAnimation* const boneAnimations, @@ -154,6 +155,7 @@ extern "C" { int numFrames, float frameLengthInMs) { ((SceneAsset*)asset)->setAnimation( + entityName, morphData, numMorphWeights, boneAnimations, diff --git a/ios/src/SceneAsset.cpp b/ios/src/SceneAsset.cpp index 9e124a5b..6b7aeb54 100644 --- a/ios/src/SceneAsset.cpp +++ b/ios/src/SceneAsset.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -48,15 +49,12 @@ SceneAsset::~SceneAsset() { } } -void SceneAsset::setMorphTargetWeights(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::setMorphTargetWeights(const char* const entityName, float *weights, int count) { + // TODO } void SceneAsset::setAnimation( + const char* entityName, const float* const morphData, int numMorphWeights, const BoneAnimation* const boneAnimations, @@ -107,13 +105,31 @@ void SceneAsset::setAnimation( frameData )); } - _runtimeAnimationBuffer = std::make_unique( - morphData, - numMorphWeights, - transforms, - numFrames, - frameLengthInMs - ); + + RenderableManager &rm = _engine->getRenderableManager(); + Instance inst; + for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) { + auto entity = _asset->getEntities()[i]; + auto name = _ncm->getName(_ncm->getInstance(entity)); + + if(strcmp(entityName,name)==0) { + inst = rm.getInstance(_asset->getEntities()[i]); + } + } + + if(!inst) { + Log("Warning: failed to find Renderable instance for entity %s", entityName); + } else { + + _runtimeAnimationBuffer = std::make_unique( + inst, + morphData, + numMorphWeights, + transforms, + numFrames, + frameLengthInMs + ); + } } void SceneAsset::updateAnimations() { @@ -142,12 +158,15 @@ void SceneAsset::updateRuntimeAnimation() { return; } + RenderableManager &rm = _engine->getRenderableManager(); if (frameNumber > _runtimeAnimationBuffer->frameNumber) { _runtimeAnimationBuffer->frameNumber = frameNumber; if(_runtimeAnimationBuffer->mMorphFrameData) { auto morphFramePtrOffset = frameNumber * _runtimeAnimationBuffer->mNumMorphWeights; - setMorphTargetWeights(_runtimeAnimationBuffer->mMorphFrameData + morphFramePtrOffset, - _runtimeAnimationBuffer->mNumMorphWeights); + rm.setMorphWeights( + _runtimeAnimationBuffer->mInstance, + _runtimeAnimationBuffer->mMorphFrameData + morphFramePtrOffset, + _runtimeAnimationBuffer->mNumMorphWeights); } if(_runtimeAnimationBuffer->mTargets->size() > 0) { diff --git a/ios/src/SceneAssetLoader.cpp b/ios/src/SceneAssetLoader.cpp index c30f74b3..4c030a84 100644 --- a/ios/src/SceneAssetLoader.cpp +++ b/ios/src/SceneAssetLoader.cpp @@ -97,9 +97,6 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { _scene->addEntities(asset->getEntities(), entityCount); Log("Added %d entities to scene", entityCount); - - size_t lightEntityCount = asset->getLightEntityCount(); - Log("Found %d light entities in scene.", lightEntityCount ); _resourceLoader->loadResources(asset); @@ -115,6 +112,10 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { rm.setCulling(entityInstance, true); } + auto lights = asset->getLightEntities(); + _scene->addEntities(lights, asset->getLightEntityCount()); + + Log("Added %d lights to scene from asset", asset->getLightEntityCount()); FilamentInstance* inst = asset->getInstance(); inst->getAnimator()->updateBoneMatrices(); @@ -131,8 +132,15 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) { } void SceneAssetLoader::remove(SceneAsset *asset) { + + Log("Removing asset and all associated entities/lights."); + _scene->removeEntities(asset->_asset->getEntities(), asset->_asset->getEntityCount()); + + _scene->removeEntities(asset->getLightEntities(), + asset->getLightEntityCount()); + _resourceLoader->evictResourceData(); _assetLoader->destroyAsset(asset->_asset); delete asset; diff --git a/lib/animations/animation_builder.dart b/lib/animations/animation_builder.dart index 8a697230..cabb5158 100644 --- a/lib/animations/animation_builder.dart +++ b/lib/animations/animation_builder.dart @@ -15,7 +15,7 @@ class AnimationBuilder { List? _boneAnimations = null; - Animation build() { + Animation build(String meshName, List morphNames) { if (_numMorphWeights == 0 || _duration == 0 || _frameLengthInMs == 0) throw Exception(); @@ -36,8 +36,11 @@ class AnimationBuilder { } } - return Animation(morphData, _numMorphWeights, _boneAnimations, numFrames, - _frameLengthInMs); + var morphAnimation = + MorphAnimation(meshName, morphData, morphNames, _frameLengthInMs); + + return Animation( + morphAnimation: morphAnimation, boneAnimations: _boneAnimations); } AnimationBuilder setFramerate(int framerate) { diff --git a/lib/animations/animations.dart b/lib/animations/animations.dart index 47f70318..9b7351e5 100644 --- a/lib/animations/animations.dart +++ b/lib/animations/animations.dart @@ -2,29 +2,6 @@ import 'dart:typed_data'; import 'package:vector_math/vector_math.dart'; -// class Vec3 { -// final double x; -// final double y; -// final double z; - -// Vec3({this.x = 0, this.y = 0, this.z = 0}); - -// factory Vec3.from(List vals) => -// Vec3(x: vals[0], y: vals[1], z: vals[2]); -// } - -// class Quaternion { -// double x = 0; -// double y = 0; -// double z = 0; -// double w = 1; - -// Quaternion({this.x = 0, this.y = 0, this.z = 0, this.w = 1.0}); - -// factory Quaternion.from(List vals) => -// Quaternion(x: vals[0], y: vals[1], z: vals[2], w: vals[3]); -// } - class BoneAnimation { final List boneNames; final List meshNames; @@ -37,37 +14,33 @@ class BoneAnimation { } } -class Animation { - late final Float32List? morphData; - final int numMorphWeights; +// +// Frame weights for the morph targets specified in [morphNames] attached to mesh [meshName]. +// morphData is laid out as numFrames x numMorphTargets +// where the weights are in the same order as [morphNames]. +// [morphNames] must be provided but is not used directly; this is only used to check that the eventual asset being animated contains the same morph targets in the same order. +// +class MorphAnimation { + final String meshName; + final List morphNames; + + late final Float32List morphData; + + MorphAnimation( + this.meshName, this.morphData, this.morphNames, this.frameLengthInMs); + + int get numMorphWeights => morphNames.length; + + int get numFrames => morphData.length ~/ numMorphWeights; - final int numFrames; final double frameLengthInMs; +} +class Animation { + final MorphAnimation? morphAnimation; final List? boneAnimations; - Animation(this.morphData, this.numMorphWeights, this.boneAnimations, - this.numFrames, this.frameLengthInMs) { - if (morphData != null && morphData!.length != numFrames * numMorphWeights) { - throw Exception("Mismatched animation data with frame length"); - } - } - - Animation.from( - {required List> morphData, - required this.numMorphWeights, - this.boneAnimations, - required this.numFrames, - required this.frameLengthInMs}) { - if (morphData.length != numFrames) { - throw Exception("Mismatched animation data with frame length"); - } - this.morphData = Float32List(numMorphWeights * numFrames); - for (int i = 0; i < numFrames; i++) { - this.morphData!.setRange((i * numMorphWeights), - (i * numMorphWeights) + numMorphWeights, morphData[i]); - } - } + Animation({this.morphAnimation, this.boneAnimations}); } class BoneTransformFrameData { @@ -94,3 +67,18 @@ class BoneTransformFrameData { yield quaternions[frame].w; } } + +// Animation.from( +// {required this.meshName, +// required List> morphData, +// required this.numMorphWeights, +// this.boneAnimations, +// required this.numFrames, +// required this.frameLengthInMs}) { +// if (morphData.length != numFrames) { +// throw Exception("Mismatched animation data with frame length"); +// } +// } + +// not directly used, the list of morph targets animated by this [Animation], and may be a subset of the actual morph targets in the asset (and may also be ordered differently). +// // When passed to a [FilamentController], these will be re-mapped appropriately (and any morph targets not provided will be set to zero at each frame). \ No newline at end of file diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index d1c834c9..f57c53ba 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -298,11 +298,12 @@ class PolyvoxFilamentController extends FilamentController { Future setAnimation(FilamentAsset asset, Animation animation) async { await _channel.invokeMethod("setAnimation", [ asset, - animation.morphData!, - animation.numMorphWeights, + animation.morphAnimation!.meshName, + animation.morphAnimation!.morphData, + animation.morphAnimation!.numMorphWeights, animation.boneAnimations?.map((a) => a.toList()).toList() ?? [], - animation.numFrames, - animation.frameLengthInMs + animation.morphAnimation!.numFrames, + animation.morphAnimation!.frameLengthInMs ]); } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index f1ffa476..23f9e26f 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -8,7 +8,7 @@ set(PROJECT_NAME "polyvox_filament") project(${PROJECT_NAME}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fPIC -Wno-unused-variable -Wno-unused-function") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-variable") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-variable -Wno-unused-function") # This value is used when generating builds using this plugin, so it must # not be changed. diff --git a/linux/polyvox_filament_plugin.cc b/linux/polyvox_filament_plugin.cc index 5642d197..1b16e717 100644 --- a/linux/polyvox_filament_plugin.cc +++ b/linux/polyvox_filament_plugin.cc @@ -21,11 +21,12 @@ #include "include/polyvox_filament/resource_loader.hpp" #include "FilamentViewer.hpp" +#include "Log.hpp" + extern "C" { #include "PolyvoxFilamentApi.h" } - #include #include @@ -63,7 +64,7 @@ static gboolean on_frame_tick(GtkWidget* widget, GdkFrameClock* frame_clock, gpo static FlMethodResponse* _initialize(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { if(self->_viewer) { - std::cout << "Deleting existing viewer"; + Log("Deleting existing viewer"); filament_viewer_delete(self->_viewer); } @@ -113,6 +114,17 @@ static FlMethodResponse* _loadSkybox(PolyvoxFilamentPlugin* self, FlMethodCall* return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); } +static FlMethodResponse* _loadIbl(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { + FlValue* args = fl_method_call_get_args(method_call); + + const gchar* path = fl_value_get_string(args); + + load_ibl(self->_viewer, path); + + g_autoptr(FlValue) result = fl_value_new_string("OK"); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + static FlMethodResponse* _removeSkybox(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { std::cout << "Removing skybox" << std::endl; remove_skybox(self->_viewer); @@ -287,6 +299,16 @@ static FlMethodResponse* _set_position(PolyvoxFilamentPlugin* self, FlMethodCall // return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); // } +static FlMethodResponse* _set_camera(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { + FlValue* args = fl_method_call_get_args(method_call); + auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); + auto cameraName = fl_value_get_string(fl_value_get_list_value(args, 1)) ; + + set_camera(self->_viewer, (void*)assetPtr, cameraName); + g_autoptr(FlValue) result = fl_value_new_string("OK"); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + static FlMethodResponse* _set_camera_position(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto x = (float)fl_value_get_float(fl_value_get_list_value(args, 0)); @@ -363,10 +385,11 @@ static FlMethodResponse* _stop_animation(PolyvoxFilamentPlugin* self, FlMethodCa static FlMethodResponse* _apply_weights(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); - auto weightsValue = fl_value_get_list_value(args, 1); + auto entityName = fl_value_get_string(fl_value_get_list_value(args, 1)); + auto weightsValue = fl_value_get_list_value(args, 2); float* const weights = (float* const) fl_value_get_float32_list(weightsValue); size_t len = fl_value_get_length(weightsValue); - apply_weights(assetPtr, weights, (int)len); + apply_weights(assetPtr, entityName, weights, (int)len); g_autoptr(FlValue) result = fl_value_new_string("OK"); return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); } @@ -374,17 +397,18 @@ static FlMethodResponse* _apply_weights(PolyvoxFilamentPlugin* self, FlMethodCal static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) { FlValue* args = fl_method_call_get_args(method_call); auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0)); - - float* const morphData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 1)); - - int64_t numMorphWeights = fl_value_get_int(fl_value_get_list_value(args, 2)); - FlValue* flBoneAnimations = fl_value_get_list_value(args, 3); + const char* entityName = fl_value_get_string(fl_value_get_list_value(args, 1)); + + float* const morphData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 2)); + + int64_t numMorphWeights = fl_value_get_int(fl_value_get_list_value(args, 3)); + + FlValue* flBoneAnimations = fl_value_get_list_value(args, 4); size_t numBoneAnimations = fl_value_get_length(flBoneAnimations); vector boneAnimations; - boneAnimations.resize(numBoneAnimations); for(int i = 0; i < numBoneAnimations; i++) { @@ -394,12 +418,13 @@ static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCal FlValue* flMeshNames = fl_value_get_list_value(flBoneAnimation, 1); float* const frameData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(flBoneAnimation, 2)); + Log("Framedata %f", frameData); + vector boneNames; boneNames.resize(fl_value_get_length(flBoneNames)); for(int i=0; i < boneNames.size(); i++) { boneNames[i] = fl_value_get_string(fl_value_get_list_value(flBoneNames, i)) ; - std::cout << boneNames[i] << std::endl; } vector meshNames; @@ -407,28 +432,34 @@ static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCal for(int i=0; i < meshNames.size(); i++) { meshNames[i] = fl_value_get_string(fl_value_get_list_value(flMeshNames, i)); } + + const char** boneNamesPtr = (const char**)malloc(boneNames.size() * sizeof(char*)); + memcpy((void*)boneNamesPtr, (void*)boneNames.data(), boneNames.size() * sizeof(char*)); + auto meshNamesPtr = (const char**)malloc(meshNames.size() * sizeof(char*)); + memcpy((void*)meshNamesPtr, (void*)meshNames.data(), meshNames.size() * sizeof(char*)); - auto animation = BoneAnimation(); - animation.boneNames = (const char**)malloc(boneNames.size() * sizeof(char*)); - memcpy(animation.boneNames, boneNames.data(), boneNames.size() * sizeof(char*)); - animation.numBones = boneNames.size(); - animation.meshNames = (const char**)malloc(meshNames.size() * sizeof(char*)); - memcpy(animation.meshNames, meshNames.data(), meshNames.size() * sizeof(char*)); - animation.numMeshTargets = meshNames.size(); - animation.data = frameData; + BoneAnimation animation { + .boneNames = boneNamesPtr, + .meshNames = meshNamesPtr, + .data = frameData, + .numBones = boneNames.size(), + .numMeshTargets = meshNames.size() + }; + + boneAnimations.push_back(animation); - boneAnimations[i] = animation; } - int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 4)); + int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 5)); - float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 5)); + float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 6)); auto boneAnimationsPointer = boneAnimations.data(); auto boneAnimationsSize = boneAnimations.size(); set_animation( assetPtr, + entityName, morphData, numMorphWeights, boneAnimationsPointer, @@ -501,6 +532,8 @@ static void polyvox_filament_plugin_handle_method_call( response = _initialize(self, method_call); } else if(strcmp(method, "loadSkybox") == 0) { response = _loadSkybox(self, method_call); + } else if(strcmp(method, "loadIbl") == 0) { + response = _loadIbl(self, method_call); } else if(strcmp(method, "removeSkybox") == 0) { response = _removeSkybox(self, method_call); } else if(strcmp(method, "resize") == 0) { @@ -541,6 +574,8 @@ static void polyvox_filament_plugin_handle_method_call( response = _rotate_end(self, method_call); } else if(strcmp(method, "rotateUpdate") == 0) { response = _rotate_update(self, method_call); + } else if(strcmp(method, "setCamera") == 0) { + response = _set_camera(self, method_call); } else if(strcmp(method, "setCameraPosition") == 0) { response = _set_camera_position(self, method_call); } else if(strcmp(method, "setCameraRotation") == 0) {