add android integration & make iOS API consistent

add pubspec android plugin

update android CMakeLists

add filament android libs for linking
This commit is contained in:
Nick Fisher
2022-02-06 13:45:45 +08:00
parent 5c40b24b14
commit 9c0c73146b
38 changed files with 1046 additions and 6646 deletions

21
android/CMakeLists.txt Normal file
View File

@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.4.1)
include_directories(../ios/src)
include_directories(../ios/include)
include_directories(src/main/cpp)
link_directories(src/main/libs/${ANDROID_ABI}) # don't use jniLibs here because we just want to link against these libraries, the actual .so files will be copied by the AAR dependencies
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
add_library(
filament_interop
SHARED
src/main/cpp/filament_api.cpp
../ios/src/FilamentViewer.cpp
# ../ios/src/Utils.cpp
# ../ios/src/HDRLoader.cpp
# ../ios/include/common/NioUtils.cpp
#../ios/src/morph/GPUMorphHelper.cpp
)
target_link_libraries(filament_interop -landroid -llog -lfilament-jni -lfilament-utils-jni -lgltfio-jni )

View File

@@ -2,7 +2,7 @@ group 'app.polyvox.filament'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.6.0'
repositories {
google()
mavenCentral()
@@ -23,9 +23,14 @@ rootProject.allprojects {
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
compileSdkVersion 31
//ndkVersion '21.1.6352462'
ndkVersion '23.1.7779620'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -41,10 +46,23 @@ android {
}
defaultConfig {
minSdkVersion 16
minSdkVersion 21
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile 'net.java.dev.jna:jna:5.10.0@aar'
implementation "com.google.android.filament:filament-android:1.17.0"
implementation "com.google.android.filament:filament-utils-android:1.17.0"
implementation "com.google.android.filament:gltfio-android:1.17.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
}

View File

@@ -1 +1 @@
rootProject.name = 'filament'
rootProject.name = 'polyvox_filament'

View File

@@ -0,0 +1,146 @@
#include "FilamentViewer.hpp"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#include <android/native_activity.h>
using namespace polyvox;
static AAssetManager* am;
std::vector<AAsset*> _assets;
uint64_t id = -1;
static polyvox::ResourceBuffer loadResource(const char* name) {
id++;
AAsset *asset = AAssetManager_open(am, name, AASSET_MODE_BUFFER);
if(asset == nullptr) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Couldn't locate asset [ %s ]", name);
return polyvox::ResourceBuffer(nullptr, 0, 0);
}
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Loading asset [ %s ]", name);
off_t length = AAsset_getLength(asset);
const void * buffer = AAsset_getBuffer(asset);
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Read [ %lu ] bytes into buffer", length);
_assets.push_back(asset);
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Loaded asset [ %s ] of length %zu", name, length);
return ResourceBuffer(buffer, length, id);
}
static void freeResource(ResourceBuffer rb) {
AAsset_close(_assets.at(rb.id));
}
extern "C" {
void load_skybox(void* viewer, const char* skyboxPath, const char* iblPath) {
((FilamentViewer*)viewer)->loadSkybox(skyboxPath, iblPath, am);
}
void load_glb(void* viewer, const char* assetPath) {
((FilamentViewer*)viewer)->loadGlb(assetPath);
}
void load_gltf(void* viewer, const char* assetPath, const char* relativePath) {
((FilamentViewer*)viewer)->loadGltf(assetPath, relativePath);
}
void set_camera(void* viewer, const char* nodeName) {
((FilamentViewer*)viewer)->setCamera(nodeName);
}
void* filament_viewer_new(
jobject surface,
const char* opaqueShaderPath,
const char* fadeShaderPath,
JNIEnv* env,
jobject assetManager
) {
ANativeWindow* layer = ANativeWindow_fromSurface(env, surface);
am = AAssetManager_fromJava(env, assetManager);
return new FilamentViewer((void*)layer, opaqueShaderPath, fadeShaderPath, loadResource, freeResource);
}
void render(
void* viewer
) {
((FilamentViewer*)viewer)->render();
}
void destroy_swap_chain(void* viewer) {
((FilamentViewer*)viewer)->destroySwapChain();
}
void create_swap_chain(void* viewer, jobject surface, JNIEnv* env) {
ANativeWindow* layer = ANativeWindow_fromSurface(env, surface);
if(!layer) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Couldn't get native window from surface");
return;
}
((FilamentViewer*)viewer)->createSwapChain(layer);
}
void* get_renderer(void* viewer) {
return ((FilamentViewer*)viewer)->getRenderer();
}
void update_viewport_and_camera_projection(void* viewer, int width, int height, float scaleFactor) {
return ((FilamentViewer*)viewer)->updateViewportAndCameraProjection(width, height, scaleFactor);
}
void scroll(void* viewer, float x, float y , float z) {
return ((FilamentViewer*)viewer)->manipulator->scroll(x, y, z);
}
void grab_begin(void* viewer, int x, int y, bool pan) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Grab begin at %d %d %d", x, y, pan);
((FilamentViewer*)viewer)->manipulator->grabBegin(x, y, pan);
}
void grab_update(void* viewer, int x, int y) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Grab update at %d %d %d", x, y);
((FilamentViewer*)viewer)->manipulator->grabUpdate(x, y);
}
void grab_end(void* viewer) {
((FilamentViewer*)viewer)->manipulator->grabEnd();
}
void apply_weights(void* viewer, float* weights, int count) {
((FilamentViewer*)viewer)->applyWeights(weights, count);
}
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 free_pointer(void** ptr, int size) {
for(int i = 0; i < size; i++) {
free(ptr[i]);
}
}
void release_source_assets(void* viewer) {
((FilamentViewer*)viewer)->releaseSourceAssets();
}
}

View File

@@ -0,0 +1,15 @@
#include "FilamentViewer.hpp"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/log.h>
void load_skybox(void* viewer, const char* skyboxPath, const char* iblPath);
void* filament_viewer_new(
void* layer,
const char* opaqueShaderPath,
const char* fadeShaderPath,
void* assetManager
);
}

View File

