2 * Copyright (c) 2021 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>
40 * @brief Loads a texture from a file
41 * @param[in] imageUrl The url of the file
42 * @param[in] generateMipmaps Indicates whether to generate mipmaps for the texture
43 * @return A texture if loading succeeds, an empty handle otherwise
45 Texture LoadTexture(const char* imageUrl, bool generateMipmaps)
49 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(imageUrl);
52 texture = Texture::New(TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
53 PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
54 texture.Upload(pixelData);
58 texture.GenerateMipmaps();
64 } // unnamed namespace
72 //Defines ordering of textures for shaders.
73 //All shaders, if including certain texture types, must include them in the same order.
74 //Within the texture set for the renderer, textures are ordered in the same manner.
83 DALI_ENUM_TO_STRING_TABLE_BEGIN(SHADING_MODE)
84 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURELESS_WITH_DIFFUSE_LIGHTING)
85 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_SPECULAR_LIGHTING)
86 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
87 DALI_ENUM_TO_STRING_TABLE_END(SHADING_MODE)
90 const char* const OBJECT_MATRIX_UNIFORM_NAME("uObjectMatrix");
91 const char* const STAGE_OFFSET_UNIFORM_NAME("uStageOffset");
93 } // unnamed namespace
95 MeshVisualPtr MeshVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
97 MeshVisualPtr meshVisualPtr(new MeshVisual(factoryCache));
98 meshVisualPtr->SetProperties(properties);
99 meshVisualPtr->Initialize();
100 return meshVisualPtr;
103 MeshVisual::MeshVisual(VisualFactoryCache& factoryCache)
104 : Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::MESH),
105 mShadingMode(Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING),
107 mUseMipmapping(true),
108 mUseSoftNormals(true)
112 MeshVisual::~MeshVisual()
116 void MeshVisual::DoSetProperties(const Property::Map& propertyMap)
118 for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
120 KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
121 if(keyValue.first.type == Property::Key::INDEX)
123 DoSetProperty(keyValue.first.indexKey, keyValue.second);
127 if(keyValue.first == OBJECT_URL_NAME)
129 DoSetProperty(Toolkit::MeshVisual::Property::OBJECT_URL, keyValue.second);
131 else if(keyValue.first == MATERIAL_URL_NAME)
133 DoSetProperty(Toolkit::MeshVisual::Property::MATERIAL_URL, keyValue.second);
135 else if(keyValue.first == TEXTURES_PATH_NAME)
137 DoSetProperty(Toolkit::MeshVisual::Property::TEXTURES_PATH, keyValue.second);
139 else if(keyValue.first == SHADING_MODE_NAME)
141 DoSetProperty(Toolkit::MeshVisual::Property::SHADING_MODE, keyValue.second);
143 else if(keyValue.first == USE_MIPMAPPING_NAME)
145 DoSetProperty(Toolkit::MeshVisual::Property::USE_MIPMAPPING, keyValue.second);
147 else if(keyValue.first == USE_SOFT_NORMALS_NAME)
149 DoSetProperty(Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, keyValue.second);
151 else if(keyValue.first == LIGHT_POSITION_NAME)
153 DoSetProperty(Toolkit::MeshVisual::Property::LIGHT_POSITION, keyValue.second);
158 if(mMaterialUrl.empty())
163 if(mLightPosition == Vector3::ZERO)
165 // Default behaviour is to place the light directly in front of the object,
166 // at a reasonable distance to light everything on screen.
167 Stage stage = Stage::GetCurrent();
169 mLightPosition = Vector3(stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5);
173 void MeshVisual::DoSetProperty(Property::Index index, const Property::Value& value)
177 case Toolkit::MeshVisual::Property::OBJECT_URL:
179 if(!value.Get(mObjectUrl))
181 DALI_LOG_ERROR("MeshVisual: property objectUrl is the wrong type, use STRING\n");
185 case Toolkit::MeshVisual::Property::MATERIAL_URL:
187 if(!value.Get(mMaterialUrl))
189 DALI_LOG_ERROR("MeshVisual: property materialUrl is the wrong type, use STRING\n");
193 case Toolkit::MeshVisual::Property::TEXTURES_PATH:
195 if(!value.Get(mTexturesPath))
197 mTexturesPath.clear();
201 case Toolkit::MeshVisual::Property::SHADING_MODE:
203 Scripting::GetEnumerationProperty(value, SHADING_MODE_TABLE, SHADING_MODE_TABLE_COUNT, mShadingMode);
206 case Toolkit::MeshVisual::Property::USE_MIPMAPPING:
208 if(!value.Get(mUseMipmapping))
210 DALI_LOG_ERROR("MeshVisual: property useMipmapping is the wrong type, use BOOLEAN\n");
214 case Toolkit::MeshVisual::Property::USE_SOFT_NORMALS:
216 if(!value.Get(mUseSoftNormals))
218 DALI_LOG_ERROR("MeshVisual: property useSoftNormals is the wrong type, use BOOLEAN\n");
222 case Toolkit::MeshVisual::Property::LIGHT_POSITION:
224 if(!value.Get(mLightPosition))
226 mLightPosition = Vector3::ZERO;
227 DALI_LOG_ERROR("MeshVisual: property lightPosition is the wrong type, use VECTOR3\n");
234 void MeshVisual::OnSetTransform()
238 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
242 void MeshVisual::DoSetOnScene(Actor& actor)
244 actor.AddRenderer(mImpl->mRenderer);
246 // Mesh loaded and ready to display
247 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
250 void MeshVisual::DoCreatePropertyMap(Property::Map& map) const
253 map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::MESH);
254 map.Insert(Toolkit::MeshVisual::Property::OBJECT_URL, mObjectUrl);
255 map.Insert(Toolkit::MeshVisual::Property::MATERIAL_URL, mMaterialUrl);
256 map.Insert(Toolkit::MeshVisual::Property::TEXTURES_PATH, mTexturesPath);
257 map.Insert(Toolkit::MeshVisual::Property::SHADING_MODE, mShadingMode);
258 map.Insert(Toolkit::MeshVisual::Property::USE_MIPMAPPING, mUseMipmapping);
259 map.Insert(Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, mUseSoftNormals);
260 map.Insert(Toolkit::MeshVisual::Property::LIGHT_POSITION, mLightPosition);
263 void MeshVisual::DoCreateInstancePropertyMap(Property::Map& map) const
268 void MeshVisual::OnInitialize()
270 //Try to load the geometry from the file.
273 SupplyEmptyGeometry();
277 //If a texture is used by the obj file, load the supplied material file.
278 if(mObjLoader.IsTexturePresent() && !mMaterialUrl.empty())
282 SupplyEmptyGeometry();
287 //Now that the required parts are loaded, create the geometry for the object.
288 if(!CreateGeometry())
290 SupplyEmptyGeometry();
296 //Load the various texture files supplied by the material file.
299 SupplyEmptyGeometry();
303 mImpl->mRenderer = Renderer::New(mGeometry, mShader);
304 mImpl->mRenderer.SetTextures(mTextureSet);
305 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
306 mImpl->mRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
308 //Register transform properties
309 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
312 void MeshVisual::SupplyEmptyGeometry()
314 mGeometry = Geometry::New();
315 mShader = Shader::New(SHADER_MESH_VISUAL_SIMPLE_SHADER_VERT, SHADER_MESH_VISUAL_SIMPLE_SHADER_FRAG);
316 mImpl->mRenderer = Renderer::New(mGeometry, mShader);
318 DALI_LOG_ERROR("Initialisation error in mesh visual.\n");
321 void MeshVisual::UpdateShaderUniforms()
323 Stage stage = Stage::GetCurrent();
324 float width = stage.GetSize().width;
325 float height = stage.GetSize().height;
328 scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
330 mShader.RegisterProperty(STAGE_OFFSET_UNIFORM_NAME, Vector2(width, height) / 2.0f);
331 mShader.RegisterProperty(LIGHT_POSITION_NAME, mLightPosition);
332 mShader.RegisterProperty(OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix);
335 void MeshVisual::CreateShader()
337 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
339 mShader = Shader::New(SHADER_MESH_VISUAL_NORMAL_MAP_SHADER_VERT, SHADER_MESH_VISUAL_NORMAL_MAP_SHADER_FRAG);
341 else if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING)
343 mShader = Shader::New(SHADER_MESH_VISUAL_SHADER_VERT, SHADER_MESH_VISUAL_SHADER_FRAG);
347 mShader = Shader::New(SHADER_MESH_VISUAL_SIMPLE_SHADER_VERT, SHADER_MESH_VISUAL_SIMPLE_SHADER_FRAG);
350 UpdateShaderUniforms();
353 bool MeshVisual::CreateGeometry()
355 //Determine if we need to use a simpler shader to handle the provided data
356 if(!mUseTexture || !mObjLoader.IsDiffuseMapPresent())
358 mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING;
360 else if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING && (!mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent()))
362 mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING;
365 int objectProperties = 0;
367 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING ||
368 mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
370 objectProperties |= ObjLoader::TEXTURE_COORDINATES;
373 if(mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING)
375 objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
378 //Create geometry with attributes required by shader.
379 mGeometry = mObjLoader.CreateGeometry(objectProperties, mUseSoftNormals);
386 DALI_LOG_ERROR("Failed to load geometry in mesh visual.\n");
390 bool MeshVisual::LoadGeometry()
392 std::streampos fileSize;
393 Dali::Vector<char> fileContent;
395 if(FileLoader::ReadFile(mObjectUrl, fileSize, fileContent, FileLoader::TEXT))
397 mObjLoader.ClearArrays();
398 mObjLoader.LoadObject(fileContent.Begin(), fileSize);
400 //Get size information from the obj loaded
401 mSceneCenter = mObjLoader.GetCenter();
402 mSceneSize = mObjLoader.GetSize();
407 DALI_LOG_ERROR("Failed to find object to load in mesh visual.\n");
411 bool MeshVisual::LoadMaterial()
413 std::streampos fileSize;
414 Dali::Vector<char> fileContent;
416 if(FileLoader::ReadFile(mMaterialUrl, fileSize, fileContent, FileLoader::TEXT))
418 //Load data into obj (usable) form
419 mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl);
423 DALI_LOG_ERROR("Failed to find texture set to load in mesh visual.\n");
428 bool MeshVisual::LoadTextures()
430 mTextureSet = TextureSet::New();
432 if(mShadingMode != Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING)
434 Sampler sampler = Sampler::New();
437 sampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR);
440 if(!mDiffuseTextureUrl.empty())
442 std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
445 Texture diffuseTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
448 mTextureSet.SetTexture(DIFFUSE_INDEX, diffuseTexture);
449 mTextureSet.SetSampler(DIFFUSE_INDEX, sampler);
453 DALI_LOG_ERROR("Failed to load diffuse map texture in mesh visual.\n");
458 if(!mNormalTextureUrl.empty() && (mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING))
460 std::string imageUrl = mTexturesPath + mNormalTextureUrl;
463 Texture normalTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
466 mTextureSet.SetTexture(NORMAL_INDEX, normalTexture);
467 mTextureSet.SetSampler(NORMAL_INDEX, sampler);
471 DALI_LOG_ERROR("Failed to load normal map texture in mesh visual.\n");
476 if(!mGlossTextureUrl.empty() && (mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING))
478 std::string imageUrl = mTexturesPath + mGlossTextureUrl;
481 Texture glossTexture = LoadTexture(imageUrl.c_str(), mUseMipmapping);
484 mTextureSet.SetTexture(GLOSS_INDEX, glossTexture);
485 mTextureSet.SetSampler(GLOSS_INDEX, sampler);
489 DALI_LOG_ERROR("Failed to load gloss map texture in mesh visual.\n");
497 } // namespace Internal
499 } // namespace Toolkit