diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index b7fca0d5..85639aad 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="app.polyvox.filament_example"> diff --git a/example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt b/example/android/app/src/main/MainActivity.kt similarity index 68% rename from example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt rename to example/android/app/src/main/MainActivity.kt index cf4cdf74..4442a61e 100644 --- a/example/android/app/src/main/kotlin/com/example/polyvox_filament_example/MainActivity.kt +++ b/example/android/app/src/main/MainActivity.kt @@ -1,6 +1,7 @@ -package app.polyvox.polyvox_filament_example +package app.polyvox.filament_example import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { + } diff --git a/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt b/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt index cf4cdf74..59d17d7f 100644 --- a/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/app/polyvox/polyvox_filament_example/MainActivity.kt @@ -1,6 +1,429 @@ -package app.polyvox.polyvox_filament_example +package app.polyvox.filament_example import io.flutter.embedding.android.FlutterActivity +// import com.google.android.filament.gltf.* +import com.google.android.filament.utils.* + +import android.annotation.SuppressLint +import android.app.Activity +import android.os.Bundle +import android.util.Log +import android.view.* +import android.view.GestureDetector +import android.widget.TextView +import android.widget.Toast +import com.google.android.filament.Fence +import com.google.android.filament.IndirectLight +import com.google.android.filament.Skybox +import com.google.android.filament.View +import com.google.android.filament.utils.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileInputStream +import java.io.RandomAccessFile +import java.nio.Buffer +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets +import java.util.zip.ZipInputStream + class MainActivity: FlutterActivity() { + } + + +// + + +// import io.flutter.embedding.android.FlutterActivity + +// class MainActivity : FlutterActivity() { + +// // companion object { +// // // // Load the library for the utility layer, which in turn loads gltfio and the Filament core. +// // // init { Utils.init() } +// // private const val TAG = "gltf-viewer" +// // } + +// // private lateinit var surfaceView : SurfaceView +// // private lateinit var choreographer: Choreographer +// // private val frameScheduler = FrameCallback() +// // private lateinit var modelViewer: ModelViewer +// // private lateinit var titlebarHint: TextView +// // private val doubleTapListener = DoubleTapListener() +// // private lateinit var doubleTapDetector: GestureDetector +// // private var remoteServer: RemoteServer? = null +// // private var statusToast: Toast? = null +// // private var statusText: String? = null +// // private var latestDownload: String? = null +// // private val automation = AutomationEngine() +// // private var loadStartTime = 0L +// // private var loadStartFence: Fence? = null +// // private val viewerContent = AutomationEngine.ViewerContent() + +// // @SuppressLint("ClickableViewAccessibility") +// // override fun onCreate(savedInstanceState: Bundle?) { +// // super.onCreate(savedInstanceState) +// // surfaceView = SurfaceView(this) +// // setContentView( surfaceView) +// // // window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + +// // // // titlebarHint = findViewById(R.id.user_hint) +// // // // surfaceView = findViewById(R.id.main_sv) +// // // choreographer = Choreographer.getInstance() + +// // // doubleTapDetector = GestureDetector(applicationContext, doubleTapListener) + +// // // modelViewer = ModelViewer(surfaceView) +// // // viewerContent.view = modelViewer.view +// // // viewerContent.sunlight = modelViewer.light +// // // viewerContent.lightManager = modelViewer.engine.lightManager +// // // viewerContent.scene = modelViewer.scene +// // // viewerContent.renderer = modelViewer.renderer + +// // // surfaceView.setOnTouchListener { _, event -> +// // // modelViewer.onTouchEvent(event) +// // // doubleTapDetector.onTouchEvent(event) +// // // true +// // // } + +// // // createDefaultRenderables() +// // // createIndirectLight() + +// // // setStatusText("To load a new model, go to the above URL on your host machine.") + +// // // val view = modelViewer.view + +// // // /* +// // // * Note: The settings below are overriden when connecting to the remote UI. +// // // */ + +// // // // on mobile, better use lower quality color buffer +// // // view.renderQuality = view.renderQuality.apply { +// // // hdrColorBuffer = View.QualityLevel.MEDIUM +// // // } + +// // // // dynamic resolution often helps a lot +// // // view.dynamicResolutionOptions = view.dynamicResolutionOptions.apply { +// // // enabled = true +// // // quality = View.QualityLevel.MEDIUM +// // // } + +// // // // MSAA is needed with dynamic resolution MEDIUM +// // // view.multiSampleAntiAliasingOptions = view.multiSampleAntiAliasingOptions.apply { +// // // enabled = true +// // // } + +// // // // FXAA is pretty cheap and helps a lot +// // // view.antiAliasing = View.AntiAliasing.FXAA; + +// // // // ambient occlusion is the cheapest effect that adds a lot of quality +// // // view.ambientOcclusionOptions = view.ambientOcclusionOptions.apply { +// // // enabled = true +// // // } + +// // // // bloom is pretty expensive but adds a fair amount of realism +// // // view.bloomOptions = view.bloomOptions.apply { +// // // enabled = true +// // // } + +// // // remoteServer = RemoteServer(8082) +// // } + +// // private fun createDefaultRenderables() { +// // val buffer = assets.open("models/scene.gltf").use { input -> +// // val bytes = ByteArray(input.available()) +// // input.read(bytes) +// // ByteBuffer.wrap(bytes) +// // } + +// // modelViewer.loadModelGltfAsync(buffer) { uri -> readCompressedAsset("models/$uri") } +// // updateRootTransform() +// // } + +// // private fun createIndirectLight() { +// // val engine = modelViewer.engine +// // val scene = modelViewer.scene +// // val ibl = "default_env" +// // readCompressedAsset("envs/$ibl/${ibl}_ibl.ktx").let { +// // scene.indirectLight = KTXLoader.createIndirectLight(engine, it) +// // scene.indirectLight!!.intensity = 30_000.0f +// // viewerContent.indirectLight = modelViewer.scene.indirectLight +// // } +// // readCompressedAsset("envs/$ibl/${ibl}_skybox.ktx").let { +// // scene.skybox = KTXLoader.createSkybox(engine, it) +// // } +// // } + +// // private fun readCompressedAsset(assetName: String): ByteBuffer { +// // val input = assets.open(assetName) +// // val bytes = ByteArray(input.available()) +// // input.read(bytes) +// // return ByteBuffer.wrap(bytes) +// // } + +// // private fun clearStatusText() { +// // statusToast?.let { +// // it.cancel() +// // statusText = null +// // } +// // } + +// // private fun setStatusText(text: String) { +// // runOnUiThread { +// // if (statusToast == null || statusText != text) { +// // statusText = text +// // statusToast = Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT) +// // statusToast!!.show() + +// // } +// // } +// // } + +// // private suspend fun loadGlb(message: RemoteServer.ReceivedMessage) { +// // withContext(Dispatchers.Main) { +// // modelViewer.destroyModel() +// // modelViewer.loadModelGlb(message.buffer) +// // updateRootTransform() +// // loadStartTime = System.nanoTime() +// // loadStartFence = modelViewer.engine.createFence() +// // } +// // } + +// // private suspend fun loadHdr(message: RemoteServer.ReceivedMessage) { +// // withContext(Dispatchers.Main) { +// // val engine = modelViewer.engine +// // val equirect = HDRLoader.createTexture(engine, message.buffer) +// // if (equirect == null) { +// // setStatusText("Could not decode HDR file.") +// // } else { +// // setStatusText("Successfully decoded HDR file.") + +// // val context = IBLPrefilterContext(engine) +// // val equirectToCubemap = IBLPrefilterContext.EquirectangularToCubemap(context) +// // val skyboxTexture = equirectToCubemap.run(equirect)!! +// // engine.destroyTexture(equirect) + +// // val specularFilter = IBLPrefilterContext.SpecularFilter(context) +// // val reflections = specularFilter.run(skyboxTexture) + +// // val ibl = IndirectLight.Builder() +// // .reflections(reflections) +// // .intensity(30000.0f) +// // .build(engine) + +// // val sky = Skybox.Builder().environment(skyboxTexture).build(engine) + +// // specularFilter.destroy(); +// // equirectToCubemap.destroy(); +// // context.destroy(); + +// // // destroy the previous IBl +// // engine.destroyIndirectLight(modelViewer.scene.indirectLight!!); +// // engine.destroySkybox(modelViewer.scene.skybox!!); + +// // modelViewer.scene.skybox = sky +// // modelViewer.scene.indirectLight = ibl +// // viewerContent.indirectLight = ibl +// // } +// // } +// // } + +// // private suspend fun loadZip(message: RemoteServer.ReceivedMessage) { +// // // To alleviate memory pressure, remove the old model before deflating the zip. +// // withContext(Dispatchers.Main) { +// // modelViewer.destroyModel() +// // } + +// // // Large zip files should first be written to a file to prevent OOM. +// // // It is also crucial that we null out the message "buffer" field. +// // val (zipStream, zipFile) = withContext(Dispatchers.IO) { +// // val file = File.createTempFile("incoming", "zip", cacheDir) +// // val raf = RandomAccessFile(file, "rw") +// // raf.getChannel().write(message.buffer); +// // message.buffer = null +// // raf.seek(0) +// // Pair(FileInputStream(file), file) +// // } + +// // // Deflate each resource using the IO dispatcher, one by one. +// // var gltfPath: String? = null +// // var outOfMemory: String? = null +// // val pathToBufferMapping = withContext(Dispatchers.IO) { +// // val deflater = ZipInputStream(zipStream) +// // val mapping = HashMap() +// // while (true) { +// // val entry = deflater.nextEntry ?: break +// // if (entry.isDirectory) continue + +// // // This isn't strictly required, but as an optimization +// // // we ignore common junk that often pollutes ZIP files. +// // if (entry.name.startsWith("__MACOSX")) continue +// // if (entry.name.startsWith(".DS_Store")) continue + +// // val uri = entry.name +// // val byteArray: ByteArray? = try { +// // deflater.readBytes() +// // } +// // catch (e: OutOfMemoryError) { +// // outOfMemory = uri +// // break +// // } +// // Log.i(TAG, "Deflated ${byteArray!!.size} bytes from $uri") +// // val buffer = ByteBuffer.wrap(byteArray) +// // mapping[uri] = buffer +// // if (uri.endsWith(".gltf") || uri.endsWith(".glb")) { +// // gltfPath = uri +// // } +// // } +// // mapping +// // } + +// // zipFile.delete() + +// // if (gltfPath == null) { +// // setStatusText("Could not find .gltf or .glb in the zip.") +// // return +// // } + +// // if (outOfMemory != null) { +// // setStatusText("Out of memory while deflating $outOfMemory") +// // return +// // } + +// // val gltfBuffer = pathToBufferMapping[gltfPath]!! + +// // // The gltf is often not at the root level (e.g. if a folder is zipped) so +// // // we need to extract its path in order to resolve the embedded uri strings. +// // var gltfPrefix = gltfPath!!.substringBeforeLast('/', "") +// // if (gltfPrefix.isNotEmpty()) { +// // gltfPrefix += "/" +// // } + +// // withContext(Dispatchers.Main) { +// // if (gltfPath!!.endsWith(".glb")) { +// // modelViewer.loadModelGlb(gltfBuffer) +// // } else { +// // modelViewer.loadModelGltf(gltfBuffer) { uri -> +// // val path = gltfPrefix + uri +// // if (!pathToBufferMapping.contains(path)) { +// // Log.e(TAG, "Could not find $path in the zip.") +// // setStatusText("Zip is missing $path") +// // } +// // pathToBufferMapping[path] +// // } +// // } +// // updateRootTransform() +// // loadStartTime = System.nanoTime() +// // loadStartFence = modelViewer.engine.createFence() +// // } +// // } + +// // override fun onResume() { +// // super.onResume() +// // choreographer.postFrameCallback(frameScheduler) +// // } + +// // override fun onPause() { +// // super.onPause() +// // choreographer.removeFrameCallback(frameScheduler) +// // } + +// // override fun onDestroy() { +// // super.onDestroy() +// // choreographer.removeFrameCallback(frameScheduler) +// // remoteServer?.close() +// // } + +// // fun loadModelData(message: RemoteServer.ReceivedMessage) { +// // Log.i(TAG, "Downloaded model ${message.label} (${message.buffer.capacity()} bytes)") +// // clearStatusText() +// // // titlebarHint.text = message.label +// // CoroutineScope(Dispatchers.IO).launch { +// // if (message.label.endsWith(".zip")) { +// // loadZip(message) +// // } else if (message.label.endsWith(".hdr")) { +// // loadHdr(message) +// // } else { +// // loadGlb(message) +// // } +// // } +// // } + +// // fun loadSettings(message: RemoteServer.ReceivedMessage) { +// // val json = StandardCharsets.UTF_8.decode(message.buffer).toString() +// // viewerContent.assetLights = modelViewer.asset?.lightEntities +// // automation.applySettings(json, viewerContent) +// // modelViewer.view.colorGrading = automation.getColorGrading(modelViewer.engine) +// // modelViewer.cameraFocalLength = automation.viewerOptions.cameraFocalLength +// // updateRootTransform() +// // } + +// // private fun updateRootTransform() { +// // if (automation.viewerOptions.autoScaleEnabled) { +// // modelViewer.transformToUnitCube() +// // } else { +// // modelViewer.clearRootTransform() +// // } +// // } + +// // inner class FrameCallback : Choreographer.FrameCallback { +// // private val startTime = System.nanoTime() +// // override fun doFrame(frameTimeNanos: Long) { +// // choreographer.postFrameCallback(this) + +// // loadStartFence?.let { +// // if (it.wait(Fence.Mode.FLUSH, 0) == Fence.FenceStatus.CONDITION_SATISFIED) { +// // val end = System.nanoTime() +// // val total = (end - loadStartTime) / 1_000_000 +// // Log.i(TAG, "The Filament backend took $total ms to load the model geometry.") +// // modelViewer.engine.destroyFence(it) +// // loadStartFence = null +// // } +// // } + +// // modelViewer.animator?.apply { +// // if (animationCount > 0) { +// // val elapsedTimeSeconds = (frameTimeNanos - startTime).toDouble() / 1_000_000_000 +// // applyAnimation(0, elapsedTimeSeconds.toFloat()) +// // } +// // updateBoneMatrices() +// // } + +// // modelViewer.render(frameTimeNanos) + +// // // Check if a new download is in progress. If so, let the user know with toast. +// // val currentDownload = remoteServer?.peekIncomingLabel() +// // if (RemoteServer.isBinary(currentDownload) && currentDownload != latestDownload) { +// // latestDownload = currentDownload +// // Log.i(TAG, "Downloading $currentDownload") +// // setStatusText("Downloading $currentDownload") +// // } + +// // // Check if a new message has been fully received from the client. +// // val message = remoteServer?.acquireReceivedMessage() +// // if (message != null) { +// // if (message.label == latestDownload) { +// // latestDownload = null +// // } +// // if (RemoteServer.isJson(message.label)) { +// // loadSettings(message) +// // } else { +// // loadModelData(message) +// // } +// // } +// // } +// // } + +// // // Just for testing purposes, this releases the current model and reloads the default model. +// // inner class DoubleTapListener : GestureDetector.SimpleOnGestureListener() { +// // override fun onDoubleTap(e: MotionEvent?): Boolean { +// // modelViewer.destroyModel() +// // createDefaultRenderables() +// // return super.onDoubleTap(e) +// // } +// // } +// } diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index b7fca0d5..85639aad 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="app.polyvox.filament_example"> diff --git a/example/android/build.gradle b/example/android/build.gradle index ed45c658..e6cb3895 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.0' repositories { google() mavenCentral() @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } } diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 44e62bcf..121d30d8 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,11 +1,15 @@ include ':app' -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} \ No newline at end of file diff --git a/example/assets/cube.bin b/example/assets/cube.bin new file mode 100644 index 00000000..830b692b Binary files /dev/null and b/example/assets/cube.bin differ diff --git a/example/assets/cube.gltf b/example/assets/cube.gltf new file mode 100644 index 00000000..d0d00f82 --- /dev/null +++ b/example/assets/cube.gltf @@ -0,0 +1,772 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v1.6.16", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0, + 1, + 2, + 3 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube" + }, + { + "name" : "Light", + "rotation" : [ + 0.16907575726509094, + 0.7558803558349609, + -0.27217137813568115, + 0.570947527885437 + ], + "translation" : [ + 4.076245307922363, + 5.903861999511719, + -1.0054539442062378 + ] + }, + { + "name" : "Camera", + "rotation" : [ + 0.483536034822464, + 0.33687159419059753, + -0.20870360732078552, + 0.7804827094078064 + ], + "translation" : [ + 7.358891487121582, + 4.958309173583984, + 6.925790786743164 + ] + }, + { + "mesh" : 1, + "name" : "Cone", + "translation" : [ + 0, + 0, + -4.3612141609191895 + ] + } + ], + "materials" : [ + { + "doubleSided" : true, + "name" : "Material", + "pbrMetallicRoughness" : { + "baseColorFactor" : [ + 0.800000011920929, + 0.800000011920929, + 0.800000011920929, + 1 + ], + "metallicFactor" : 0, + "roughnessFactor" : 0.4000000059604645 + } + } + ], + "meshes" : [ + { + "extras" : { + "targetNames" : [ + "Key 1", + "Key 2", + "Key 3", + "Key 4", + "Key 5", + "Key 6", + "Key 7", + "Key 8" + ] + }, + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1, + "TEXCOORD_0" : 2 + }, + "indices" : 3, + "material" : 0, + "targets" : [ + { + "POSITION" : 4, + "NORMAL" : 5 + }, + { + "POSITION" : 6, + "NORMAL" : 7 + }, + { + "POSITION" : 8, + "NORMAL" : 9 + }, + { + "POSITION" : 10, + "NORMAL" : 11 + }, + { + "POSITION" : 12, + "NORMAL" : 13 + }, + { + "POSITION" : 14, + "NORMAL" : 15 + }, + { + "POSITION" : 16, + "NORMAL" : 17 + }, + { + "POSITION" : 18, + "NORMAL" : 19 + } + ] + } + ], + "weights" : [ + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + { + "extras" : { + "targetNames" : [ + "Key 1", + "Key 2", + "Key 3", + "Key 4", + "Key 5", + "Key 6" + ] + }, + "name" : "Cone", + "primitives" : [ + { + "attributes" : { + "POSITION" : 20, + "NORMAL" : 21, + "TEXCOORD_0" : 22 + }, + "indices" : 23, + "targets" : [ + { + "POSITION" : 24, + "NORMAL" : 25 + }, + { + "POSITION" : 26, + "NORMAL" : 27 + }, + { + "POSITION" : 28, + "NORMAL" : 29 + }, + { + "POSITION" : 30, + "NORMAL" : 31 + }, + { + "POSITION" : 32, + "NORMAL" : 33 + }, + { + "POSITION" : 34, + "NORMAL" : 35 + } + ] + } + ], + "weights" : [ + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 264, + "max" : [ + 1, + 1, + 1 + ], + "min" : [ + -1, + -1, + -1 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 264, + "type" : "VEC2" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 276, + "type" : "SCALAR" + }, + { + "bufferView" : 4, + "componentType" : 5126, + "count" : 264, + "max" : [ + 0.14205700159072876, + 0.36317670345306396, + 2.1620800495147705 + ], + "min" : [ + -2.325753688812256, + -0.12704896926879883, + -0.1493830382823944 + ], + "type" : "VEC3" + }, + { + "bufferView" : 5, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 6, + "componentType" : 5126, + "count" : 264, + "max" : [ + 0.14205700159072876, + 0.6298741102218628, + 0.14937379956245422 + ], + "min" : [ + -0.5040037631988525, + -0.12704896926879883, + -0.7224071025848389 + ], + "type" : "VEC3" + }, + { + "bufferView" : 7, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 8, + "componentType" : 5126, + "count" : 264, + "max" : [ + 1.1911587715148926, + 0.7055504322052002, + 0.14937379956245422 + ], + "min" : [ + -0.1420515477657318, + -0.12704896926879883, + -0.9040634632110596 + ], + "type" : "VEC3" + }, + { + "bufferView" : 9, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 10, + "componentType" : 5126, + "count" : 264, + "max" : [ + 1.0930120944976807, + 0.12705659866333008, + 0.14937379956245422 + ], + "min" : [ + -0.1420515477657318, + -1.7105424404144287, + -0.3054158687591553 + ], + "type" : "VEC3" + }, + { + "bufferView" : 11, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 12, + "componentType" : 5126, + "count" : 264, + "max" : [ + 1.0931031703948975, + 7.137829303741455, + 1.149359941482544 + ], + "min" : [ + -1.0931031703948975, + -0.284426212310791, + -1.149359941482544 + ], + "type" : "VEC3" + }, + { + "bufferView" : 13, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 14, + "componentType" : 5126, + "count" : 264, + "max" : [ + 0.7663934230804443, + 0.12705659866333008, + 0.14937379956245422 + ], + "min" : [ + -0.1420515477657318, + -1.3416147232055664, + -1.2583342790603638 + ], + "type" : "VEC3" + }, + { + "bufferView" : 15, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 16, + "componentType" : 5126, + "count" : 264, + "max" : [ + 1.0939359664916992, + 0.12705659866333008, + 0.14937379956245422 + ], + "min" : [ + -0.1420515477657318, + -1.257744312286377, + -1.9783165454864502 + ], + "type" : "VEC3" + }, + { + "bufferView" : 17, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 18, + "componentType" : 5126, + "count" : 264, + "max" : [ + 0.9689376950263977, + 0.12705659866333008, + 0.14937379956245422 + ], + "min" : [ + -0.1420515477657318, + -1.4092154502868652, + -1.7750303745269775 + ], + "type" : "VEC3" + }, + { + "bufferView" : 19, + "componentType" : 5126, + "count" : 264, + "type" : "VEC3" + }, + { + "bufferView" : 20, + "componentType" : 5126, + "count" : 128, + "max" : [ + 1, + 1, + 1 + ], + "min" : [ + -1, + -1, + -1 + ], + "type" : "VEC3" + }, + { + "bufferView" : 21, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 22, + "componentType" : 5126, + "count" : 128, + "type" : "VEC2" + }, + { + "bufferView" : 23, + "componentType" : 5123, + "count" : 186, + "type" : "SCALAR" + }, + { + "bufferView" : 24, + "componentType" : 5126, + "count" : 128, + "max" : [ + 0, + 0.5201449394226074, + 0 + ], + "min" : [ + 0, + 0, + 0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 25, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 26, + "componentType" : 5126, + "count" : 128, + "max" : [ + 5.200448989868164, + 0, + 0 + ], + "min" : [ + 0, + 0, + 0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 27, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 28, + "componentType" : 5126, + "count" : 128, + "max" : [ + 0, + 0, + 0 + ], + "min" : [ + 0, + 0, + -1.9945937395095825 + ], + "type" : "VEC3" + }, + { + "bufferView" : 29, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 30, + "componentType" : 5126, + "count" : 128, + "max" : [ + 0, + 0, + 0 + ], + "min" : [ + 0, + 0, + 0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 31, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 32, + "componentType" : 5126, + "count" : 128, + "max" : [ + 0, + 0, + 0 + ], + "min" : [ + 0, + 0, + 0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 33, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + }, + { + "bufferView" : 34, + "componentType" : 5126, + "count" : 128, + "max" : [ + 0, + 0, + 0 + ], + "min" : [ + 0, + 0, + 0 + ], + "type" : "VEC3" + }, + { + "bufferView" : 35, + "componentType" : 5126, + "count" : 128, + "type" : "VEC3" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 3168 + }, + { + "buffer" : 0, + "byteLength" : 2112, + "byteOffset" : 6336 + }, + { + "buffer" : 0, + "byteLength" : 552, + "byteOffset" : 8448 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 9000 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 12168 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 15336 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 18504 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 21672 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 24840 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 28008 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 31176 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 34344 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 37512 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 40680 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 43848 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 47016 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 50184 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 53352 + }, + { + "buffer" : 0, + "byteLength" : 3168, + "byteOffset" : 56520 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 59688 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 61224 + }, + { + "buffer" : 0, + "byteLength" : 1024, + "byteOffset" : 62760 + }, + { + "buffer" : 0, + "byteLength" : 372, + "byteOffset" : 63784 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 64156 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 65692 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 67228 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 68764 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 70300 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 71836 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 73372 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 74908 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 76444 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 77980 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 79516 + }, + { + "buffer" : 0, + "byteLength" : 1536, + "byteOffset" : 81052 + } + ], + "buffers" : [ + { + "byteLength" : 82588, + "uri" : "cube.bin" + } + ] +} diff --git a/example/assets/default_env/default_env_ibl.ktx b/example/assets/default_env/default_env_ibl.ktx index 6194dc3f..b2e6cbab 100644 Binary files a/example/assets/default_env/default_env_ibl.ktx and b/example/assets/default_env/default_env_ibl.ktx differ diff --git a/example/assets/default_env/default_env_skybox.ktx b/example/assets/default_env/default_env_skybox.ktx index e8de441a..74750d42 100644 Binary files a/example/assets/default_env/default_env_skybox.ktx and b/example/assets/default_env/default_env_skybox.ktx differ diff --git a/example/lib/main.dart b/example/lib/main.dart index f70c5c86..703ce136 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:polyvox_filament/filament_controller.dart'; import 'package:polyvox_filament/gesture_detecting_filament_view.dart'; +import 'package:polyvox_filament/view/filament_view.dart'; import 'package:polyvox_filament/view/filament_widget.dart'; void main() { @@ -36,9 +37,14 @@ class _MyAppState extends State { title: const Text('Plugin example app'), ), body: Stack(children: [ - GestureDetectingFilamentView( - controller: _filamentController, - ), + Center( + child: Container( + width: 400, + height: 400, + child: FilamentWidget( + controller: _filamentController, + ), + )), Positioned.fill( child: Wrap( alignment: WrapAlignment.end, @@ -56,35 +62,72 @@ class _MyAppState extends State { onPressed: () async { await _filamentController.loadGltf( 'assets/cube.gltf', 'assets'); - await _filamentController.createMorpher('Cube', [0]); }), ElevatedButton( - child: const Text('stretch'), + child: const Text('set all weights to 1'), onPressed: () async { await _filamentController .applyWeights(List.filled(8, 1.0)); }), ElevatedButton( - child: const Text('squeeze'), + child: const Text('set all weights to 0'), onPressed: () async { await _filamentController .applyWeights(List.filled(8, 0)); }), - ElevatedButton( - child: const Text('load caleb'), - onPressed: () async { - await _filamentController.loadGltf( - 'assets/caleb_mouth_morph_target.gltf', 'assets'); - _targets = await _filamentController - .getTargetNames('CC_Base_Body'); - setState(() {}); - - _filamentController - .createMorpher('CC_Base_Body', [1, 7, 8]); - }), ElevatedButton( onPressed: () => _filamentController.playAnimation(0), - child: const Text('Play')) + child: const Text('play animation')), + ElevatedButton( + onPressed: () { + _filamentController.zoom(-1.0); + }, + child: const Text('zoom in')), + ElevatedButton( + onPressed: () { + _filamentController.zoom(1.0); + }, + child: const Text('zoom out')), + Builder(builder:(innerCtx) => ElevatedButton( + onPressed: () async { + final names = await _filamentController + .getTargetNames("Cube"); + + await showDialog( + builder: (ctx) { + return Container( + color: Colors.white, + height:200, width:200, + child: Column( + mainAxisSize: MainAxisSize.min, + children: names + .map((name) => Text(name)) + .cast() + .toList() + + [ + ElevatedButton( + onPressed: () => + Navigator.of(ctx).pop(), + child: Text("Close")) + ])); + }, + context: innerCtx); + }, + child: const Text('get target names'))), + ElevatedButton( + onPressed: () async { + await _filamentController.panStart(1, 1); + await _filamentController.panUpdate(1, 2); + await _filamentController.panEnd(); + }, + child: Text("Pan left")), + ElevatedButton( + onPressed: () async { + await _filamentController.panStart(1, 1); + await _filamentController.panUpdate(0, 0); + await _filamentController.panEnd(); + }, + child: Text("Pan right")) ], ), ), @@ -137,3 +180,8 @@ class _MyAppState extends State { // .values // .toList(), // ) + // ElevatedButton( + // child: const Text('init'), + // onPressed: () async { + // await _filamentController.initialize(); + // }), \ No newline at end of file diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bee540ab..ddbfc00d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -41,7 +41,7 @@ flutter: - assets/BusterDrone/ - assets/BusterDrone/textures/ - assets/FlightHelmet/ - - assets/FlightHelmet/textures/ - - assets/textures/ + #- assets/FlightHelmet/textures/ + #- assets/textures/ \ No newline at end of file