@@ -0,0 +1,61 @@
package app.polyvox.filament
import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.Pointer
import com.sun.jna.ptr.PointerByReference
import com.sun.jna.ptr.IntByReference
import com.sun.jna.Structure
import com.sun.jna.NativeLibrary
import com.sun.jna.StringArray
import com.sun.jna.JNIEnv
import android.view.Surface
import android.content.res.AssetManager
import java.nio.ByteBuffer
interface FilamentInterop : Library {
fun filament_viewer_new(
layer:Object,
opaqueShaderPath:String,
fadeShaderPath:String,
env:JNIEnv,
am:AssetManager
) : Pointer;
fun load_skybox(viewer:Pointer, skyboxPath:String, iblPath:String) : Pointer;
fun load_glb(viewer:Pointer, uri:String) : Pointer;
fun load_gltf(viewer:Pointer, uri:String, relativeResourcePath:String) : Pointer;
fun set_camera(viewer:Pointer, nodeName:String) : Pointer;
fun render(viewer:Pointer);
fun create_swap_chain(viewer:Pointer, surface:Surface, env:JNIEnv);
fun destroy_swap_chain(viewer:Pointer);
fun update_viewport_and_camera_projection(viewer:Pointer, width:Int, height:Int, scaleFactor:Float);
fun scroll(viewer:Pointer, x:Float, y:Float, z:Float);
fun grab_begin(viewer:Pointer, x:Int, y:Int, pan:Boolean)
fun grab_update(viewer:Pointer, x:Int, y:Int)
fun grab_end(viewer:Pointer)
fun apply_weights(viewer:Pointer, weights:FloatArray, size:Int);
fun get_target_names(viewer:Pointer, meshName:String, outPtr:PointerByReference, outLen:IntByReference);
fun free_pointer(ptr:Pointer, size:Int)
fun release_source_assets(viewer:Pointer)
}

View File

@@ -0,0 +1,298 @@
package app.polyvox.filament
import android.content.res.AssetManager
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.SurfaceTexture
import android.graphics.PixelFormat
import io.flutter.FlutterInjector
import android.opengl.GLU
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import android.hardware.Camera
import android.opengl.GLSurfaceView
import android.view.SurfaceView
import android.view.TextureView
import android.view.View
import android.view.Surface
import android.widget.TextView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.DefaultLifecycleObserver
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView
import java.io.IOException
import android.util.Log
import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.Pointer
import com.sun.jna.ptr.PointerByReference
import com.sun.jna.ptr.IntByReference
import com.sun.jna.Structure
import com.sun.jna.NativeLibrary
import com.sun.jna.StringArray
import com.sun.jna.JNIEnv
import android.R.attr.path
import java.util.Collections;
import com.google.android.filament.android.DisplayHelper
import android.hardware.display.DisplayManager
import com.google.android.filament.android.*
import com.google.android.filament.*
import com.google.android.filament.SwapChain
import com.google.android.filament.utils.*
import android.view.Choreographer
import android.view.SurfaceHolder
class FilamentView(
private val viewId: Int,
private val context: Context,
private val activity: Activity,
private val binaryMessenger: BinaryMessenger,
private val creationParams : Map<String?, Any?>?
) : DefaultLifecycleObserver,
MethodChannel.MethodCallHandler,
PlatformView {
companion object {
const val TAG = "FilamentView"
}
private val _view = SurfaceView(context)
override fun getView(): View {
return _view
}
private val _methodChannel: MethodChannel
private lateinit var _lib : FilamentInterop
private var _viewer : Pointer? = null
private lateinit var choreographer: Choreographer
private lateinit var displayHelper : DisplayHelper
private val frameScheduler = FrameCallback()
private lateinit var uiHelper : UiHelper
private lateinit var assetManager : AssetManager
init {
MethodChannel(binaryMessenger, PolyvoxFilamentPlugin.VIEW_TYPE + '_' + viewId).also {
_methodChannel = it
it.setMethodCallHandler(this)
}
_lib = Native.loadLibrary("filament_interop", FilamentInterop::class.java, Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, true))
choreographer = Choreographer.getInstance()
_view.setZOrderOnTop(false)
_view.holder.setFormat(PixelFormat.OPAQUE)
_view.holder.addCallback (object : SurfaceHolder.Callback {
override fun surfaceChanged(holder:SurfaceHolder, format:Int, width:Int, height:Int) {
_lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f);
}
override fun surfaceCreated(holder:SurfaceHolder) {
_lib.destroy_swap_chain(_viewer!!)
_lib.create_swap_chain(_viewer!!, _view.holder.surface, JNIEnv.CURRENT)
}
override fun surfaceDestroyed(holder:SurfaceHolder) {
_lib.destroy_swap_chain(_viewer!!)
}
})
assetManager = context.assets
_viewer = _lib.filament_viewer_new(
_view.holder.surface as Object,
"unused",
"unused",
JNIEnv.CURRENT,
assetManager)
choreographer.postFrameCallback(frameScheduler)
val mDisplayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
activity.window.setFormat(PixelFormat.RGBA_8888)
uiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK)
uiHelper.renderCallback = SurfaceCallback()
uiHelper.attachTo(_view)
}
override fun onFlutterViewAttached(flutterView:View) {
}
override fun dispose() {
_methodChannel.setMethodCallHandler(null)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"loadSkybox" -> {
val args = call.arguments as ArrayList<Any?>
val loader = FlutterInjector.instance().flutterLoader()
_lib.load_skybox(_viewer!!, loader.getLookupKeyForAsset(args[0] as String), loader.getLookupKeyForAsset(args[1] as String))
result.success("OK");
}
"loadGlb" -> {
if (_viewer == null)
return;
val loader = FlutterInjector.instance().flutterLoader()
_lib.load_glb(
_viewer!!,
loader.getLookupKeyForAsset(call.arguments as String)
)
result.success("OK");
}
"loadGltf" -> {
if (_viewer == null)
return;
val args = call.arguments as ArrayList<Any?>
val loader = FlutterInjector.instance().flutterLoader()
_lib.load_gltf(
_viewer!!,
loader.getLookupKeyForAsset(args[0] as String),
loader.getLookupKeyForAsset(args[1] as String)
)
result.success("OK");
}
"setCamera" -> {
if (_viewer == null)
return;
_lib.set_camera(
_viewer!!,
call.arguments as String
)
result.success("OK");
}
"zoom" -> {
if(_viewer == null)
return;
_lib.scroll(_viewer!!, 0.0f, 0.0f, (call.arguments as Double).toFloat())
result.success("OK");
}
"getTargetNames" -> {
if(_viewer == null)
return;
val arrPtr = PointerByReference();
val countPtr = IntByReference();
_lib.get_target_names(_viewer!!, call.arguments as String, arrPtr, countPtr)
val names = arrPtr.value.getStringArray(0, countPtr.value);
_lib.free_pointer(arrPtr.value, countPtr.getValue())
val namesAsList = names.toCollection(ArrayList())
result.success(namesAsList)
}
"applyWeights" -> {
if(_viewer == null)
return;
val weights = call.arguments as ArrayList<Float>;
_lib.apply_weights(_viewer!!, weights.toFloatArray(), weights.size)
result.success("OK");
}
"panStart" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true)
result.success("OK");
}
"panUpdate" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
"panEnd" -> {
_lib.grab_end(_viewer!!)
result.success("OK");
}
"rotateStart" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, false)
result.success("OK");
}
"rotateUpdate" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
"rotateEnd" -> {
_lib.grab_end(_viewer!!)
result.success("OK");
}
"grabStart" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true)
result.success("OK");
}
"grabUpdate" -> {
val args = call.arguments as ArrayList<Any?>
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
"grabEnd" -> {
_lib.grab_end(_viewer!!)
result.success("OK");
}
"releaseSourceAssets" -> {
_lib.release_source_assets(_viewer!!)
result.success("OK");
}
}
}
inner class SurfaceCallback : UiHelper.RendererCallback {
override fun onNativeWindowChanged(surface: Surface) {
_lib.destroy_swap_chain(_viewer!!)
_lib.create_swap_chain(_viewer!!, surface, JNIEnv.CURRENT)
}
override fun onDetachedFromSurface() {
_lib.destroy_swap_chain(_viewer!!)
}
override fun onResized(width: Int, height: Int) {
_lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f)
}
}
inner class FrameCallback : Choreographer.FrameCallback {
private val startTime = System.nanoTime()
override fun doFrame(frameTimeNanos: Long) {
choreographer.postFrameCallback(this)
// modelViewer.animator?.apply {
// if (animationCount > 0) {
// val elapsedTimeSeconds = (frameTimeNanos - startTime).toDouble() / 1_000_000_000
// applyAnimation(0, elapsedTimeSeconds.toFloat())
// }
// updateBoneMatrices()
// }
_lib.render(_viewer!!)
}
}
}

