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:
21
android/CMakeLists.txt
Normal file
21
android/CMakeLists.txt
Normal 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 )
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
rootProject.name = 'filament'
|
||||
rootProject.name = 'polyvox_filament'
|
||||
|
||||
146
android/src/main/cpp/filament_api.cpp
Normal file
146
android/src/main/cpp/filament_api.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
15
android/src/main/cpp/filament_api.h
Normal file
15
android/src/main/cpp/filament_api.h
Normal 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
|
||||
);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
298
android/src/main/kotlin/app/polyvox/filament/FilamentView.kt
Normal file
298
android/src/main/kotlin/app/polyvox/filament/FilamentView.kt
Normal 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!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
3
android/src/main/libs/arm64-v8a/libfilament-jni.so
Normal file
3
android/src/main/libs/arm64-v8a/libfilament-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a8f24f2cb744814f1502a1a29164ca9d08c7f844a83e9d077f3831a1fd13c67a
|
||||
size 1723112
|
||||
3
android/src/main/libs/arm64-v8a/libfilament-utils-jni.so
Normal file
3
android/src/main/libs/arm64-v8a/libfilament-utils-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8cbdbc57e41114b428fbd6e417a4cafbffd83be8994ea0da44b2cdad6abc4e4f
|
||||
size 430944
|
||||
3
android/src/main/libs/arm64-v8a/libfilament_interop.so
Normal file
3
android/src/main/libs/arm64-v8a/libfilament_interop.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1d2c3b8bf5dae7441fc7d16a345fd7a3fd170e0bcd0f0f054b16ba4e64a289d0
|
||||
size 2152000
|
||||
3
android/src/main/libs/arm64-v8a/libgltfio-jni.so
Normal file
3
android/src/main/libs/arm64-v8a/libgltfio-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fa2185681699dc2f72ed79bf0f3b227c8a936047e1d0f35edf2854e2dbb0319d
|
||||
size 8758184
|
||||
3
android/src/main/libs/armeabi-v7a/libfilament-jni.so
Normal file
3
android/src/main/libs/armeabi-v7a/libfilament-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:16fbe91a5f417dab44046090e918e3f3fb119cc7aa7ce72e68b1692687915c90
|
||||
size 1378344
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8cf27e32b857a98c8b8a0862ec55d8b4eb06d2f22d6d7502865f8ed5dd21db78
|
||||
size 344268
|
||||
3
android/src/main/libs/armeabi-v7a/libfilament_interop.so
Normal file
3
android/src/main/libs/armeabi-v7a/libfilament_interop.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:30734d9a58740c04ee282843c2a0db455d4daa239a5d15bf2f5d8c3ef04f21c8
|
||||
size 2346424
|
||||
3
android/src/main/libs/armeabi-v7a/libgltfio-jni.so
Normal file
3
android/src/main/libs/armeabi-v7a/libgltfio-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b1498fff038d1bcdb7e52d4369b61e71ea33154ebf769934dbcadafb0bbb814b
|
||||
size 8463116
|
||||
3
android/src/main/libs/x86/libfilament-jni.so
Normal file
3
android/src/main/libs/x86/libfilament-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:134ff007e621892b60c01be75173b94fd02be5b94f6818f76c0e639d85003446
|
||||
size 1880488
|
||||
3
android/src/main/libs/x86/libfilament-utils-jni.so
Normal file
3
android/src/main/libs/x86/libfilament-utils-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a1699bf6ab28d55e49d0a8d4d7ace8043b9477036ae8760f14c4c14deeba94d6
|
||||
size 461552
|
||||
3
android/src/main/libs/x86/libfilament_interop.so
Normal file
3
android/src/main/libs/x86/libfilament_interop.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bc2e220862a8179129fbfd5fe944e725eec57335c7014bea7ba538d62f6d93de
|
||||
size 2327272
|
||||
3
android/src/main/libs/x86/libgltfio-jni.so
Normal file
3
android/src/main/libs/x86/libgltfio-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8a82bd46c8f0e3ed5970e873c92f219cdbed2d02d75855ffb889ac3821cf53c8
|
||||
size 8846488
|
||||
3
android/src/main/libs/x86_64/libfilament-jni.so
Normal file
3
android/src/main/libs/x86_64/libfilament-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e227eefd03b2ef8b79366fc443efe11ec87768c284f33dcfdc8906e3985fc7a6
|
||||
size 1840928
|
||||
3
android/src/main/libs/x86_64/libfilament-utils-jni.so
Normal file
3
android/src/main/libs/x86_64/libfilament-utils-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:43fa88beba41cce0ffa2f25418cee021946818882b91ad6da63194e19b34fca6
|
||||
size 469208
|
||||
3
android/src/main/libs/x86_64/libfilament_interop.so
Normal file
3
android/src/main/libs/x86_64/libfilament_interop.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f5c0abca686c763b814af96ada136cb872b9d776ebad063b8293bb20488c4a13
|
||||
size 2141136
|
||||
3
android/src/main/libs/x86_64/libgltfio-jni.so
Normal file
3
android/src/main/libs/x86_64/libgltfio-jni.so
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:39eaf4b8d74194db66401e754527fe3d01a457f829de559ef2503e76b8ffd9e6
|
||||
size 8859584
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
6327
ios/Classes/cgltf.h
6327
ios/Classes/cgltf.h
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
// }
|
||||
@@ -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;
|
||||
// };
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.');
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -27,6 +27,9 @@ flutter:
|
||||
#- assets/lit_fade.filamat
|
||||
plugin:
|
||||
platforms:
|
||||
android:
|
||||
pluginClass: PolyvoxFilamentPlugin
|
||||
package: app.polyvox.filament
|
||||
ios:
|
||||
pluginClass: PolyvoxFilamentPlugin
|
||||
windows:
|
||||
|
||||
Reference in New Issue
Block a user