From c3c8293862a14de3d7b713793626ac9e1cd2f90d Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Wed, 6 May 2020 09:06:37 -0700 Subject: [PATCH] MaterialInstance now has an optional name. When no name is provided during instance creation, it does NOT inherit the name of its parent material. This is because instances should be lightweight and users can already do instance->getMaterial()->getName(). In a subsequent PR, this feature will be exercised and tested via the gltfio AssetLoader. Fixes #2485. --- RELEASE_NOTES.md | 2 ++ .../filament-android/src/main/cpp/Material.cpp | 10 ++++++++++ .../com/google/android/filament/Material.java | 16 ++++++++++++++++ .../android/filament/MaterialInstance.java | 12 ++++++++++++ filament/include/filament/Material.h | 5 ++++- filament/include/filament/MaterialInstance.h | 5 +++++ filament/src/Engine.cpp | 5 +++-- filament/src/Material.cpp | 8 ++++---- filament/src/MaterialInstance.cpp | 9 +++++++-- filament/src/Skybox.cpp | 2 +- filament/src/details/Engine.h | 2 +- filament/src/details/Material.h | 2 +- filament/src/details/MaterialInstance.h | 6 +++++- web/filament-js/filament.d.ts | 2 ++ web/filament-js/jsbindings.cpp | 7 +++++++ 15 files changed, 80 insertions(+), 13 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2c9c77e23a..f237c6ecf5 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,8 @@ A new header is inserted each time a *tag* is created. ## Next release +- MaterialInstances now have optional names. + ## v1.6.0 - gltfio: fixed incorrect cone angles with lights. diff --git a/android/filament-android/src/main/cpp/Material.cpp b/android/filament-android/src/main/cpp/Material.cpp index 6fda58f1b6..beb9b51a2f 100644 --- a/android/filament-android/src/main/cpp/Material.cpp +++ b/android/filament-android/src/main/cpp/Material.cpp @@ -47,6 +47,16 @@ Java_com_google_android_filament_Material_nCreateInstance(JNIEnv*, jclass, return (jlong) material->createInstance(); } +extern "C" JNIEXPORT jlong JNICALL +Java_com_google_android_filament_Material_nCreateInstanceWithName(JNIEnv* env, jclass, + jlong nativeMaterial, jstring name_) { + Material* material = (Material*) nativeMaterial; + const char *name = env->GetStringUTFChars(name_, 0); + jlong instance = (jlong) material->createInstance(name); + env->ReleaseStringUTFChars(name_, name); + return instance; +} + extern "C" JNIEXPORT jstring JNICALL Java_com_google_android_filament_Material_nGetName(JNIEnv* env, jclass, jlong nativeMaterial) { diff --git a/android/filament-android/src/main/java/com/google/android/filament/Material.java b/android/filament-android/src/main/java/com/google/android/filament/Material.java index b82e4c8309..eb0343ae27 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Material.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Material.java @@ -326,6 +326,21 @@ public class Material { return new MaterialInstance(this, nativeInstance); } + /** + * Creates a new instance of this material with a specified name. Material instances should be + * freed using {@link Engine#destroyMaterialInstance(MaterialInstance)}. + * + * @param name arbitrary label to associate with the given material instance + * + * @return the new instance + */ + @NonNull + public MaterialInstance createInstance(@NonNull String name) { + long nativeInstance = nCreateInstanceWithName(getNativeObject(), name); + if (nativeInstance == 0) throw new IllegalStateException("Couldn't create MaterialInstance"); + return new MaterialInstance(this, nativeInstance, name); + } + /** Returns the material's default instance. */ @NonNull public MaterialInstance getDefaultInstance() { @@ -879,6 +894,7 @@ public class Material { private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size); private static native long nCreateInstance(long nativeMaterial); + private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name); private static native long nGetDefaultInstance(long nativeMaterial); private static native String nGetName(long nativeMaterial); diff --git a/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java b/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java index d82b4714ba..c93f5fa18f 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java +++ b/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java @@ -24,6 +24,7 @@ public class MaterialInstance { private Material mMaterial; private long mNativeObject; private long mNativeMaterial; + private String mName; public enum BooleanElement { BOOL, @@ -53,6 +54,12 @@ public class MaterialInstance { mNativeObject = nativeMaterialInstance; } + MaterialInstance(@NonNull Material material, long nativeMaterialInstance, String name) { + mMaterial = material; + mNativeObject = nativeMaterialInstance; + mName = name; + } + MaterialInstance(long nativeMaterial, long nativeMaterialInstance) { mNativeMaterial = nativeMaterial; mNativeObject = nativeMaterialInstance; @@ -67,6 +74,11 @@ public class MaterialInstance { return mMaterial; } + /** @return the name associated with this instance if one exists, otherwise null */ + public String getName() { + return mName; + } + /** * Sets the value of a bool parameter. * diff --git a/filament/include/filament/Material.h b/filament/include/filament/Material.h index 6be3a8df13..6fce86359a 100644 --- a/filament/include/filament/Material.h +++ b/filament/include/filament/Material.h @@ -123,9 +123,12 @@ public: * Creates a new instance of this material. Material instances should be freed using * Engine::destroy(const MaterialInstance*). * + * @param name Optional name to associate with the given material instance. If this is null, + * then there is no associated name (note that the material's name does not get inherited). + * * @return A pointer to the new instance. */ - MaterialInstance* createInstance() const noexcept; + MaterialInstance* createInstance(const char* name = nullptr) const noexcept; //! Returns the name of this material as a null-terminated string. const char* getName() const noexcept; diff --git a/filament/include/filament/MaterialInstance.h b/filament/include/filament/MaterialInstance.h index bbc867b22d..8a617316a7 100644 --- a/filament/include/filament/MaterialInstance.h +++ b/filament/include/filament/MaterialInstance.h @@ -65,6 +65,11 @@ public: */ Material const* getMaterial() const noexcept; + /** + * @return the name associated with this instance if one exists, otherwise null + */ + const char* getName() const noexcept; + /** * Set a uniform by name * diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index 61377664af..99ef2f331c 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -551,8 +551,9 @@ FRenderer* FEngine::createRenderer() noexcept { return p; } -FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material) noexcept { - FMaterialInstance* p = mHeapAllocator.make(*this, material); +FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material, + const char* name) noexcept { + FMaterialInstance* p = mHeapAllocator.make(*this, material, name); if (p) { auto pos = mMaterialInstances.emplace(material, "MaterialInstance"); pos.first->second.insert(p); diff --git a/filament/src/Material.cpp b/filament/src/Material.cpp index 3969d51b1c..183d306e61 100644 --- a/filament/src/Material.cpp +++ b/filament/src/Material.cpp @@ -286,8 +286,8 @@ void FMaterial::terminate(FEngine& engine) { mDefaultInstance.terminate(engine); } -FMaterialInstance* FMaterial::createInstance() const noexcept { - return mEngine.createMaterialInstance(this); +FMaterialInstance* FMaterial::createInstance(const char* name) const noexcept { + return mEngine.createMaterialInstance(this, name); } bool FMaterial::hasParameter(const char* name) const noexcept { @@ -529,8 +529,8 @@ void FMaterial::destroyPrograms(FEngine& engine) { using namespace details; -MaterialInstance* Material::createInstance() const noexcept { - return upcast(this)->createInstance(); +MaterialInstance* Material::createInstance(const char* name) const noexcept { + return upcast(this)->createInstance(name); } const char* Material::getName() const noexcept { diff --git a/filament/src/MaterialInstance.cpp b/filament/src/MaterialInstance.cpp index 3737493e36..977c6d4609 100644 --- a/filament/src/MaterialInstance.cpp +++ b/filament/src/MaterialInstance.cpp @@ -41,7 +41,8 @@ namespace details { FMaterialInstance::FMaterialInstance() noexcept = default; -FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material) { +FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material, const char* name) : + mName(name) { FEngine::DriverApi& driver = engine.getDriverApi(); if (!material->getUniformInterfaceBlock().isEmpty()) { @@ -223,7 +224,11 @@ template UTILS_NOINLINE void FMaterialInstance::setParameter (const cha using namespace details; Material const* MaterialInstance::getMaterial() const noexcept { - return upcast(this)->mMaterial; + return upcast(this)->getMaterial(); +} + +const char* MaterialInstance::getName() const noexcept { + return upcast(this)->getName(); } template diff --git a/filament/src/Skybox.cpp b/filament/src/Skybox.cpp index 3da96519c6..df9215ae01 100644 --- a/filament/src/Skybox.cpp +++ b/filament/src/Skybox.cpp @@ -98,7 +98,7 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept mIntensity(builder->mIntensity) { FMaterial const* material = engine.getSkyboxMaterial(); - mSkyboxMaterialInstance = material->createInstance(); + mSkyboxMaterialInstance = material->createInstance("Skybox"); TextureSampler sampler(TextureSampler::MagFilter::LINEAR, TextureSampler::WrapMode::REPEAT); auto pInstance = static_cast(mSkyboxMaterialInstance); diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 2e1cc1da0e..81fce37ef5 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -230,7 +230,7 @@ public: void createLight(const LightManager::Builder& builder, utils::Entity entity); FRenderer* createRenderer() noexcept; - FMaterialInstance* createMaterialInstance(const FMaterial* material) noexcept; + FMaterialInstance* createMaterialInstance(const FMaterial* material, const char* name) noexcept; FScene* createScene() noexcept; FView* createView() noexcept; diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h index 1d9d53ea22..63789224c2 100644 --- a/filament/src/details/Material.h +++ b/filament/src/details/Material.h @@ -65,7 +65,7 @@ public: } // Create an instance of this material - FMaterialInstance* createInstance() const noexcept; + FMaterialInstance* createInstance(const char* name) const noexcept; bool hasParameter(const char* name) const noexcept; diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index 0fb0d62c1f..852cf31656 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -38,7 +38,7 @@ class FMaterial; class FMaterialInstance : public MaterialInstance { public: - FMaterialInstance(FEngine& engine, FMaterial const* material); + FMaterialInstance(FEngine& engine, FMaterial const* material, const char* name); FMaterialInstance(const FMaterialInstance& rhs) = delete; FMaterialInstance& operator=(const FMaterialInstance& rhs) = delete; @@ -132,6 +132,8 @@ public: void setDepthCulling(bool enable) noexcept; + const char* getName() const noexcept { return mName.c_str(); } + private: friend class FMaterial; friend class MaterialInstance; @@ -162,6 +164,8 @@ private: (uint32_t)std::numeric_limits::max(), (uint32_t)std::numeric_limits::max() }; + + utils::CString mName; }; FILAMENT_UPCAST(MaterialInstance) diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index 76bcc4ce15..459dbf590f 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -109,6 +109,7 @@ export class TextureSampler { } export class MaterialInstance { + public getName(): string; public setBoolParameter(name: string, value: boolean): void; public setFloatParameter(name: string, value: number): void; public setFloat2Parameter(name: string, value: float2): void; @@ -283,6 +284,7 @@ export class Renderer { export class Material { public createInstance(): MaterialInstance; + public createNamedInstance(name: string): MaterialInstance; public getDefaultInstance(): MaterialInstance; public getName(): string; } diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index d7f4deb044..79ed13b7da 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -988,11 +988,18 @@ class_("Material") select_overload(&Material::getDefaultInstance), allow_raw_pointers()) .function("createInstance", &Material::createInstance, allow_raw_pointers()) + .function("createNamedInstance", EMBIND_LAMBDA(MaterialInstance*, + (Material* self, std::string name), { + return self->createInstance(name.c_str()); }), allow_raw_pointers()) .function("getName", EMBIND_LAMBDA(std::string, (Material* self), { return std::string(self->getName()); }), allow_raw_pointers()); class_("MaterialInstance") + .function("getName", EMBIND_LAMBDA(std::string, (MaterialInstance* self), { + const char* name = self->getName(); + return std::string(name ? name : ""); + }), allow_raw_pointers()) .function("setBoolParameter", EMBIND_LAMBDA(void, (MaterialInstance* self, std::string name, bool value), { self->setParameter(name.c_str(), value); }), allow_raw_pointers())