View File

@@ -0,0 +1,20 @@
package app.polyvox.filament
import io.flutter.plugin.common.BinaryMessenger
import android.app.Activity
import android.content.Context
import android.view.View
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
class FilamentViewFactory(
private val activity: Activity,
private val binaryMessenger: BinaryMessenger
) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return FilamentView(viewId, context, activity, binaryMessenger, creationParams)
}
}

View File

@@ -2,26 +2,53 @@ package app.polyvox.filament
import androidx.annotation.NonNull
import androidx.lifecycle.Lifecycle
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference
/** PolyvoxFilamentPlugin */
class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler {
class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
companion object {
const val VIEW_TYPE = "app.polyvox.filament/filament_view"
}
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
/// Keep a referene to the plugin binding so we can defer construction of a FilamentViewFactory
/// until Activity is attached.
private lateinit var flutterPluginBinding : FlutterPlugin.FlutterPluginBinding
private var lifecycle: Lifecycle? = null
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "polyvox_filament")
this.flutterPluginBinding = flutterPluginBinding
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "app.polyvox.filament")
channel.setMethodCallHandler(this)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
lifecycle = (binding.lifecycle as? HiddenLifecycleReference)?.lifecycle
flutterPluginBinding
.platformViewRegistry
.registerViewFactory(VIEW_TYPE, FilamentViewFactory(binding.activity, flutterPluginBinding.binaryMessenger))
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getPlatformVersion") {
result.success("Android ${android.os.Build.VERSION.RELEASE}")
} else {
@@ -32,4 +59,17 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler {
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
onAttachedToActivity(binding)
}
override fun onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity()
}
override fun onDetachedFromActivity() {
lifecycle = null
}
}

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8f24f2cb744814f1502a1a29164ca9d08c7f844a83e9d077f3831a1fd13c67a
size 1723112

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8cbdbc57e41114b428fbd6e417a4cafbffd83be8994ea0da44b2cdad6abc4e4f
size 430944

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1d2c3b8bf5dae7441fc7d16a345fd7a3fd170e0bcd0f0f054b16ba4e64a289d0
size 2152000

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fa2185681699dc2f72ed79bf0f3b227c8a936047e1d0f35edf2854e2dbb0319d
size 8758184

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:16fbe91a5f417dab44046090e918e3f3fb119cc7aa7ce72e68b1692687915c90
size 1378344

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8cf27e32b857a98c8b8a0862ec55d8b4eb06d2f22d6d7502865f8ed5dd21db78
size 344268

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:30734d9a58740c04ee282843c2a0db455d4daa239a5d15bf2f5d8c3ef04f21c8
size 2346424

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b1498fff038d1bcdb7e52d4369b61e71ea33154ebf769934dbcadafb0bbb814b
size 8463116

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:134ff007e621892b60c01be75173b94fd02be5b94f6818f76c0e639d85003446
size 1880488

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a1699bf6ab28d55e49d0a8d4d7ace8043b9477036ae8760f14c4c14deeba94d6
size 461552

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bc2e220862a8179129fbfd5fe944e725eec57335c7014bea7ba538d62f6d93de
size 2327272

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8a82bd46c8f0e3ed5970e873c92f219cdbed2d02d75855ffb889ac3821cf53c8
size 8846488

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e227eefd03b2ef8b79366fc443efe11ec87768c284f33dcfdc8906e3985fc7a6
size 1840928

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:43fa88beba41cce0ffa2f25418cee021946818882b91ad6da63194e19b34fca6
size 469208

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f5c0abca686c763b814af96ada136cb872b9d776ebad063b8293bb20488c4a13
size 2141136

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39eaf4b8d74194db66401e754527fe3d01a457f829de559ef2503e76b8ffd9e6
size 8859584

