2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/internal/model-components/model-primitive-impl.h>
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
27 #include <dali-scene3d/internal/model-components/material-impl.h>
28 #include <dali-scene3d/public-api/loader/environment-definition.h>
39 * Creates control through type registry
43 return Scene3D::ModelPrimitive::New();
46 // Setup properties, signals and actions using the type-registry.
47 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
48 DALI_TYPE_REGISTRATION_END()
50 constexpr std::string_view MORPH_KEYWORD = "MORPH";
51 constexpr std::string_view MORPH_POSITION_KEYWORD = "MORPH_POSITION";
52 constexpr std::string_view MORPH_NORMAL_KEYWORD = "MORPH_NORMAL";
53 constexpr std::string_view MORPH_TANGENT_KEYWORD = "MORPH_TANGENT";
54 constexpr std::string_view MORPH_VERSION_2_0_KEYWORD = "MORPH_VERSION_2_0";
55 } // unnamed namespace
57 ModelPrimitivePtr ModelPrimitive::New()
59 ModelPrimitivePtr primitive = new ModelPrimitive();
61 primitive->Initialize();
66 ModelPrimitive::ModelPrimitive()
70 ModelPrimitive::~ModelPrimitive()
74 GetImplementation(mMaterial).RemoveObserver(this);
79 void ModelPrimitive::Initialize()
83 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
86 mGeometry = renderer.GetGeometry();
87 mTextureSet = renderer.GetTextures();
88 mShader = renderer.GetShader();
91 Dali::Renderer ModelPrimitive::GetRenderer() const
96 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
102 Dali::Geometry ModelPrimitive::GetGeometry() const
107 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
114 if(mMaterial != material)
116 // Stop observe from previous material.
119 GetImplementation(mMaterial).RemoveObserver(this);
122 mMaterial = material;
124 // Start observe from new material.
128 GetImplementation(mMaterial).AddObserver(this);
133 mIsMaterialChanged = true;
134 if(GetImplementation(mMaterial).IsResourceReady())
136 GetImplementation(mMaterial).UpdateMaterialData();
137 ApplyMaterialToRenderer();
140 UpdateImageBasedLightTexture();
144 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
149 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
151 mObservers.insert(observer);
154 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
156 mObservers.erase(observer);
159 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
161 mDiffuseTexture = diffuseTexture;
162 mSpecularTexture = specularTexture;
163 mIblScaleFactor = iblScaleFactor;
164 mSpecularMipmapLevels = specularMipmapLevels;
166 UpdateImageBasedLightTexture();
169 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
171 mIblScaleFactor = iblScaleFactor;
172 if(mRenderer && mMaterial)
174 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
178 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
180 mBlendShapeData = std::move(data);
181 Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
184 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
186 mBlendShapeGeometry = blendShapeGeometry;
189 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents)
191 mHasPositions = hasPositions;
192 mHasNormals = hasNormals;
193 mHasTangents = hasTangents;
196 void ModelPrimitive::SetSkinned(bool isSkinned)
198 mHasSkinning = isSkinned;
201 // From MaterialModifyObserver
203 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
205 ApplyMaterialToRenderer(flag);
208 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
210 uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
211 if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
213 std::string vertexShader = GetImplementation(mMaterial).GetVertexShader();
214 std::string fragmentShader = GetImplementation(mMaterial).GetFragmentShader();
216 std::vector<std::string> defines;
217 defines.push_back("VEC4_TANGENT");
220 defines.push_back("SKINNING");
222 if(mHasPositions || mHasNormals || mHasTangents)
226 defines.push_back(MORPH_POSITION_KEYWORD.data());
230 defines.push_back(MORPH_NORMAL_KEYWORD.data());
234 defines.push_back(MORPH_TANGENT_KEYWORD.data());
236 defines.push_back(MORPH_KEYWORD.data());
237 if(mBlendShapeData.version == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
239 defines.push_back(MORPH_VERSION_2_0_KEYWORD.data());
242 for(const auto& define : defines)
244 Scene3D::Loader::ShaderDefinition::ApplyDefine(vertexShader, define);
248 mShader = Shader::New(vertexShader, fragmentShader);
256 mRenderer.SetShader(mShader);
260 uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
261 if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
263 mTextureSet = GetImplementation(mMaterial).GetTextureSet();
265 if(mBlendShapeGeometry)
267 TextureSet newTextureSet = TextureSet::New();
268 newTextureSet.SetTexture(0u, mBlendShapeGeometry);
270 const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
271 for(unsigned int index = 0u; index < numberOfTextures; ++index)
273 const unsigned int newIndex = index + 1u;
274 newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
275 newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
278 mTextureSet = newTextureSet;
281 uint32_t textureCount = mTextureSet.GetTextureCount();
282 Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
283 if(!mSpecularTexture || !mDiffuseTexture)
285 Scene3D::Loader::EnvironmentMapData environmentMapData;
286 environmentMapData.mPixelData.resize(6);
287 for(auto& face : environmentMapData.mPixelData)
289 face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
291 environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
292 Texture iblTexture = environmentMapData.GetTexture();
293 mDiffuseTexture = iblTexture;
294 mSpecularTexture = iblTexture;
297 mTextureSet.SetTexture(textureCount++, brdfTexture);
298 mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
299 mTextureSet.SetTexture(textureCount, mSpecularTexture);
301 auto specularSampler = Sampler::New();
302 specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
303 specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
304 mTextureSet.SetSampler(textureCount, specularSampler);
312 mRenderer.SetTextures(mTextureSet);
316 uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
317 if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
321 mNeedToSetRendererUniform = true;
325 UpdateRendererUniform();
328 mIsMaterialChanged = false;
331 void ModelPrimitive::CreateRenderer()
333 if(!mShader || !mGeometry || !mTextureSet || mRenderer)
338 mRenderer = Renderer::New(mGeometry, mShader);
339 mRenderer.SetTextures(mTextureSet);
340 UpdateRendererUniform();
341 for(auto* observer : mObservers)
343 observer->OnRendererCreated(mRenderer);
347 void ModelPrimitive::UpdateImageBasedLightTexture()
349 if(mRenderer && mMaterial)
351 Dali::TextureSet textures = mRenderer.GetTextures();
357 uint32_t textureCount = textures.GetTextureCount();
358 if(textureCount > 2u &&
359 (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
360 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
362 Dali::TextureSet newTextures = Dali::TextureSet::New();
364 for(uint32_t index = 0u; index < textureCount; ++index)
366 Dali::Texture texture = textures.GetTexture(index);
367 if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
369 texture = mDiffuseTexture;
371 else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
373 texture = mSpecularTexture;
376 newTextures.SetTexture(index, texture);
377 newTextures.SetSampler(index, textures.GetSampler(index));
380 mRenderer.SetTextures(newTextures);
382 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
383 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
387 void ModelPrimitive::UpdateRendererUniform()
389 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
390 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
391 GetImplementation(mMaterial).SetRendererUniform(mRenderer);
394 } // namespace Internal
396 } // namespace Scene3D