2 * Copyright (c) 2024 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 "mesh-visual.h"
22 #include <dali/devel-api/adaptor-framework/file-loader.h>
23 #include <dali/devel-api/adaptor-framework/image-loading.h>
24 #include <dali/devel-api/common/stage.h>
25 #include <dali/devel-api/scripting/enum-helper.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/integration-api/debug.h>
30 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
31 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
32 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
33 #include <dali-toolkit/public-api/visuals/visual-properties.h>
39 const int CUSTOM_PROPERTY_COUNT(5); // 5 transform properties
42 * @brief Loads a texture from a file
43 * @param[in] imageUrl The url of the file
44 * @param[in] generateMipmaps Indicates whether to generate mipmaps for the texture
45 * @return A texture if loading succeeds, an empty handle otherwise
47 Texture LoadTexture(const char* imageUrl, bool generateMipmaps)
51 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(imageUrl);
54 texture = Texture::New(TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
55 PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
56 texture.Upload(pixelData);
60 texture.GenerateMipmaps();
66 } // unnamed namespace
74 //Defines ordering of textures for shaders.
75 //All shaders, if including certain texture types, must include them in the same order.
76 //Within the texture set for the renderer, textures are ordered in the same manner.
85 DALI_ENUM_TO_STRING_TABLE_BEGIN(SHADING_MODE)
86 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURELESS_WITH_DIFFUSE_LIGHTING)
87 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_SPECULAR_LIGHTING)
88 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
89 DALI_ENUM_TO_STRING_TABLE_END(SHADING_MODE)
92 const char* const OBJECT_MATRIX_UNIFORM_NAME("uObjectMatrix");
93 const char* const STAGE_OFFSET_UNIFORM_NAME("uStageOffset");
95 } // unnamed namespace
97 MeshVisualPtr MeshVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
99 MeshVisualPtr meshVisualPtr(new MeshVisual(factoryCache));
100 meshVisualPtr->SetProperties(properties);
101 meshVisualPtr->Initialize();
102 return meshVisualPtr;
105 MeshVisual::MeshVisual(VisualFactoryCache& factoryCache)
106 : Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::MESH),
107 mShadingMode(Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING),
109 mUseMipmapping(true),
110 mUseSoftNormals(true)
114 MeshVisual::~MeshVisual()
118 void MeshVisual::DoSetProperties(const Property::Map& propertyMap)
120 for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
122 KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
123 if(keyValue.first.type == Property::Key::INDEX)
125 DoSetProperty(keyValue.first.indexKey, keyValue.second);
129 if(keyValue.first == OBJECT_URL_NAME)
131 DoSetProperty(Toolkit::MeshVisual::Property::OBJECT_URL, keyValue.second);
133 else if(keyValue.first == MATERIAL_URL_NAME)
135 DoSetProperty(Toolkit::MeshVisual::Property::MATERIAL_URL, keyValue.second);
137 else if(keyValue.first == TEXTURES_PATH_NAME)
139 DoSetProperty(Toolkit::MeshVisual::Property::TEXTURES_PATH, keyValue.second);
141 else if(keyValue.first == SHADING_MODE_NAME)
143 DoSetProperty(Toolkit::MeshVisual::Property::SHADING_MODE, keyValue.second);
145 else if(keyValue.first == USE_MIPMAPPING_NAME)
147 DoSetProperty(Toolkit::MeshVisual::Property::USE_MIPMAPPING, keyValue.second);
149 else if(keyValue.first == USE_SOFT_NORMALS_NAME)
151 DoSetProperty(Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, keyValue.second);
153 else if(keyValue.first == LIGHT_POSITION_NAME)
155 DoSetProperty(Toolkit::MeshVisual::Property::LIGHT_POSITION, keyValue.second);
160 if(mMaterialUrl.empty())
165 if(mLightPosition == Vector3::ZERO)
167 // Default behaviour is to place the light directly in front of the object,
168 // at a reasonable distance to light everything on screen.
169 Stage stage = Stage::GetCurrent();
171 mLightPosition = Vector3(stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5);
175 void MeshVisual::DoSetProperty(Property::Index index, const Property::Value& value)
179 case Toolkit::MeshVisual::Property::OBJECT_URL:
181 if(!value.Get(mObjectUrl))
183 DALI_LOG_ERROR("MeshVisual: property objectUrl is the wrong type, use STRING\n");
187 case Toolkit::MeshVisual::Property::MATERIAL_URL:
189 if(!value.Get(mMaterialUrl))
191 DALI_LOG_ERROR("MeshVisual: property materialUrl is the wrong type, use STRING\n");
195 case Toolkit::MeshVisual::Property::TEXTURES_PATH:
197 if(!value.Get(mTexturesPath))
199 mTexturesPath.clear();
203 case Toolkit::MeshVisual::Property::SHADING_MODE:
205 Scripting::GetEnumerationProperty(value, SHADING_MODE_TABLE, SHADING_MODE_TABLE_COUNT, mShadingMode);
208 case Toolkit::MeshVisual::Property::USE_MIPMAPPING:
210 if(!value.Get(mUseMipmapping))
212 DALI_LOG_ERROR("MeshVisual: property useMipmapping is the wrong type, use BOOLEAN\n");
216 case Toolkit::MeshVisual::Property::USE_SOFT_NORMALS:
218 if(!value.Get(mUseSoftNormals))
220 DALI_LOG_ERROR("MeshVisual: property useSoftNormals is the wrong type, use BOOLEAN\n");
224 case Toolkit::MeshVisual::Property::LIGHT_POSITION:
226 if(!value.Get(mLightPosition))
228 mLightPosition = Vector3::ZERO;
229 DALI_LOG_ERROR("MeshVisual: property lightPosition is the wrong type, use VECTOR3\n");
236 void MeshVisual::OnSetTransform()
240 mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
244 void MeshVisual::DoSetOnScene(Actor& actor)
246 actor.AddRenderer(mImpl->mRenderer);
248 // Mesh loaded and ready to display
249 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
252 void MeshVisual::DoCreatePropertyMap(Property::Map& map) const
255 map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::MESH);
256 map.Insert(Toolkit::MeshVisual::Property::OBJECT_URL, mObjectUrl);
257 map.Insert(Toolkit::MeshVisual::Property::MATERIAL_URL, mMaterialUrl);
258 map.Insert(Toolkit::MeshVisual::Property::TEXTURES_PATH, mTexturesPath);
259 map.Insert(Toolkit::MeshVisual::Property::SHADING_MODE, mShadingMode);
260 map.Insert(Toolkit::MeshVisual::Property::USE_MIPMAPPING, mUseMipmapping);
261 map.Insert(Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, mUseSoftNormals);
262 map.Insert(Toolkit::MeshVisual::Property::LIGHT_POSITION, mLightPosition);
265 void MeshVisual::DoCreateInstancePropertyMap(Property::Map& map) const
270 void MeshVisual::OnInitialize()
272 //Try to load the geometry from the file.
275 SupplyEmptyGeometry();
279 //If a texture is used by the obj file, load the supplied material file.
280 if(mObjLoader.IsTexturePresent() && !mMaterialUrl.empty())
284 SupplyEmptyGeometry();
289 //Now that the required parts are loaded, create the geometry for the object.
290 if(!CreateGeometry())
292 SupplyEmptyGeometry();
298 //Load the various texture files supplied by the material file.
301 SupplyEmptyGeometry();
305 mImpl->mRenderer = VisualRenderer::New(mGeometry, mShader);
306 mImpl->mRenderer.SetTextures(mTextureSet);
307 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
308 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
310 //Register transform properties
311 mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
314 void MeshVisual::SupplyEmptyGeometry()
316 mGeometry = Geometry::New();
317 mShader = Shader::New(SHADER_MESH_VISUAL_SIMPLE_SHADER_VERT, SHADER_MESH_VISUAL_SIMPLE_SHADER_FRAG, Shader::Hint::NONE, "MESH_VISUAL_SIMPLE");
318 mImpl->mRenderer = VisualRenderer::New(mGeometry, mShader);
320 DALI_LOG_ERROR("Initialisation error in mesh visual.\n");
323 void MeshVisual::UpdateShaderUniforms()
325 Stage stage = Stage::GetCurrent();
326 float width = stage.GetSize().width;
327 float height = stage.GetSize().height;
330 scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
332 mShader.RegisterProperty(STAGE_OFFSET_UNIFORM_NAME, Vector2(width, height) / 2.0f);
333 mShader.RegisterProperty(LIGHT_POSITION_NAME, mLightPosition);
334 mShader.RegisterProperty(OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix);
337 void MeshVisual::CreateShader()
339 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
341 mShader = Shader::New(SHADER_MESH_VISUAL_NORMAL_MAP_SHADER_VERT, SHADER_MESH_VISUAL_NORMAL_MAP_SHADER_FRAG, Shader::Hint::NONE, "MESH_VISUAL_NRMMAP");
343 else if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING)
345 mShader = Shader::New(SHADER_MESH_VISUAL_SHADER_VERT, SHADER_MESH_VISUAL_SHADER_FRAG, Shader::Hint::NONE, "MESH_VISUA");
349 mShader = Shader::New(SHADER_MESH_VISUAL_SIMPLE_SHADER_VERT, SHADER_MESH_VISUAL_SIMPLE_SHADER_FRAG, Shader::Hint::NONE, "MESH_VISUAL_SIMPLE");
352 UpdateShaderUniforms();
355 bool MeshVisual::CreateGeometry()
357 //Determine if we need to use a simpler shader to handle the provided data
358 if(!mUseTexture || !mObjLoader.IsDiffuseMapPresent())
360 mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING;
362 else if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING && (!mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent()))
364 mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING;
367 int objectProperties = 0;
369 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING ||
370 mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
372 objectProperties |= ObjLoader::TEXTURE_COORDINATES;
375 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
377 objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
380 //Create geometry with attributes required by shader.
381 mGeometry = mObjLoader.CreateGeometry(objectProperties, mUseSoftNormals);
388 DALI_LOG_ERROR("Failed to load geometry in mesh visual.\n");
392 bool MeshVisual::LoadGeometry()
394 std::streampos fileSize;
395 Dali::Vector<char> fileContent;
397 if(FileLoader::ReadFile(mObjectUrl, fileSize, fileContent, FileLoader::TEXT))
399 mObjLoader.ClearArrays();
400 mObjLoader.LoadObject(fileContent.Begin(), fileSize);
402 //Get size information from the obj loaded
403 mSceneCenter = mObjLoader.GetCenter();
404 mSceneSize = mObjLoader.GetSize();
409 DALI_LOG_ERROR("Failed to find object to load in mesh visual.\n");
413 bool MeshVisual::LoadMaterial()
415 std::streampos fileSize;
416 Dali::Vector<char> fileContent;
418 if(FileLoader::ReadFile(mMaterialUrl, fileSize, fileContent, FileLoader::TEXT))
420 //Load data into obj (usable) form
421 mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl);
425 DALI_LOG_ERROR("Failed to find texture set to load in mesh visual.\n");
430 bool MeshVisual::LoadTextures()
432 mTextureSet = TextureSet::New();
434 if(mShadingMode != Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING)
436 Sampler sampler = Sampler::New();
439 sampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR);
442 if(!mDiffuseTextureUrl.empty())
444 std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
447 Texture diffuseTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
450 mTextureSet.SetTexture(DIFFUSE_INDEX, diffuseTexture);
451 mTextureSet.SetSampler(DIFFUSE_INDEX, sampler);
455 DALI_LOG_ERROR("Failed to load diffuse map texture in mesh visual.\n");
460 if(!mNormalTextureUrl.empty() && (mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING))
462 std::string imageUrl = mTexturesPath + mNormalTextureUrl;
465 Texture normalTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
468 mTextureSet.SetTexture(NORMAL_INDEX, normalTexture);
469 mTextureSet.SetSampler(NORMAL_INDEX, sampler);
473 DALI_LOG_ERROR("Failed to load normal map texture in mesh visual.\n");
478 if(!mGlossTextureUrl.empty() && (mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING))
480 std::string imageUrl = mTexturesPath + mGlossTextureUrl;
483 Texture glossTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
486 mTextureSet.SetTexture(GLOSS_INDEX, glossTexture);
487 mTextureSet.SetSampler(GLOSS_INDEX, sampler);
491 DALI_LOG_ERROR("Failed to load gloss map texture in mesh visual.\n");
499 } // namespace Internal
501 } // namespace Toolkit