View File

@@ -23,10 +23,12 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 30
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -43,8 +45,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "app.polyvox.polyvox_filament_example"
minSdkVersion 16
applicationId "app.polyvox.filament_example"
minSdkVersion 21
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
@@ -57,6 +59,14 @@ android {
signingConfig signingConfigs.debug
}
}
packagingOptions {
merge "**/libfilament-jni.so"
merge "**/libgltfio-jni.so"
merge "**/libfilament-utils-jni.so"
}
aaptOptions {
noCompress "ktx"
}
}
flutter {
@@ -64,5 +74,13 @@ flutter {
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.google.android.filament:filament-android:1.17.0"
implementation "com.google.android.filament:filament-utils-android:1.17.0"
implementation "com.google.android.filament:gltfio-android:1.17.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
implementation "androidx.annotation:annotation:1.3.0"
implementation "androidx.core:core:1.7.0"
}

View File

@@ -1,8 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.polyvox.polyvox_filament_example">
package="app.polyvox.filament_example">
<application
android:name="${applicationName}"
android:label="polyvox_filament_example"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
>
<activity
android:name=".MainActivity"
android:launchMode="singleTop"

View File

@@ -8,8 +8,8 @@ static polyvox::ResourceBuffer loadResourceGlobal(const char* name) {
return [_handler loadResource:name];
}
static void* freeResourceGlobal(void* mem, size_t size, void* misc) {
[_handler freeResource:mem size:size misc:misc ];
static void* freeResourceGlobal(ResourceBuffer rb) {
[_handler freeResource:rb ];
return nullptr;
}
@@ -37,19 +37,16 @@ static void* freeResourceGlobal(void* mem, size_t size, void* misc) {
[self handleMethodCall:call result:result];
}];
_handler = self;
_viewer = new polyvox::FilamentViewer(_layer, nullptr, nullptr, loadResourceGlobal, freeResourceGlobal);
[_controller setViewer:_viewer];
[_controller startDisplayLink];
return self;
}
- (void)handleMethodCall:(FlutterMethodCall* _Nonnull)call result:(FlutterResult _Nonnull )result {
if([@"initialize" isEqualToString:call.method]) {
if(!call.arguments)
_viewer = new polyvox::FilamentViewer(_layer, nullptr, nullptr, loadResourceGlobal, freeResourceGlobal);
else
_viewer = new polyvox::FilamentViewer(_layer, [call.arguments[0] UTF8String], [call.arguments[1] UTF8String], loadResourceGlobal, freeResourceGlobal);
[_controller setViewer:_viewer];
[_controller startDisplayLink];
result(@"OK");
} else if([@"loadSkybox" isEqualToString:call.method]) {
if([@"loadSkybox" isEqualToString:call.method]) {
if(!_viewer)
return;
@@ -65,6 +62,11 @@ static void* freeResourceGlobal(void* mem, size_t size, void* misc) {
return; // TODO should throw exception here
_viewer->loadGltf([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]);
result(@"OK");
} else if([@"setCamera" isEqualToString:call.method]) {
if(!_viewer)
return; // TODO should throw exception here
_viewer->setCamera([call.arguments UTF8String]);
result(@"OK");
} else if([@"panStart" isEqualToString:call.method]) {
if(!_viewer)
return;
@@ -169,8 +171,8 @@ static void* freeResourceGlobal(void* mem, size_t size, void* misc) {
return rbuf;
}
- (void)freeResource:(void*)mem size:(size_t)s misc:(void *)m {
free(mem);
- (void)freeResource:(ResourceBuffer)rb {
free(rb.data);
}
- (void)ready {

View File

@@ -3,7 +3,7 @@ import UIKit
public class SwiftPolyvoxFilamentPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "polyvox_filament", binaryMessenger: registrar.messenger())
let channel = FlutterMethodChannel(name: "app.polyvox.filament", binaryMessenger: registrar.messenger())
let instance = SwiftPolyvoxFilamentPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,9 @@
#include <utils/JobSystem.h>
#include "math.h"
#include "upcast.h"
#include "FFilamentInstance.h"
#include "FFilamentAsset.h"
#include <math/mat4.h>
#include <math/quat.h>
@@ -57,13 +59,21 @@
#include <chrono>
#include <iostream>
#include "Log.h"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#include <android/native_activity.h>
using namespace filament;
using namespace filament::math;
using namespace gltfio;
using namespace utils;
using namespace std::chrono;
namespace foo {
namespace gltfio {
MaterialProvider* createUbershaderLoader(filament::Engine* engine);
}
@@ -127,11 +137,16 @@ FilamentViewer::FilamentViewer(
FreeResource freeResource) : _layer(layer),
_loadResource(loadResource),
_freeResource(freeResource),
opaqueShaderResources(nullptr, 0),
fadeShaderResources(nullptr, 0) {
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,
.presentationDeadlineNanos = (uint64_t)0,
.vsyncOffsetNanos = (uint64_t)0 });
_scene = _engine->createScene();
Entity camera = EntityManager::get().create();
_mainCamera = _engine->createCamera(camera);
@@ -144,18 +159,22 @@ FilamentViewer::FilamentViewer(
_swapChain = _engine->createSwapChain(_layer);
// if(shaderPath) {
opaqueShaderResources = _loadResource(opaqueShaderPath);
fadeShaderResources = _loadResource(fadeShaderPath);
_materialProvider = createGPUMorphShaderLoader(
opaqueShaderResources.data,
opaqueShaderResources.size,
fadeShaderResources.data,
fadeShaderResources.size,
_engine);
// } else {
// _materialProvider = foo::createUbershaderLoader(_engine);
// }
View::DynamicResolutionOptions options;
options.enabled = true;
// options.homogeneousScaling = homogeneousScaling;
// options.minScale = filament::math::float2{ minScale };
// options.maxScale = filament::math::float2{ maxScale };
//options.sharpness = sharpness;
options.quality = View::QualityLevel::MEDIUM;;
_view->setDynamicResolutionOptions(options);
View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions;
multiSampleAntiAliasingOptions.enabled = true;
_view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions);
_materialProvider = gltfio::createUbershaderLoader(_engine);
EntityManager& em = EntityManager::get();
_ncm = new NameComponentManager(em);
_assetLoader = AssetLoader::create({_engine, _materialProvider, _ncm, &em});
@@ -163,7 +182,7 @@ FilamentViewer::FilamentViewer(
{.engine = _engine, .normalizeSkinningWeights = true, .recomputeBoundingBoxes = false});
manipulator =
Manipulator<float>::Builder().orbitHomePosition(0.0f, -1.4f, 1.0f).targetPosition(0.0f, -0.5f, 0.75f).build(Mode::ORBIT);
Manipulator<float>::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, -4.0f).build(Mode::ORBIT);
_asset = nullptr;
}
@@ -172,21 +191,54 @@ FilamentViewer::~FilamentViewer() {
}
void printWeights(float* weights, int numWeights) {
for(int i =0; i < numWeights; i++) {
// std::cout << weights[i];
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<void(void*, unsigned int, void *)>;
// auto cb = [&] (void * ptr, unsigned int len, void * misc) {
// };
// FunctionCallback fcb = cb;
ResourceLoader::BufferDescriptor b(
buf.data, buf.size, (ResourceLoader::BufferDescriptor::Callback)&_freeResource, nullptr);
buf.data, buf.size);
_resourceLoader->addResourceData(resourceUris[i], std::move(b));
_freeResource(buf);
}
_resourceLoader->loadResources(_asset);
@@ -204,26 +256,22 @@ void FilamentViewer::loadResources(string relativeResourcePath) {
};
void FilamentViewer::releaseSourceAssets() {
std::cout << "Releasing source data" << std::endl;
Log("Releasing source data");
_asset->releaseSourceData();
_freeResource((void*)opaqueShaderResources.data, opaqueShaderResources.size, nullptr);
_freeResource((void*)fadeShaderResources.data, fadeShaderResources.size, nullptr);
// _freeResource(opaqueShaderResources);
// _freeResource(fadeShaderResources);
}
void FilamentViewer::animateWeights(float* data, int numWeights, int length, float frameRate) {
// transformToUnitCube();
morphAnimationBuffer = std::make_unique<MorphAnimationBuffer>(data, numWeights, length / numWeights, 1000 / frameRate );
}
void FilamentViewer::loadGlb(const char* const uri) {
std::cerr << "Loading GLB at URI " << uri << std::endl;
Log("Loading GLB at URI %s", uri);
if(_asset) {
_resourceLoader->evictResourceData();
_scene->removeEntities(_asset->getEntities(), _asset->getEntityCount());
_assetLoader->destroyAsset(_asset);
_freeResource(_assetBuffer);
}
_asset = nullptr;
_animator = nullptr;
@@ -234,7 +282,7 @@ void FilamentViewer::loadGlb(const char* const uri) {
(const uint8_t*)rbuf.data, rbuf.size);
if (!_asset) {
std::cerr << "Unknown error loading GLB asset." << std::endl;
Log("Unknown error loading GLB asset.");
exit(1);
}
@@ -242,7 +290,7 @@ void FilamentViewer::loadGlb(const char* const uri) {
_scene->addEntities(_asset->getEntities(), entityCount);
std::cerr << "Added " << entityCount << " entities to scene" << std::endl;
Log("Added %d entities to scene", entityCount);
_resourceLoader->loadResources(_asset);
_animator = _asset->getAnimator();
@@ -254,56 +302,58 @@ void FilamentViewer::loadGlb(const char* const uri) {
rm.setCulling(inst, false);
}
_freeResource((void*)rbuf.data, rbuf.size, nullptr);
// transformToUnitCube();
setCamera("Camera.001"); // TODO - expose this for external invocation
std::cerr << "Successfully loaded GLB." << std::endl;
_freeResource(rbuf);
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);
}
_asset = nullptr;
_animator = nullptr;
ResourceBuffer rbuf = _loadResource(uri);
_assetBuffer = _loadResource(uri);
// Parse the glTF file and create Filament entities.
_asset = _assetLoader->createAssetFromJson((uint8_t*)rbuf.data, rbuf.size);
Log("Creating asset from JSON");
_asset = _assetLoader->createAssetFromJson((uint8_t*)_assetBuffer.data, _assetBuffer.size);
Log("Created asset from JSON");
if (!_asset) {
std::cerr << "Unable to parse asset" << std::endl;
Log("Unable to parse asset");
exit(1);
}
Log("Loading relative resources");
loadResources(string(relativeResourcePath) + string("/"));
Log("Loaded relative resources");
// _asset->releaseSourceData();
_freeResource((void*)rbuf.data, rbuf.size, nullptr);
Log("Load complete for GLTF at URI %s", uri);
transformToUnitCube();
// transformToUnitCube();
setCamera("Camera.001"); // TODO - expose this for external invocation
}
void FilamentViewer::setCamera(const char* cameraName) {
FFilamentAsset* asset = (FFilamentAsset*)_asset;
NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap
gltfio::NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap
: asset->mNodeMap;
for (auto pair : sourceNodes) {
cgltf_node const *node = pair.first;
if(node->camera) {
std::cout << "Got camera " << node->camera->name << " of type " << node->camera->type << std::endl;
Log("Got camera %s of type %s ", node->camera->name, node->camera->type);
if(strcmp(cameraName, node->camera->name) == 0) {
filament::math::mat4 mat(
@@ -342,84 +392,48 @@ void FilamentViewer::setCamera(const char* cameraName) {
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);
NodeMap &sourceNodes = asset->isInstanced() ? asset->mInstances[0]->nodeMap
: asset->mNodeMap;
FilamentInstance** instances = asset->getAssetInstances();
std::cout << "Fetching morph target names for mesh " << meshName;
for (auto pair : sourceNodes) {
cgltf_node const *node = pair.first;
cgltf_mesh const *mesh = node->mesh;
if(node->camera) {
std::cout << "Got camera " << node->camera->name << " of type " << node->camera->type << std::endl;
Log("Got camera %s of type %s", node->camera->name, node->camera->type);
}
if (mesh) {
std::cout << "Mesh : " << mesh->name;
Log("Mesh : %s ",mesh->name);
if(strcmp(meshName, mesh->name) == 0) {
return StringList((const char**)mesh->target_names, (int) mesh->target_names_count);
}
} else {
std::cout << "No mesh attached to node";
Log("No mesh attached to node");
}
}
return StringList(nullptr, 0);
}
void FilamentViewer::createMorpher(const char* meshName, int* primitives, int numPrimitives) {
morphHelper = new gltfio::GPUMorphHelper((FFilamentAsset*)_asset, meshName, primitives, numPrimitives);
// morphHelper = new gltfio::CPUMorpher(((FFilamentAsset)*_asset, (FFilamentInstance*)_asset));
}
void FilamentViewer::applyWeights(float* weights, int count) {
morphHelper->applyWeights(weights, count);
}
void FilamentViewer::animateBones() {
Entity entity = _asset->getFirstEntityByName("CC_Base_JawRoot");
if(!entity) {
return;
}
TransformManager& transformManager = _engine->getTransformManager();
TransformManager::Instance node = transformManager.getInstance( entity);
mat4f xform = transformManager.getTransform(node);
float3 scale;
quatf rotation;
float3 translation;
decomposeMatrix(xform, &translation, &rotation, &scale);
// const quatf srcQuat { weights[0] * 0.9238,0,weights[0] * 0.3826, 0 };
// float3 { scale[0] * (1.0f - weights[0]), scale[1] * (1.0f - weights[1]), scale[2] * (1.0f - weights[2]) }
// xform = composeMatrix(translation + float3 { weights[0], weights[1], weights[2] }, rotation, scale );
transformManager.setTransform(node, xform);
}
void FilamentViewer::playAnimation(int index) {
embeddedAnimationBuffer = make_unique<EmbeddedAnimationBuffer>(index, _animator->getAnimationDuration(index));
}
void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath) {
void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath, AAssetManager* am) {
std::cout << "Loading skybox from " << skyboxPath << std::endl;
ResourceBuffer skyboxBuffer = _loadResource(skyboxPath);
std::cout << "Loaded skybox resource buffer of size " << skyboxBuffer.size << std::endl;
image::KtxBundle* skyboxBundle =
new image::KtxBundle(static_cast<const uint8_t*>(skyboxBuffer.data),
static_cast<uint32_t>(skyboxBuffer.size));
_skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, true);
new image::KtxBundle(static_cast<const uint8_t*>(skyboxBuffer.data), static_cast<uint32_t>(skyboxBuffer.size));
_skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false);
_skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
// _skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*_engine);
_scene->setSkybox(_skybox);
_freeResource((void*)skyboxBuffer.data, skyboxBuffer.size, nullptr);
std::cout << "Loading IBL from " << iblPath << std::endl;
_freeResource(skyboxBuffer);
Log("Loading IBL from %s", iblPath);
// Load IBL.
ResourceBuffer iblBuffer = _loadResource(iblPath);
@@ -436,7 +450,7 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const
.build(*_engine);
_scene->setIndirectLight(_indirectLight);
_freeResource((void*)iblBuffer.data, iblBuffer.size, nullptr);
_freeResource(iblBuffer);
// Always add a direct light source since it is required for shadowing.
_sun = EntityManager::get().create();
@@ -447,10 +461,14 @@ void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const
.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();
@@ -468,36 +486,47 @@ void FilamentViewer::cleanup() {
_assetLoader->destroyAsset(_asset);
_materialProvider->destroyMaterials();
AssetLoader::destroy(&_assetLoader);
_freeResource(_assetBuffer);
};
void FilamentViewer::render() {
if (!_view || !_mainCamera || !manipulator || !_animator) {
if (!_view || !_mainCamera || !_swapChain) {
Log("Not ready for rendering");
return;
}
// Extract the camera basis from the helper and push it to the Filament camera.
//math::float3 eye, target, upward;
//manipulator->getLookAt(&eye, &target, &upward);
//_mainCamera->lookAt(eye, target, upward);
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();
} else {
// std::cout << "Skipping frame" << std::endl;
}
}
}
//void FilamentViewer::updateAnimation(AnimationBuffer animation, std::function<void(int)> moo) {
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;
const uint32_t _height = height * contentScaleFactor;
_view->setViewport({0, 0, _width, _height});
const double aspect = (double)width / height;
_mainCamera->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane);
Log("Set viewport to %d %d", _width, _height);
}
}
//void FilamentViewer::updateAnimation(AnimationBuffer animation, std::function<void(int)> moo) {
// if(morphAnimationBuffer.frameIndex >= animation.numFrames) {
// this.animation = null;
// return;
@@ -518,80 +547,115 @@ void FilamentViewer::render() {
// }
//}
void FilamentViewer::updateMorphAnimation() {
// void FilamentViewer::updateMorphAnimation() {
if(morphAnimationBuffer->frameIndex >= morphAnimationBuffer->numFrames) {
morphAnimationBuffer = nullptr;
return;
}
// 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<double, std::milli> 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);
}
}
// if(morphAnimationBuffer->frameIndex == -1) {
// morphAnimationBuffer->frameIndex++;
// morphAnimationBuffer->startTime = std::chrono::high_resolution_clock::now();
// applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights);
// } else {
// std::chrono::duration<double, std::milli> 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::updateEmbeddedAnimation() {
duration<double> dur = duration_cast<duration<double>>(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();
}
// void FilamentViewer::updateEmbeddedAnimation() {
// duration<double> dur = duration_cast<duration<double>>(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();
// _animator->applyAnimation(embeddedAnimationBuffer->animationIndex, startTime);
// _animator->updateBoneMatrices();
}
//
//if(morphAnimationBuffer.frameIndex >= morphAnimationBuffer.numFrames) {
// this.morphAnimationBuffer = null;
// return;
//}
//
//if(morphAnimationBuffer.frameIndex == -1) {
// applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights);
// morphAnimationBuffer->frameIndex++;
// morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now();
//} else {
// duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->lastTime;
// float msElapsed = dur.count();
// if(msElapsed > morphAnimationBuffer->frameLength) {
// frameIndex++;
// applyWeights(frameData + (frameIndex * numWeights), numWeights);
// morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now();
// }
//}
// }
// //
// //if(morphAnimationBuffer.frameIndex >= morphAnimationBuffer.numFrames) {
// // this.morphAnimationBuffer = null;
// // return;
// //}
// //
// //if(morphAnimationBuffer.frameIndex == -1) {
// // applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights);
// // morphAnimationBuffer->frameIndex++;
// // morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now();
// //} else {
// // duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->lastTime;
// // float msElapsed = dur.count();
// // if(msElapsed > morphAnimationBuffer->frameLength) {
// // frameIndex++;
// // applyWeights(frameData + (frameIndex * numWeights), numWeights);
// // morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now();
// // }
// //}
// void FilamentViewer::playAnimation(int index) {
// embeddedAnimationBuffer = make_unique<EmbeddedAnimationBuffer>(index, _animator->getAnimationDuration(index));
// }
void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor) {
if (!_view || !_mainCamera || !manipulator) {
return;
}
// void FilamentViewer::animateWeights(float* data, int numWeights, int length, float frameRate) {
// morphAnimationBuffer = std::make_unique<MorphAnimationBuffer>(data, numWeights, length / numWeights, 1000 / frameRate );
// }
manipulator->setViewport(width, height);
// if(shaderPath) {
// opaqueShaderResources = _loadResource(opaqueShaderPath);
// fadeShaderResources = _loadResource(fadeShaderPath);
// _materialProvider = createGPUMorphShaderLoader(
// opaqueShaderResources.data,
// opaqueShaderResources.size,
// fadeShaderResources.data,
// fadeShaderResources.size,
// _engine);
// } else {
// }
// void printWeights(float* weights, int numWeights) {
// for(int i =0; i < numWeights; i++) {
// // std::cout << weights[i];
// }
// }
const uint32_t _width = width * contentScaleFactor;
const uint32_t _height = height * contentScaleFactor;
_view->setViewport({0, 0, _width, _height});
// void FilamentViewer::createMorpher(const char* meshName, int* primitives, int numPrimitives) {
// // morphHelper = new gltfio::GPUMorphHelper((FFilamentAsset*)_asset, meshName, primitives, numPrimitives);
// // morphHelper = new gltfio::CPUMorpher(((FFilamentAsset)*_asset, (FFilamentInstance*)_asset));
// }
const double aspect = (double)width / height;
_mainCamera->setLensProjection(_cameraFocalLength, aspect, kNearPlane, kFarPlane);
}
// void FilamentViewer::animateBones() {
// }
// Entity entity = _asset->getFirstEntityByName("CC_Base_JawRoot");
// if(!entity) {
// return;
// }
// TransformManager& transformManager = _engine->getTransformManager();
}
// TransformManager::Instance node = transformManager.getInstance( entity);
// mat4f xform = transformManager.getTransform(node);
// float3 scale;
// quatf rotation;
// float3 translation;
// decomposeMatrix(xform, &translation, &rotation, &scale);
// // const quatf srcQuat { weights[0] * 0.9238,0,weights[0] * 0.3826, 0 };
// // float3 { scale[0] * (1.0f - weights[0]), scale[1] * (1.0f - weights[1]), scale[2] * (1.0f - weights[2]) }
// // xform = composeMatrix(translation + float3 { weights[0], weights[1], weights[2] }, rotation, scale );
// transformManager.setTransform(node, xform);
// }

