diff --git a/android/gltfio-android/CMakeLists.txt b/android/gltfio-android/CMakeLists.txt index 6e3d601e0c..f4dfae004b 100644 --- a/android/gltfio-android/CMakeLists.txt +++ b/android/gltfio-android/CMakeLists.txt @@ -31,6 +31,7 @@ set(GLTFIO_SRCS ${GLTFIO_DIR}/include/gltfio/ResourceLoader.h ${GLTFIO_DIR}/include/gltfio/SimpleViewer.h ${GLTFIO_DIR}/include/gltfio/FilamentAsset.h + ${GLTFIO_DIR}/include/gltfio/FilamentInstance.h ${GLTFIO_DIR}/src/Animator.cpp ${GLTFIO_DIR}/src/AssetLoader.cpp @@ -40,6 +41,8 @@ set(GLTFIO_SRCS ${GLTFIO_DIR}/src/DependencyGraph.h ${GLTFIO_DIR}/src/FFilamentAsset.h ${GLTFIO_DIR}/src/FilamentAsset.cpp + ${GLTFIO_DIR}/src/FFilamentInstance.h + ${GLTFIO_DIR}/src/FilamentInstance.cpp ${GLTFIO_DIR}/src/GltfEnums.h ${GLTFIO_DIR}/src/MaterialProvider.cpp ${GLTFIO_DIR}/src/ResourceLoader.cpp @@ -53,6 +56,7 @@ set(GLTFIO_SRCS src/main/cpp/Animator.cpp src/main/cpp/AssetLoader.cpp src/main/cpp/FilamentAsset.cpp + src/main/cpp/FilamentInstance.cpp src/main/cpp/MaterialProvider.cpp src/main/cpp/ResourceLoader.cpp diff --git a/android/gltfio-android/src/main/cpp/AssetLoader.cpp b/android/gltfio-android/src/main/cpp/AssetLoader.cpp index 84bc979ac1..2ba72e9eb6 100644 --- a/android/gltfio-android/src/main/cpp/AssetLoader.cpp +++ b/android/gltfio-android/src/main/cpp/AssetLoader.cpp @@ -67,6 +67,27 @@ Java_com_google_android_filament_gltfio_AssetLoader_nCreateAssetFromJson(JNIEnv* buffer.getSize()); } +extern "C" JNIEXPORT jlong JNICALL +Java_com_google_android_filament_gltfio_AssetLoader_nCreateInstancedAsset(JNIEnv* env, jclass, + jlong nativeLoader, jobject javaBuffer, jint remaining, jlongArray instances) { + AssetLoader* loader = (AssetLoader*) nativeLoader; + AutoBuffer buffer(env, javaBuffer, remaining); + jsize numInstances = env->GetArrayLength(instances); + using Handle = FilamentInstance*; + Handle* ptrInstances = new Handle[numInstances]; + jlong asset = (jlong) loader->createInstancedAsset((const uint8_t *) buffer.getData(), + buffer.getSize(), ptrInstances, numInstances); + if (asset) { + jlong* longInstances = env->GetLongArrayElements(instances, nullptr); + for (jsize i = 0; i < numInstances; i++) { + longInstances[i] = (jlong) ptrInstances[i]; + } + env->ReleaseLongArrayElements(instances, longInstances, 0); + } + delete[] ptrInstances; + return asset; +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_gltfio_AssetLoader_nEnableDiagnostics(JNIEnv*, jclass, jlong nativeLoader, jboolean enable) { diff --git a/android/gltfio-android/src/main/cpp/FilamentInstance.cpp b/android/gltfio-android/src/main/cpp/FilamentInstance.cpp new file mode 100644 index 0000000000..62a61331fc --- /dev/null +++ b/android/gltfio-android/src/main/cpp/FilamentInstance.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +using namespace gltfio; +using namespace utils; + +extern "C" JNIEXPORT jint JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetRoot(JNIEnv*, jclass, + jlong nativeInstance) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + return instance->getRoot().getId(); +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetEntityCount(JNIEnv*, jclass, + jlong nativeInstance) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + return instance->getEntityCount(); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetEntities(JNIEnv* env, jclass, + jlong nativeInstance, jintArray result) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + jsize available = env->GetArrayLength(result); + Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr); + std::copy_n(instance->getEntities(), + std::min(available, (jsize) instance->getEntityCount()), entities); + env->ReleaseIntArrayElements(result, (jint*) entities, 0); +} + +extern "C" JNIEXPORT jlong JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetAnimator(JNIEnv* , jclass, + jlong nativeInstance) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + return (jlong) instance->getAnimator(); +} diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java index 79749afdd6..9e7574072b 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java @@ -128,9 +128,34 @@ public class AssetLoader { return nativeAsset != 0 ? new FilamentAsset(mEngine, nativeAsset) : null; } + /** + * Consumes the contents of a glTF 2.0 file and produces a master asset with one or more + * instances. + * + * The given instance array must be sized to the desired number of instances. If successful, + * this method will populate the array with slave instances whose resources are shared with + * the master asset. + */ + @Nullable + @SuppressWarnings("unused") + public FilamentAsset createInstancedAsset(@NonNull Buffer buffer, + @NonNull FilamentInstance[] instances) { + long[] nativeInstances = new long[instances.length]; + long nativeAsset = nCreateInstancedAsset(mNativeObject, buffer, buffer.remaining(), + nativeInstances); + if (nativeAsset == 0) { + return null; + } + for (int i = 0; i < nativeInstances.length; i++) { + instances[i] = new FilamentInstance(nativeInstances[i]); + } + return new FilamentAsset(mEngine, nativeAsset); + } + /** * Allows clients to enable diagnostic shading on newly-loaded assets. */ + @SuppressWarnings("unused") public void enableDiagnostics(boolean enable) { nEnableDiagnostics(mNativeObject, enable); } @@ -148,6 +173,8 @@ public class AssetLoader { private static native void nDestroyAssetLoader(long nativeLoader); private static native long nCreateAssetFromBinary(long nativeLoader, Buffer buffer, int remaining); private static native long nCreateAssetFromJson(long nativeLoader, Buffer buffer, int remaining); + private static native long nCreateInstancedAsset(long nativeLoader, Buffer buffer, int remaining, + long[] nativeInstances); private static native void nEnableDiagnostics(long nativeLoader, boolean enable); private static native void nDestroyAsset(long nativeLoader, long nativeAsset); } diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java new file mode 100644 index 0000000000..895eed8a80 --- /dev/null +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.filament.gltfio; + +import androidx.annotation.NonNull; + +import com.google.android.filament.Entity; + +/** + * Provides access to a hierarchy of entities that have been instanced from a glTF asset. + * + * @see FilamentAsset + * @see Animator + * @see AssetLoader + */ +public class FilamentInstance { + private long mNativeObject; + private Animator mAnimator; + + FilamentInstance(long nativeObject) { + mNativeObject = nativeObject; + mAnimator = null; + } + + @SuppressWarnings("unused") + long getNativeObject() { + return mNativeObject; + } + + @SuppressWarnings("unused") + void clearNativeObject() { + mNativeObject = 0; + } + + /** + * Gets the transform root for the asset, which has no matching glTF node. + */ + @SuppressWarnings("unused") + public @Entity int getRoot() { + return nGetRoot(mNativeObject); + } + + /** + * Gets the list of entities for this instance, one for each glTF node. + * + *

All of these have a transform component. Some of the returned entities may also have a + * renderable component.

+ */ + public @NonNull @Entity int[] getEntities() { + int[] result = new int[nGetEntityCount(mNativeObject)]; + nGetEntities(mNativeObject, result); + return result; + } + + /** + * Creates or retrieves the Animator for this instance. + * + *

When calling this for the first time, this must be called after + * {@link ResourceLoader#loadResources}.

+ */ + public @NonNull Animator getAnimator() { + if (mAnimator != null) { + return mAnimator; + } + mAnimator = new Animator(nGetAnimator(mNativeObject)); + return mAnimator; + } + + private static native int nGetRoot(long nativeAsset); + private static native int nGetEntityCount(long nativeAsset); + private static native void nGetEntities(long nativeAsset, int[] result); + private static native long nGetAnimator(long nativeAsset); +}