run all Android work on separate thread, add HotReloadPathHelper, separate loadTexture/setTexture

This commit is contained in:
Nick Fisher
2022-08-25 17:09:54 +10:00
parent 051085f440
commit f4c1f59399
12 changed files with 392 additions and 227 deletions

View File

@@ -7,44 +7,69 @@
#include <android/log.h> #include <android/log.h>
#include <android/native_activity.h> #include <android/native_activity.h>
#include <map>
using namespace polyvox; using namespace polyvox;
using namespace std; using namespace std;
static AAssetManager* am; static AAssetManager* am;
static vector<AAsset*> _assets; static map<uint32_t, AAsset*> _apk_assets;
uint64_t id = -1; static map<uint32_t, void*> _file_assets;
static uint32_t _i = 0;
static ResourceBuffer loadResource(const char* name) { static ResourceBuffer loadResource(const char* name) {
id++;
string name_str(name);
AAsset *asset = AAssetManager_open(am, name, AASSET_MODE_BUFFER); auto id = _i++;
if(asset == nullptr) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Couldn't locate asset [ %s ]", name); if (name_str.rfind("file://", 0) == 0) {
return ResourceBuffer(nullptr, 0, 0); streampos length;
ifstream is(name_str.substr(7), ios::binary);
is.seekg (0, ios::end);
length = is.tellg();
char * buffer;
buffer = new char [length];
is.seekg (0, ios::beg);
is.read (buffer, length);
is.close();
_file_assets[id] = buffer;
return ResourceBuffer(buffer, length, id);
} else {
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 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);
_apk_assets[id] = asset;
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Loaded asset [ %s ] of length %zu at index %d", name, length, id);
return ResourceBuffer(buffer, length, id);
} }
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Loading asset [ %s ]", name);
off_t length = AAsset_getLength(asset);
const void * buffer = AAsset_getBuffer(asset);
uint8_t *buf = new uint8_t[length ];
memcpy(buf,buffer, length);
__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(buf, length, id);
} }
static void freeResource(uint32_t id) { static void freeResource(uint32_t id) {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Freeing loaded resource at index [ %d ] ", id); __android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Freeing loaded resource at index [ %d ] ", id);
AAsset* asset = _assets[id]; auto apk_it = _apk_assets.find(id);
if(asset) { if (apk_it != _apk_assets.end()) {
AAsset_close(asset); AAsset_close(apk_it->second);
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Closed Android asset");
} else { } else {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Attempting to free resource at index [ %d ] that has already been released.", id); auto file_it = _file_assets.find(id);
if (file_it != _file_assets.end()) {
free(file_it->second);
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Freed asset from filesystem.");
} else {
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "FATAL - could not find Android or filesystem (hot reload) asset under id %d", id);
}
} }
_assets[id] = nullptr;
} }
extern "C" { extern "C" {

View File

@@ -78,7 +78,8 @@ interface FilamentInterop : Library {
fun set_background_image(viewer:Pointer, path:String); fun set_background_image(viewer:Pointer, path:String);
fun set_texture(asset:Pointer, path:String, renderableIndex:Int); fun load_texture(asset:Pointer, path:String, renderableIndex:Int);
fun set_texture(asset:Pointer);
fun transform_to_unit_cube(asset:Pointer); fun transform_to_unit_cube(asset:Pointer);

View File

@@ -0,0 +1,35 @@
import java.io.*
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.listDirectoryEntries
import android.util.Log
class HotReloadPathHelper {
companion object {
fun getAssetPath(path: String, packageName: String): String? {
// iterate over evr
val shortName = packageName.split(".").last().split("_").last()
val packagePath = "/data/user/0/${packageName}/code_cache/"
Log.v("FFI", "Looking for shortName ${shortName} under package path ${packagePath}")
val files = File(packagePath).listFiles().filter {
it.path.split("/").last().startsWith(shortName)
}.map {
val f = File(it.path + "/${shortName}/build/${path}")
Log.v("FFI", "Looking for ${f.path.toString()}")
f
}.filter {
it.exists()
}.sortedBy {
Log.v("FFI", it.path.toString())
it.lastModified()
}
Log.v("FFI", files.size.toString())
if(files.size > 0)
return files.first().path;
return null;
}
}
}

View File

@@ -4,6 +4,7 @@ import androidx.annotation.NonNull
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import io.flutter.embedding.engine.FlutterJNI
import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
@@ -12,6 +13,8 @@ import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.embedding.engine.loader.FlutterApplicationInfo
import io.flutter.embedding.engine.loader.ApplicationInfoLoader
import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference
@@ -25,6 +28,7 @@ import android.content.pm.PackageManager
import io.flutter.FlutterInjector import io.flutter.FlutterInjector
import android.os.CountDownTimer import android.os.CountDownTimer
import android.os.Handler
import android.opengl.GLU import android.opengl.GLU
import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.egl.EGLConfig
@@ -74,6 +78,10 @@ import android.view.Surface.CHANGE_FRAME_RATE_ALWAYS
import android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT import android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT
import android.view.SurfaceHolder import android.view.SurfaceHolder
import java.util.Timer
import java.util.concurrent.Executor
import java.util.concurrent.Executors
/** PolyvoxFilamentPlugin */ /** PolyvoxFilamentPlugin */
class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
@@ -84,7 +92,7 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private val startTime = System.nanoTime() private val startTime = System.nanoTime()
override fun doFrame(frameTimeNanos: Long) { override fun doFrame(frameTimeNanos: Long) {
choreographer.postFrameCallback(this) choreographer.postFrameCallback(this)
synchronized(lock) { executor.execute {
if(_viewer != null) { if(_viewer != null) {
if(!surface.isValid()) { if(!surface.isValid()) {
Log.v(TAG, "INVALID") Log.v(TAG, "INVALID")
@@ -126,6 +134,8 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var activity:Activity private lateinit var activity:Activity
private val executor = Executors.newFixedThreadPool(1);
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
this.flutterPluginBinding = flutterPluginBinding this.flutterPluginBinding = flutterPluginBinding
channel = MethodChannel(flutterPluginBinding.binaryMessenger, CHANNEL_NAME) channel = MethodChannel(flutterPluginBinding.binaryMessenger, CHANNEL_NAME)
@@ -137,144 +147,162 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
override fun onAttachedToActivity(binding: ActivityPluginBinding) { override fun onAttachedToActivity(binding: ActivityPluginBinding) {
lifecycle = (binding.lifecycle as? HiddenLifecycleReference)?.lifecycle lifecycle = (binding.lifecycle as? HiddenLifecycleReference)?.lifecycle
activity = binding.activity activity = binding.activity
choreographer = Choreographer.getInstance()
choreographer.postFrameCallback(frameCallback)
activity.window.setFormat(PixelFormat.RGBA_8888)
}
fun getAssetPath(path:String) : String {
val loader = FlutterInjector.instance().flutterLoader()
val key = loader.getLookupKeyForAsset(path)
val hotReloadPath = HotReloadPathHelper.getAssetPath(key, activity.getPackageName())
if(hotReloadPath != null) {
return "file://" + hotReloadPath;
}
return key
} }
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) { when (call.method) {
"initialize" -> { "initialize" -> {
if(_viewer != null) { print("Initializing")
synchronized(lock) {
print("Deleting existing viewer")
_lib.filament_viewer_delete(_viewer!!);
_viewer = null;
}
}
if(surfaceTexture != null) {
print("Releasing existing texture")
surfaceTexture!!.release()
surfaceTexture = null;
}
val args = call.arguments as ArrayList<Int>
val width = args[0]
val height = args[1]
val entry = flutterPluginBinding.textureRegistry.createSurfaceTexture(); val entry = flutterPluginBinding.textureRegistry.createSurfaceTexture();
executor.execute {
if(_viewer != null) {
synchronized(lock) {
print("Deleting existing viewer")
_lib.filament_viewer_delete(_viewer!!);
print("Deleted viewer")
_viewer = null;
}
}
if(surfaceTexture != null) {
print("Releasing existing texture")
surfaceTexture!!.release()
surfaceTexture = null;
}
val args = call.arguments as ArrayList<Int>
val width = args[0]
val height = args[1]
surfaceTexture = entry.surfaceTexture()
surfaceTexture!!.setDefaultBufferSize(width, height)
surface = Surface(surfaceTexture!!)
_viewer = _lib.filament_viewer_new_android(
surface as Object,
JNIEnv.CURRENT,
(activity as Context).assets)
_lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f);
result.success(entry.id().toInt())
choreographer = Choreographer.getInstance() }
surfaceTexture = entry.surfaceTexture()
surfaceTexture!!.setDefaultBufferSize(width, height)
surface = Surface(surfaceTexture!!)
_viewer = _lib.filament_viewer_new_android(
surface as Object,
JNIEnv.CURRENT,
(activity as Context).assets)
choreographer.postFrameCallback(frameCallback)
activity.window.setFormat(PixelFormat.RGBA_8888)
_lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f);
result.success(entry.id().toInt())
} }
"resize" -> { "resize" -> {
val args = call.arguments as ArrayList<Int> executor.execute {
val width = args[0] val args = call.arguments as ArrayList<Int>
val height = args[1] val width = args[0]
val height = args[1]
surfaceTexture!!.setDefaultBufferSize(width, height) surfaceTexture!!.setDefaultBufferSize(width, height)
_lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f); _lib.update_viewport_and_camera_projection(_viewer!!, width, height, 1.0f);
result.success(null) result.success(null)
}
"reloadAssets" -> {
// context = context.createPackageContext(context.getPackageName(), 0)
// val assetManager = context.getAssets()
// val flutterJNI = FlutterJNI.Factory.provideFlutterJNI()
// flutterJNI.updateJavaAssetManager(assetManager, flutterApplicationInfo.flutterAssetsDir)
} }
}
"setBackgroundImage" -> { "setBackgroundImage" -> {
val args = call.arguments as String executor.execute {
val loader = FlutterInjector.instance().flutterLoader() _lib.set_background_image(_viewer!!, getAssetPath(call.arguments as String))
_lib.set_background_image(_viewer!!, loader.getLookupKeyForAsset(args))
_lib.render(_viewer!!)
result.success("OK"); result.success("OK");
}
} }
"loadSkybox" -> { "loadSkybox" -> {
val args = call.arguments as String executor.execute {
val loader = FlutterInjector.instance().flutterLoader() _lib.load_skybox(_viewer!!, getAssetPath(call.arguments as String))
_lib.load_skybox(_viewer!!, loader.getLookupKeyForAsset(args))
result.success("OK"); result.success("OK");
}
} }
"loadIbl" -> { "loadIbl" -> {
val args = call.arguments as String executor.execute {
val loader = FlutterInjector.instance().flutterLoader() _lib.load_ibl(_viewer!!, getAssetPath(call.arguments as String))
_lib.load_ibl(_viewer!!, loader.getLookupKeyForAsset(args))
result.success("OK"); result.success("OK");
}
} }
"removeIbl" -> { "removeIbl" -> {
_lib.remove_ibl(_viewer!!) executor.execute {
result.success(true); _lib.remove_ibl(_viewer!!)
result.success(true);
}
} }
"removeSkybox" -> { "removeSkybox" -> {
_lib.remove_skybox(_viewer!!) executor.execute {
result.success(true); _lib.remove_skybox(_viewer!!)
result.success(true);
}
} }
"loadGlb" -> { "loadGlb" -> {
if (_viewer == null) executor.execute {
return;
val loader = FlutterInjector.instance().flutterLoader()
val key = loader.getLookupKeyForAsset(call.arguments as String)
val key2 = loader.getLookupKeyForAsset(call.arguments as String, (activity as Context).packageName)
val path = loader.findAppBundlePath()
val assetPtr = _lib.load_glb( val assetPtr = _lib.load_glb(
_viewer!!, _viewer!!,
key getAssetPath(call.arguments as String)
) )
result.success(Pointer.nativeValue(assetPtr)); result.success(Pointer.nativeValue(assetPtr));
}
} }
"loadGltf" -> { "loadGltf" -> {
if (_viewer == null) executor.execute {
return;
val args = call.arguments as ArrayList<Any?> val args = call.arguments as ArrayList<Any?>
val loader = FlutterInjector.instance().flutterLoader()
val assetPtr = _lib.load_gltf( val assetPtr = _lib.load_gltf(
_viewer!!, _viewer!!,
loader.getLookupKeyForAsset(args[0] as String), getAssetPath(args[0] as String),
loader.getLookupKeyForAsset(args[1] as String) getAssetPath(args[1] as String)
) )
result.success(Pointer.nativeValue(assetPtr)); result.success(Pointer.nativeValue(assetPtr));
}
} }
"transformToUnitCube" -> { "transformToUnitCube" -> {
val assetPtr = Pointer(call.arguments as Long); executor.execute {
_lib.transform_to_unit_cube(assetPtr) val assetPtr = Pointer(call.arguments as Long);
result.success("OK"); _lib.transform_to_unit_cube(assetPtr)
result.success("OK");
}
} }
"setPosition" -> { "setPosition" -> {
val args = call.arguments as ArrayList<*> executor.execute {
val assetPtr = Pointer(args[0] as Long) val args = call.arguments as ArrayList<*>
_lib.set_position(assetPtr, (args[1] as Double).toFloat(), (args[2] as Double).toFloat(), (args[3] as Double).toFloat()) val assetPtr = Pointer(args[0] as Long)
result.success("OK"); _lib.set_position(assetPtr, (args[1] as Double).toFloat(), (args[2] as Double).toFloat(), (args[3] as Double).toFloat())
result.success("OK");
}
} }
"setRotation" -> { "setRotation" -> {
val args = call.arguments as ArrayList<*> executor.execute {
val assetPtr = Pointer(args[0] as Long) val args = call.arguments as ArrayList<*>
_lib.set_rotation(assetPtr, (args[1] as Double).toFloat(), (args[2] as Double).toFloat(), (args[3] as Double).toFloat(), (args[4] as Double).toFloat()) val assetPtr = Pointer(args[0] as Long)
result.success("OK"); _lib.set_rotation(assetPtr, (args[1] as Double).toFloat(), (args[2] as Double).toFloat(), (args[3] as Double).toFloat(), (args[4] as Double).toFloat())
result.success("OK");
}
} }
"setTexture" -> { "setTexture" -> {
val args = call.arguments as ArrayList<*> executor.execute {
val loader = FlutterInjector.instance().flutterLoader() val args = call.arguments as ArrayList<*>
val assetPtr = Pointer(args[0] as Long); val assetPtr = Pointer(args[0] as Long);
_lib.set_texture(assetPtr, loader.getLookupKeyForAsset(args[1] as String), args[2] as Int) _lib.load_texture(assetPtr, getAssetPath(args[1] as String), args[2] as Int)
result.success("OK"); print("Texture loaded")
result.success("OK");
}
} }
"setCamera" -> { "setCamera" -> {
executor.execute {
val args = call.arguments as ArrayList<*> val args = call.arguments as ArrayList<*>
val success = _lib.set_camera( val success = _lib.set_camera(
_viewer!!, _viewer!!,
@@ -286,110 +314,143 @@ class PolyvoxFilamentPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
} else { } else {
result.error("failed","failed", "Failed to set camera") result.error("failed","failed", "Failed to set camera")
} }
}
} }
"zoom" -> { "zoom" -> {
if(_viewer == null) executor.execute {
return; _lib.scroll(_viewer!!, 0.0f, 0.0f, (call.arguments as Double).toFloat())
_lib.scroll(_viewer!!, 0.0f, 0.0f, (call.arguments as Double).toFloat()) result.success("OK");
result.success("OK"); }
} }
"getTargetNames" -> { "getTargetNames" -> {
val args = call.arguments as ArrayList<*> executor.execute {
val assetPtr = Pointer(args[0] as Long) val args = call.arguments as ArrayList<*>
val meshName = args[1] as String val assetPtr = Pointer(args[0] as Long)
val names = mutableListOf<String>() val meshName = args[1] as String
val outPtr = Memory(256) val names = mutableListOf<String>()
for(i in 0.._lib.get_target_name_count(assetPtr, meshName) - 1) { val outPtr = Memory(256)
_lib.get_target_name(assetPtr, meshName, outPtr, i) for(i in 0.._lib.get_target_name_count(assetPtr, meshName) - 1) {
val name = outPtr.getString(0) _lib.get_target_name(assetPtr, meshName, outPtr, i)
names.add(name) val name = outPtr.getString(0)
names.add(name)
}
result.success(names)
} }
result.success(names)
} }
"getAnimationNames" -> { "getAnimationNames" -> {
val assetPtr = Pointer(call.arguments as Long) executor.execute {
val names = mutableListOf<String>() val assetPtr = Pointer(call.arguments as Long)
val outPtr = Memory(256) val names = mutableListOf<String>()
for(i in 0.._lib.get_animation_count(assetPtr) - 1) { val outPtr = Memory(256)
_lib.get_animation_name(assetPtr, outPtr, i) for(i in 0.._lib.get_animation_count(assetPtr) - 1) {
val name = outPtr.getString(0) _lib.get_animation_name(assetPtr, outPtr, i)
names.add(name) val name = outPtr.getString(0)
names.add(name)
}
result.success(names)
} }
result.success(names)
} }
"applyWeights" -> { "applyWeights" -> {
val args = call.arguments as ArrayList<*> executor.execute {
val assetPtr = Pointer(args[0] as Long) val args = call.arguments as ArrayList<*>
val weights = args[1] as ArrayList<Float>; val assetPtr = Pointer(args[0] as Long)
val weights = args[1] as ArrayList<Float>;
_lib.apply_weights(assetPtr, weights.toFloatArray(), weights.size) _lib.apply_weights(assetPtr, weights.toFloatArray(), weights.size)
result.success("OK"); result.success("OK");
}
} }
"animateWeights" -> { "animateWeights" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
val assetPtr = Pointer(args[0] as Long) val args = call.arguments as ArrayList<Any?>
val frames = args[1] as ArrayList<Float>; val assetPtr = Pointer(args[0] as Long)
val numWeights = args[2] as Int val frames = args[1] as ArrayList<Float>;
val numFrames = args[3] as Int val numWeights = args[2] as Int
val frameLenInMs = args[4] as Double val numFrames = args[3] as Int
val frameLenInMs = args[4] as Double
_lib.animate_weights(assetPtr, frames.toFloatArray(), numWeights, numFrames, frameLenInMs.toFloat()) _lib.animate_weights(assetPtr, frames.toFloatArray(), numWeights, numFrames, frameLenInMs.toFloat())
result.success("OK"); result.success("OK");
}
} }
"panStart" -> { "panStart" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true)
result.success("OK");
}
} }
"panUpdate" -> { "panUpdate" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
} }
"panEnd" -> { "panEnd" -> {
_lib.grab_end(_viewer!!) executor.execute {
result.success("OK"); _lib.grab_end(_viewer!!)
result.success("OK");
}
} }
"rotateStart" -> { "rotateStart" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, false) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, false)
result.success("OK");
}
} }
"rotateUpdate" -> { "rotateUpdate" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
} }
"rotateEnd" -> { "rotateEnd" -> {
_lib.grab_end(_viewer!!) executor.execute {
result.success("OK"); _lib.grab_end(_viewer!!)
result.success("OK");
}
} }
"grabStart" -> { "grabStart" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_begin(_viewer!!, args[0] as Int, args[1] as Int, true)
result.success("OK");
}
} }
"grabUpdate" -> { "grabUpdate" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int) val args = call.arguments as ArrayList<Any?>
result.success("OK"); _lib.grab_update(_viewer!!, args[0] as Int, args[1] as Int)
result.success("OK");
}
} }
"grabEnd" -> { "grabEnd" -> {
_lib.grab_end(_viewer!!) executor.execute {
result.success("OK"); _lib.grab_end(_viewer!!)
result.success("OK");
}
} }
"removeAsset" -> { "removeAsset" -> {
_lib.remove_asset(_viewer!!, Pointer(call.arguments as Long)) executor.execute {
result.success("OK"); _lib.remove_asset(_viewer!!, Pointer(call.arguments as Long))
result.success("OK");
}
} }
"clearAssets" -> { "clearAssets" -> {
_lib.clear_assets(_viewer!!) executor.execute {
result.success("OK"); _lib.clear_assets(_viewer!!)
result.success("OK");
}
} }
"playAnimation" -> { "playAnimation" -> {
val args = call.arguments as ArrayList<Any?> executor.execute {
_lib.play_animation(Pointer(args[0] as Long), args[1] as Int, args[2] as Boolean) val args = call.arguments as ArrayList<Any?>
result.success("OK") _lib.play_animation(Pointer(args[0] as Long), args[1] as Int, args[2] as Boolean)
result.success("OK")
}
} }
else -> { else -> {
result.notImplemented() result.notImplemented()

View File

@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:polyvox_filament/filament_controller.dart'; import 'package:polyvox_filament/filament_controller.dart';
import 'package:polyvox_filament/filament_widget.dart'; import 'package:polyvox_filament/filament_widget.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
@@ -223,6 +224,9 @@ class _MyAppState extends State<MyApp> {
setState(() { setState(() {
_vertical = !_vertical; _vertical = !_vertical;
}); });
break;
case 26:
await _filamentController.reload();
} }
}, },
itemBuilder: (BuildContext context) => itemBuilder: (BuildContext context) =>
@@ -302,6 +306,9 @@ class _MyAppState extends State<MyApp> {
value: 19, child: Text('pan right')), value: 19, child: Text('pan right')),
PopupMenuItem( PopupMenuItem(
value: 25, child: Text(_vertical ? 'set horizontal' : 'set vertical')), value: 25, child: Text(_vertical ? 'set horizontal' : 'set vertical')),
PopupMenuItem(
value: 26, child: Text(
"reload native assets")),
]))) ])))
]))); ])));
} }

View File

@@ -111,7 +111,7 @@ FilamentViewer::FilamentViewer(void *layer, LoadResource loadResource,
.presentationDeadlineNanos = (uint64_t)0, .presentationDeadlineNanos = (uint64_t)0,
.vsyncOffsetNanos = (uint64_t)0}); .vsyncOffsetNanos = (uint64_t)0});
Renderer::FrameRateOptions fro; Renderer::FrameRateOptions fro;
fro.interval = 30; fro.interval = 60;
_renderer->setFrameRateOptions(fro); _renderer->setFrameRateOptions(fro);
_scene = _engine->createScene(); _scene = _engine->createScene();
@@ -119,6 +119,7 @@ FilamentViewer::FilamentViewer(void *layer, LoadResource loadResource,
Log("Scene created"); Log("Scene created");
Entity camera = EntityManager::get().create(); Entity camera = EntityManager::get().create();
_mainCamera = _engine->createCamera(camera); _mainCamera = _engine->createCamera(camera);
Log("Main camera created"); Log("Main camera created");
_view = _engine->createView(); _view = _engine->createView();
@@ -185,14 +186,15 @@ FilamentViewer::FilamentViewer(void *layer, LoadResource loadResource,
_scene->addEntity(_sun); _scene->addEntity(_sun);
Log("Added sun"); Log("Added sun");
_sceneAssetLoader = new SceneAssetLoader(_loadResource, _sceneAssetLoader = new SceneAssetLoader(_loadResource,
_freeResource, _freeResource,
_assetLoader, _assetLoader,
_resourceLoader, _resourceLoader,
_ncm, _ncm,
_engine, _engine,
_scene); _scene,
tp);
} }
static constexpr float4 sFullScreenTriangleVertices[3] = { static constexpr float4 sFullScreenTriangleVertices[3] = {
@@ -336,23 +338,20 @@ void FilamentViewer::setBackgroundImage(const char *resourcePath) {
FilamentViewer::~FilamentViewer() { FilamentViewer::~FilamentViewer() {
clearAssets(); clearAssets();
_resourceLoader->asyncCancelLoad(); Log("Deleting SceneAssetLoader");
Log("c1");
_materialProvider->destroyMaterials();
Log("c2");
AssetLoader::destroy(&_assetLoader);
Log("c3");
delete _sceneAssetLoader; delete _sceneAssetLoader;
_resourceLoader->asyncCancelLoad();
_materialProvider->destroyMaterials();
AssetLoader::destroy(&_assetLoader);
_engine->destroy(_sun);
_engine->destroyCameraComponent(_mainCamera->getEntity());
_mainCamera = nullptr;
_engine->destroy(_view); _engine->destroy(_view);
Log("c4");
_engine->destroy(_scene); _engine->destroy(_scene);
Log("c5");
_engine->destroy(_renderer); _engine->destroy(_renderer);
Log("c6");
_engine->destroy(_swapChain); _engine->destroy(_swapChain);
Log("c7");
Engine::destroy(&_engine); // clears engine* Engine::destroy(&_engine); // clears engine*
Log("c8");
} }
Renderer *FilamentViewer::getRenderer() { return _renderer; } Renderer *FilamentViewer::getRenderer() { return _renderer; }
@@ -401,8 +400,11 @@ SceneAsset *FilamentViewer::loadGltf(const char *const uri,
void FilamentViewer::clearAssets() { void FilamentViewer::clearAssets() {
Log("Clearing all assets"); Log("Clearing all assets");
mtx.lock(); // mtx.lock();
_view->setCamera(_mainCamera); if(_mainCamera) {
_view->setCamera(_mainCamera);
}
int i = 0; int i = 0;
for (auto asset : _assets) { for (auto asset : _assets) {
_sceneAssetLoader->remove(asset); _sceneAssetLoader->remove(asset);
@@ -410,7 +412,8 @@ void FilamentViewer::clearAssets() {
i++; i++;
} }
_assets.clear(); _assets.clear();
mtx.unlock(); // mtx.unlock();
Log("Cleared all assets");
} }
void FilamentViewer::removeAsset(SceneAsset *asset) { void FilamentViewer::removeAsset(SceneAsset *asset) {
@@ -555,7 +558,7 @@ void FilamentViewer::render() {
return; return;
} }
mtx.lock(); // mtx.lock();
for (auto &asset : _assets) { for (auto &asset : _assets) {
asset->updateAnimations(); asset->updateAnimations();
} }
@@ -569,7 +572,7 @@ void FilamentViewer::render() {
_renderer->render(_view); _renderer->render(_view);
_renderer->endFrame(); _renderer->endFrame();
} }
mtx.unlock(); // mtx.unlock();
} }
void FilamentViewer::updateViewportAndCameraProjection( void FilamentViewer::updateViewportAndCameraProjection(

View File

@@ -127,7 +127,6 @@ namespace polyvox {
Material* _imageMaterial = nullptr; Material* _imageMaterial = nullptr;
TextureSampler _imageSampler; TextureSampler _imageSampler;
ColorGrading *colorGrading = nullptr; ColorGrading *colorGrading = nullptr;
}; };

View File

@@ -15,7 +15,6 @@ extern "C" {
void* filament_viewer_new(void* texture, ResourceBuffer (*loadResource)(const char*), void (*freeResource)(uint32_t)) { void* filament_viewer_new(void* texture, ResourceBuffer (*loadResource)(const char*), void (*freeResource)(uint32_t)) {
return nullptr; return nullptr;
} }
void filament_viewer_delete(void* viewer) { void filament_viewer_delete(void* viewer) {
delete((FilamentViewer*)viewer); delete((FilamentViewer*)viewer);
@@ -135,8 +134,12 @@ extern "C" {
((FilamentViewer*)viewer)->clearAssets(); ((FilamentViewer*)viewer)->clearAssets();
} }
void set_texture(void* asset, const char* assetPath, int renderableIndex) { void load_texture(void* asset, const char* assetPath, int renderableIndex) {
((SceneAsset*)asset)->setTexture(assetPath, renderableIndex); ((SceneAsset*)asset)->loadTexture(assetPath, renderableIndex);
}
void set_texture(void* asset) {
((SceneAsset*)asset)->setTexture();
} }
void transform_to_unit_cube(void* asset) { void transform_to_unit_cube(void* asset) {

View File

@@ -46,7 +46,8 @@ void remove_asset(void* viewer, void* asset);
void clear_assets(void* viewer); void clear_assets(void* viewer);
void set_texture(void* asset, const char* assetPath, int renderableIndex); void load_texture(void* asset, const char* assetPath, int renderableIndex);
void set_texture(void* asset);
void transform_to_unit_cube(void* asset); void transform_to_unit_cube(void* asset);

View File

@@ -41,7 +41,11 @@ SceneAsset::SceneAsset(FilamentAsset *asset, Engine *engine,
} }
SceneAsset::~SceneAsset() { SceneAsset::~SceneAsset() {
// we defer all destructor work to SceneAssetLoader so we don't need to do anything here // most other destructor work is deferred to SceneAssetLoader so we don't need to do anything here
if(_texture) {
_engine->destroy(_texture);
_texture = nullptr;
}
} }
void SceneAsset::applyWeights(float *weights, int count) { void SceneAsset::applyWeights(float *weights, int count) {
@@ -121,26 +125,35 @@ void SceneAsset::stopAnimation(int index) {
_embeddedAnimationStatus[index].started = false; _embeddedAnimationStatus[index].started = false;
} }
void SceneAsset::setTexture(const char* resourcePath, int renderableIndex) { void SceneAsset::loadTexture(const char* resourcePath, int renderableIndex) {
Log("Setting texture to %s for renderableIndex %d", resourcePath, renderableIndex);
ResourceBuffer imageResource = _loadResource(resourcePath);
polyvox::StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size); Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex);
std::istream *inputStream = new std::istream(&sb); string rp("flutter_assets/assets/background.png");
if(_texture) {
_engine->destroy(_texture);
_texture = nullptr;
}
ResourceBuffer imageResource = _loadResource(rp.c_str());
StreamBufferAdapter sb((char *)imageResource.data, (char *)imageResource.data + imageResource.size);
istream *inputStream = new std::istream(&sb);
LinearImage *image = new LinearImage(ImageDecoder::decode( LinearImage *image = new LinearImage(ImageDecoder::decode(
*inputStream, resourcePath, ImageDecoder::ColorSpace::SRGB)); *inputStream, rp.c_str(), ImageDecoder::ColorSpace::SRGB));
if (!image->isValid()) { if (!image->isValid()) {
Log("Invalid image : %s", resourcePath); Log("Invalid image : %s", rp.c_str());
return; return;
} }
uint32_t channels = image->getChannels(); uint32_t channels = image->getChannels();
uint32_t w = image->getWidth(); uint32_t w = image->getWidth();
uint32_t h = image->getHeight(); uint32_t h = image->getHeight();
auto texture = Texture::Builder() _texture = Texture::Builder()
.width(w) .width(w)
.height(h) .height(h)
.levels(0xff) .levels(0xff)
@@ -149,8 +162,10 @@ void SceneAsset::setTexture(const char* resourcePath, int renderableIndex) {
.sampler(Texture::Sampler::SAMPLER_2D) .sampler(Texture::Sampler::SAMPLER_2D)
.build(*_engine); .build(*_engine);
Log("build texture");
Texture::PixelBufferDescriptor::Callback freeCallback = [](void *buf, size_t, Texture::PixelBufferDescriptor::Callback freeCallback = [](void *buf, size_t,
void *data) { void *data) {
delete reinterpret_cast<LinearImage *>(data); delete reinterpret_cast<LinearImage *>(data);
}; };
@@ -159,20 +174,26 @@ void SceneAsset::setTexture(const char* resourcePath, int renderableIndex) {
channels == 3 ? Texture::Format::RGB : Texture::Format::RGBA, channels == 3 ? Texture::Format::RGB : Texture::Format::RGBA,
Texture::Type::FLOAT, freeCallback); Texture::Type::FLOAT, freeCallback);
texture->setImage(*_engine, 0, std::move(buffer)); _texture->setImage(*_engine, 0, std::move(buffer));
Log("set image");
setTexture();
delete inputStream;
size_t mic = _asset->getMaterialInstanceCount(); _freeResource(imageResource.id);
}
void SceneAsset::setTexture() {
MaterialInstance* const* inst = _asset->getMaterialInstances(); MaterialInstance* const* inst = _asset->getMaterialInstances();
size_t mic = _asset->getMaterialInstanceCount();
Log("Material instance count : %d", mic); Log("Material instance count : %d", mic);
RenderableManager &rm = _engine->getRenderableManager(); RenderableManager &rm = _engine->getRenderableManager();
auto sampler = TextureSampler(); auto sampler = TextureSampler();
inst[0]->setParameter("baseColorIndex",0); inst[0]->setParameter("baseColorIndex",0);
inst[0]->setParameter("baseColorMap",texture,sampler); inst[0]->setParameter("baseColorMap",_texture,sampler);
delete inputStream;
_freeResource(imageResource.id);
} }
void SceneAsset::updateEmbeddedAnimations() { void SceneAsset::updateEmbeddedAnimations() {

View File

@@ -4,16 +4,17 @@
#include <filament/RenderableManager.h> #include <filament/RenderableManager.h>
#include <filament/Renderer.h> #include <filament/Renderer.h>
#include <filament/Scene.h> #include <filament/Scene.h>
#include <filament/Texture.h>
#include <gltfio/AssetLoader.h> #include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h> #include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h> #include <gltfio/ResourceLoader.h>
#include <utils/NameComponentManager.h> #include <utils/NameComponentManager.h>
#include "SceneResources.hpp" #include "SceneResources.hpp"
namespace polyvox { namespace polyvox {
using namespace filament; using namespace filament;
using namespace filament::gltfio; using namespace filament::gltfio;
@@ -32,7 +33,8 @@ namespace polyvox {
/// ///
/// ///
/// ///
void setTexture(const char* resourcePath, int renderableIndex); void loadTexture(const char* resourcePath, int renderableIndex);
void setTexture();
/// ///
/// Update the bone/morph target animations to reflect the current frame (if applicable). /// Update the bone/morph target animations to reflect the current frame (if applicable).
@@ -79,6 +81,7 @@ namespace polyvox {
private: private:
FilamentAsset* _asset = nullptr; FilamentAsset* _asset = nullptr;
Engine* _engine = nullptr; Engine* _engine = nullptr;
NameComponentManager* _ncm; NameComponentManager* _ncm;
@@ -86,6 +89,7 @@ namespace polyvox {
void updateMorphAnimation(); void updateMorphAnimation();
void updateEmbeddedAnimations(); void updateEmbeddedAnimations();
Animator* _animator; Animator* _animator;
// animation flags; // animation flags;
@@ -95,5 +99,8 @@ namespace polyvox {
LoadResource _loadResource; LoadResource _loadResource;
FreeResource _freeResource; FreeResource _freeResource;
// a slot to preload textures
filament::Texture* _texture = nullptr;
}; };
} }

View File

@@ -24,7 +24,8 @@ namespace polyvox {
ResourceLoader* resourceLoader, ResourceLoader* resourceLoader,
NameComponentManager* ncm, NameComponentManager* ncm,
Engine* engine, Engine* engine,
Scene* scene); Scene* scene,
workqueue::threadpool& threadpool);
SceneAsset* fromGltf(const char* uri, const char* relativeResourcePath); SceneAsset* fromGltf(const char* uri, const char* relativeResourcePath);
SceneAsset* fromGlb(const char* uri); SceneAsset* fromGlb(const char* uri);
void remove(SceneAsset* asset); void remove(SceneAsset* asset);
@@ -37,6 +38,7 @@ namespace polyvox {
NameComponentManager* _ncm; NameComponentManager* _ncm;
Scene* _scene; Scene* _scene;
Engine* _engine; Engine* _engine;
workqueue::threadpool& _threadpool;
}; };