View File

@@ -30,7 +30,11 @@
#include <string>
#include <chrono>
#include "GPUMorphHelper.h"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#include <android/native_activity.h>
using namespace std;
using namespace filament;
@@ -51,46 +55,22 @@ namespace polyvox {
};
struct ResourceBuffer {
ResourceBuffer(const void* data, const uint32_t size) : data(data), size(size) {};
ResourceBuffer(const void* data, const uint32_t size, const uint32_t id) : data(data), size(size), id(id) {};
ResourceBuffer& operator=(ResourceBuffer other)
{
data = other.data;
size = other.size;
id = other.id;
return *this;
}
const void* data;
uint64_t size;
};
struct MorphAnimationBuffer {
MorphAnimationBuffer(float* frameData,
int numWeights,
int numFrames,
float frameLength) : frameData(frameData), numWeights(numWeights), numFrames(numFrames), frameLength(frameLength) {
}
int frameIndex = -1;
int numFrames;
float frameLength;
time_point_t startTime;
float* frameData;
int numWeights;
};
struct EmbeddedAnimationBuffer {
EmbeddedAnimationBuffer(int animationIndex, float duration) : animationIndex(animationIndex), duration(duration) {}
bool hasStarted = false;
int animationIndex;
float duration = 0;
time_point_t lastTime;
uint32_t size;
uint32_t id;
};
using LoadResource = std::function<ResourceBuffer(const char* uri)>;
using FreeResource = std::function<void * (void *mem, size_t s, void *)>;
using FreeResource = std::function<void (ResourceBuffer)>;
class FilamentViewer {
public:
@@ -98,31 +78,29 @@ namespace polyvox {
~FilamentViewer();
void loadGlb(const char* const uri);
void loadGltf(const char* const uri, const char* relativeResourcePath);
void loadSkybox(const char* const skyboxUri, const char* const iblUri);
void loadSkybox(const char* const skyboxUri, const char* const iblUri, AAssetManager* am);
void updateViewportAndCameraProjection(int height, int width, float scaleFactor);
void render();
void createMorpher(const char* meshName, int* primitives, int numPrimitives);
// void createMorpher(const char* meshName, int* primitives, int numPrimitives);
void releaseSourceAssets();
StringList getTargetNames(const char* meshName);
Manipulator<float>* manipulator;
void applyWeights(float* weights, int count);
void animateWeights(float* data, int numWeights, int length, float frameRate);
void animateBones();
// void animateWeights(float* data, int numWeights, int length, float frameRate);
// void animateBones();
void playAnimation(int index);
void setCamera(const char* nodeName);
void destroySwapChain();
void createSwapChain(void* surface);
Renderer* getRenderer();
private:
void loadResources(std::string relativeResourcePath);
void transformToUnitCube();
void cleanup();
void updateMorphAnimation();
void updateEmbeddedAnimation();
void setCamera(const char* cameraName);
// animation flags;
bool isAnimating;
unique_ptr<MorphAnimationBuffer> morphAnimationBuffer;
unique_ptr<EmbeddedAnimationBuffer> embeddedAnimationBuffer;
void* _layer;
@@ -138,12 +116,13 @@ namespace polyvox {
Camera* _mainCamera;
Renderer* _renderer;
SwapChain* _swapChain;
SwapChain* _swapChain = nullptr;
Animator* _animator;
AssetLoader* _assetLoader;
FilamentAsset* _asset = nullptr;
ResourceBuffer _assetBuffer;
NameComponentManager* _ncm;
Entity _sun;
@@ -161,9 +140,41 @@ namespace polyvox {
float _cameraFocalLength = 0.0f;
GPUMorphHelper* morphHelper;
};
}
// void updateMorphAnimation();
// void updateEmbeddedAnimation();
// animation flags;
// bool isAnimating;
// unique_ptr<MorphAnimationBuffer> morphAnimationBuffer;
// unique_ptr<EmbeddedAnimationBuffer> embeddedAnimationBuffer;
// struct EmbeddedAnimationBuffer {
// EmbeddedAnimationBuffer(int animationIndex, float duration) : animationIndex(animationIndex), duration(duration) {}
// bool hasStarted = false;
// int animationIndex;
// float duration = 0;
// time_point_t lastTime;
// };
// struct MorphAnimationBuffer {
// MorphAnimationBuffer(float* frameData,
// int numWeights,
// int numFrames,
// float frameLength) : frameData(frameData), numWeights(numWeights), numFrames(numFrames), frameLength(frameLength) {
// }
// int frameIndex = -1;
// int numFrames;
// float frameLength;
// time_point_t startTime;
// float* frameData;
// int numWeights;
// };

View File

@@ -4,7 +4,6 @@ import 'package:flutter/services.dart';
abstract class FilamentController {
void onFilamentViewCreated(int id);
Future loadSkybox(String skyboxPath, String lightingPath);
Future loadGlb(String path);
Future loadGltf(String path, String relativeResourcePath);
@@ -43,23 +42,15 @@ class PolyvoxFilamentController extends FilamentController {
_id = id;
_channel = MethodChannel("app.polyvox.filament/filament_view_$id");
_channel.setMethodCallHandler((call) async {
await Future.delayed(const Duration(
seconds:
1)); // todo - need a better way to know when the GL context is actually ready
await _initialize();
onFilamentViewCreatedHandler?.call(_id);
return Future.value(true);
if(call.method == "ready") {
onFilamentViewCreatedHandler?.call(_id);
return Future.value(true);
} else {
throw Exception("Unknown method channel invocation ${call.method}");
}
});
}
Future _initialize() async {
await _channel.invokeMethod("initialize", [
"packages/polyvox_filament/assets/lit_opaque.filamat",
"packages/polyvox_filament/assets/lit_fade.filamat"
]);
}
@override
Future loadSkybox(String skyboxPath, String lightingPath) async {
await _channel.invokeMethod("loadSkybox", [skyboxPath, lightingPath]);

View File

@@ -1,17 +0,0 @@
// You have generated a new plugin project without
// specifying the `--platforms` flag. A plugin project supports no platforms is generated.
// To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
// directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
import 'dart:async';
import 'package:flutter/services.dart';
class PolyvoxFilament {
static const MethodChannel _channel = MethodChannel('polyvox_filament');
static Future<String?> get platformVersion async {
final String? version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}

View File

@@ -17,32 +17,14 @@ class FilamentView extends FilamentViewPlatform {
) {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return PlatformViewLink(
viewType: FILAMENT_VIEW_ID,
surfaceFactory:
(BuildContext context, PlatformViewController controller) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: const <
Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (PlatformViewCreationParams params) {
return PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: FILAMENT_VIEW_ID,
layoutDirection: TextDirection.ltr,
creationParams: {},
creationParamsCodec: StandardMessageCodec(),
)
..addOnPlatformViewCreatedListener((int id) {
onFilamentViewCreated(id);
params.onPlatformViewCreated(id);
})
..create();
},
);
return AndroidView(
viewType: FILAMENT_VIEW_ID,
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
onPlatformViewCreated: (id) {
print("onplatformview created $id");
onFilamentViewCreated(id);
});
case TargetPlatform.iOS:
return UiKitView(
viewType: FILAMENT_VIEW_ID,
@@ -51,8 +33,7 @@ class FilamentView extends FilamentViewPlatform {
},
);
case TargetPlatform.windows:
return Text(
"Flutter doesn't support platform view on Windows yet.");
return Text("Flutter doesn't support platform view on Windows yet.");
default:
return Text(
'$defaultTargetPlatform is not yet implemented by Filament plugin.');

View File

@@ -2,13 +2,13 @@ import 'package:flutter/widgets.dart';
import 'package:polyvox_filament/view/filament_view.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
typedef void FilamentViewCreatedCallback(int id);
typedef FilamentViewCreatedCallback = void Function(int id);
abstract class FilamentViewPlatform extends PlatformInterface {
FilamentViewPlatform() : super(token: _token);
static final Object _token = Object();
static FilamentViewPlatform _instance = FilamentView();
static final FilamentViewPlatform _instance = FilamentView();
static FilamentViewPlatform get instance => _instance;

View File

@@ -1,4 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:polyvox_filament/view/filament_view.dart';
import '../filament_controller.dart';
import 'filament_view_platform.dart';

View File

@@ -27,6 +27,9 @@ flutter:
#- assets/lit_fade.filamat
plugin:
platforms:
android:
pluginClass: PolyvoxFilamentPlugin
package: app.polyvox.filament
ios:
pluginClass: PolyvoxFilamentPlugin
windows: