2 * Copyright (c) 2017 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 "model3d-view-impl.h"
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraint-source.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
28 #include <dali/public-api/images/resource-image.h>
29 #include <dali/devel-api/adaptor-framework/file-loader.h>
30 #include <dali/devel-api/adaptor-framework/image-loading.h>
33 #include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
34 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
48 // Texture indices are constants.
51 DIFFUSE_TEXTURE_INDEX,
57 * @brief Loads a texture from a file.
58 * @param[in] imageUrl The URL of the file
59 * @return A texture if loading succeeds, an empty handle otherwise
61 Texture LoadTexture( const char* imageUrl )
64 Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
67 texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
68 PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
69 texture.Upload( pixelData );
70 texture.GenerateMipmaps();
79 return Toolkit::Model3dView::New();
82 // Setup properties, signals and actions using the type-registry.
83 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Model3dView, Toolkit::Control, Create );
85 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometryUrl", STRING, GEOMETRY_URL)
86 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "materialUrl", STRING, MATERIAL_URL)
87 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "imagesUrl", STRING, IMAGES_URL)
88 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illuminationType", INTEGER, ILLUMINATION_TYPE)
89 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0Url", STRING, TEXTURE0_URL)
90 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1Url", STRING, TEXTURE1_URL)
91 DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2Url", STRING, TEXTURE2_URL)
93 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "lightPosition", VECTOR3, LIGHT_POSITION)
95 DALI_TYPE_REGISTRATION_END()
98 #define MAKE_SHADER(A)#A
100 // Diffuse illumination shader
102 const char* SIMPLE_VERTEX_SHADER = MAKE_SHADER(
103 attribute highp vec3 aPosition;\n
104 attribute highp vec2 aTexCoord;\n
105 attribute highp vec3 aNormal;\n
106 varying mediump vec3 vIllumination;\n
107 uniform mediump vec3 uSize;\n
108 uniform mediump mat4 uMvpMatrix;\n
109 uniform mediump mat4 uModelView;\n
110 uniform mediump mat3 uNormalMatrix;
111 uniform mediump mat4 uObjectMatrix;\n
112 uniform mediump vec3 uLightPosition;\n
116 vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
117 vertexPosition = uObjectMatrix * vertexPosition;\n
118 vertexPosition = uMvpMatrix * vertexPosition;\n
120 //Illumination in Model-View space - Transform attributes and uniforms\n
121 vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
122 vec3 normal = uNormalMatrix * aNormal;\n
123 vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
124 vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
126 float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
127 vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
129 gl_Position = vertexPosition;\n
133 const char* SIMPLE_FRAGMENT_SHADER = MAKE_SHADER(
134 precision mediump float;\n
135 varying mediump vec3 vIllumination;\n
136 uniform lowp vec4 uColor;\n
140 gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a);\n
144 // Diffuse and specular illumination shader with albedo texture
146 const char* VERTEX_SHADER = MAKE_SHADER(
147 attribute highp vec3 aPosition;\n
148 attribute highp vec2 aTexCoord;\n
149 attribute highp vec3 aNormal;\n
150 varying mediump vec2 vTexCoord;\n
151 varying mediump vec3 vIllumination;\n
152 varying mediump float vSpecular;\n
153 uniform mediump vec3 uSize;\n
154 uniform mediump mat4 uMvpMatrix;\n
155 uniform mediump mat4 uModelView;
156 uniform mediump mat3 uNormalMatrix;
157 uniform mediump mat4 uObjectMatrix;\n
158 uniform mediump vec3 uLightPosition;\n
162 vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
163 vertexPosition = uObjectMatrix * vertexPosition;\n
164 vertexPosition = uMvpMatrix * vertexPosition;\n
166 //Illumination in Model-View space - Transform attributes and uniforms\n
167 vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
168 vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
169 vec3 normal = normalize(uNormalMatrix * aNormal);\n
171 vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
172 vec3 viewDir = normalize(-vertPos.xyz);
174 vec3 halfVector = normalize(viewDir + vecToLight);
176 float lightDiffuse = dot( vecToLight, normal );\n
177 lightDiffuse = max(0.0,lightDiffuse);\n
178 vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
180 vec3 reflectDir = reflect(-vecToLight, normal);
181 vSpecular = pow( max(dot(reflectDir, viewDir), 0.0), 4.0 );
183 vTexCoord = aTexCoord;\n
184 gl_Position = vertexPosition;\n
188 const char* FRAGMENT_SHADER = MAKE_SHADER(
189 precision mediump float;\n
190 varying mediump vec2 vTexCoord;\n
191 varying mediump vec3 vIllumination;\n
192 varying mediump float vSpecular;\n
193 uniform sampler2D sDiffuse;\n
194 uniform lowp vec4 uColor;\n
198 vec4 texture = texture2D( sDiffuse, vTexCoord );\n
199 gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a);\n
203 // Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader
205 const char* NRMMAP_VERTEX_SHADER = MAKE_SHADER(
206 attribute highp vec3 aPosition;\n
207 attribute highp vec2 aTexCoord;\n
208 attribute highp vec3 aNormal;\n
209 attribute highp vec3 aTangent;\n
210 attribute highp vec3 aBiNormal;\n
211 varying mediump vec2 vTexCoord;\n
212 varying mediump vec3 vLightDirection;\n
213 varying mediump vec3 vHalfVector;\n
214 uniform mediump vec3 uSize;\n
215 uniform mediump mat4 uMvpMatrix;\n
216 uniform mediump mat4 uModelView;
217 uniform mediump mat3 uNormalMatrix;
218 uniform mediump mat4 uObjectMatrix;\n
219 uniform mediump vec3 uLightPosition;\n
223 vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
224 vertexPosition = uObjectMatrix * vertexPosition;\n
225 vertexPosition = uMvpMatrix * vertexPosition;\n
227 vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
228 vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
230 vec3 tangent = normalize(uNormalMatrix * aTangent);
231 vec3 binormal = normalize(uNormalMatrix * aBiNormal);
232 vec3 normal = normalize(uNormalMatrix * aNormal);
234 vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
235 vLightDirection.x = dot(vecToLight, tangent);
236 vLightDirection.y = dot(vecToLight, binormal);
237 vLightDirection.z = dot(vecToLight, normal);
239 vec3 viewDir = normalize(-vertPos.xyz);
240 vec3 halfVector = normalize(viewDir + vecToLight);
241 vHalfVector.x = dot(halfVector, tangent);
242 vHalfVector.y = dot(halfVector, binormal);
243 vHalfVector.z = dot(halfVector, normal);
245 vTexCoord = aTexCoord;\n
246 gl_Position = vertexPosition;\n
250 const char* NRMMAP_FRAGMENT_SHADER = MAKE_SHADER(
251 precision mediump float;\n
252 varying mediump vec2 vTexCoord;\n
253 varying mediump vec3 vLightDirection;\n
254 varying mediump vec3 vHalfVector;\n
255 uniform sampler2D sDiffuse;\n
256 uniform sampler2D sNormal;\n
257 uniform sampler2D sGloss;\n
258 uniform lowp vec4 uColor;\n
262 vec4 texture = texture2D( sDiffuse, vTexCoord );\n
263 vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
264 vec4 glossMap = texture2D( sGloss, vTexCoord );\n
266 float lightDiffuse = max( 0.0, dot( normal, normalize(vLightDirection) ) );\n
267 lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
269 float shininess = pow (max (dot (normalize( vHalfVector ), normal), 0.0), 16.0) ;
271 gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a);\n
276 } // anonymous namespace
278 using namespace Dali;
280 Model3dView::Model3dView()
281 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
283 mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
285 mCameraFOV = Math::PI_OVER_180 * 45.f;
287 mControlSize = Vector2(100.,100.);
289 DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
290 return std::unique_ptr< Dali::Accessibility::Accessible >(
291 new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::IMAGE ) );
295 Model3dView::~Model3dView()
299 Toolkit::Model3dView Model3dView::New()
301 Model3dView* impl = new Model3dView();
303 Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView( *impl );
305 // Second-phase init of the implementation
306 // This can only be done after the CustomActor connection has been made...
312 void Model3dView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
314 Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
318 Model3dView& impl( GetImpl( model3dView ) );
321 case Toolkit::Model3dView::Property::GEOMETRY_URL:
323 if( value.Get(impl.mObjUrl) )
326 impl.CreateGeometry();
330 case Toolkit::Model3dView::Property::MATERIAL_URL:
332 if( value.Get(impl.mTextureSetUrl) )
335 impl.CreateMaterial();
340 case Toolkit::Model3dView::Property::IMAGES_URL:
342 if( value.Get(impl.mImagesUrl) )
348 case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
350 int illuminationType;
351 if( value.Get(illuminationType) )
353 impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType);
354 impl.CreateGeometry();
355 impl.CreateMaterial();
360 case Toolkit::Model3dView::Property::TEXTURE0_URL:
362 value.Get(impl.mTexture0Url);
365 case Toolkit::Model3dView::Property::TEXTURE1_URL:
367 value.Get(impl.mTexture1Url);
370 case Toolkit::Model3dView::Property::TEXTURE2_URL:
372 value.Get(impl.mTexture2Url);
379 Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index index )
381 Property::Value value;
383 Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
387 Model3dView& impl( GetImpl( model3dView ) );
390 case Toolkit::Model3dView::Property::GEOMETRY_URL:
392 value = impl.mObjUrl;
395 case Toolkit::Model3dView::Property::MATERIAL_URL:
397 value = impl.mTextureSetUrl;
400 case Toolkit::Model3dView::Property::IMAGES_URL:
402 value = impl.mImagesUrl;
405 case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
407 value = int(impl.mIlluminationType);
410 case Toolkit::Model3dView::Property::TEXTURE0_URL:
412 value = impl.mTexture0Url;
415 case Toolkit::Model3dView::Property::TEXTURE1_URL:
417 value = impl.mTexture1Url;
420 case Toolkit::Model3dView::Property::TEXTURE2_URL:
422 value = impl.mTexture2Url;
431 /////////////////////////////////////////////////////////////
434 void Model3dView::OnStageConnection( int depth )
436 CustomActor self = Self();
437 self.AddRenderer( mRenderer );
439 if( mObjLoader.IsSceneLoaded() )
441 mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
446 mRenderer.SetGeometry( mMesh );
448 //create constraint for lightPosition Property with uLightPosition in the shader
449 Vector3 lightPosition( 0, 0, 0 );
450 Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
451 Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
452 constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
456 Control::OnStageConnection( depth );
459 ///////////////////////////////////////////////////////////
464 void Model3dView::OnInitialize()
466 //Create empty versions of the geometry and material so we always have a Renderer
467 Geometry mesh = Geometry::New();
468 Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
469 mRenderer = Renderer::New( mesh, shader );
473 void Model3dView::LoadGeometry()
475 //Load file in adaptor
476 std::streampos fileSize;
477 Dali::Vector<char> fileContent;
479 if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
481 mObjLoader.ClearArrays();
482 mObjLoader.LoadObject(fileContent.Begin(), fileSize);
484 //Get size information from the obj loaded
485 mSceneCenter = mObjLoader.GetCenter();
486 mSceneSize = mObjLoader.GetSize();
494 void Model3dView::LoadMaterial()
496 //Load file in adaptor
497 std::streampos fileSize;
498 Dali::Vector<char> fileContent;
500 if( FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT) )
502 mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
510 void Model3dView::Load()
516 void Model3dView::OnRelayout( const Vector2& size, RelayoutContainer& container )
521 void Model3dView::UpdateView()
523 if( mObjLoader.IsSceneLoaded() )
525 //The object will always be centred
528 scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
530 mShader.RegisterProperty( "uObjectMatrix", scaleMatrix );
534 void Model3dView::CreateGeometry()
536 if( mObjLoader.IsSceneLoaded() )
538 mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
542 mRenderer.SetGeometry( mMesh );
543 mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
544 mRenderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
549 void Model3dView::UpdateShaderUniforms()
553 //Update shader related info, uniforms, etc. for the new shader
556 Vector3 lightPosition( 0, 0, 0 );
557 Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
559 CustomActor self = Self();
561 //create constraint for lightPosition Property with uLightPosition in the shader
564 Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
565 constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
571 void Model3dView::CreateMaterial()
573 if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
575 if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
577 mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER );
579 else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
580 mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
582 mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
586 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
591 mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
594 mTextureSet = TextureSet::New();
598 mRenderer.SetTextures( mTextureSet );
599 mRenderer.SetShader( mShader );
600 mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
603 UpdateShaderUniforms();
606 void Model3dView::LoadTextures()
613 Sampler sampler = Sampler::New();
614 sampler.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR );
616 // Setup diffuse texture.
617 if( !mTexture0Url.empty() && ( mIlluminationType != Toolkit::Model3dView::DIFFUSE ) )
619 std::string imageUrl = mImagesUrl + mTexture0Url;
622 Texture diffuseTexture = LoadTexture( imageUrl.c_str() );
625 mTextureSet.SetTexture( DIFFUSE_TEXTURE_INDEX, diffuseTexture );
626 mTextureSet.SetSampler( DIFFUSE_TEXTURE_INDEX, sampler );
630 if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
632 // Setup normal map texture.
633 if( !mTexture1Url.empty() )
635 std::string imageUrl = mImagesUrl + mTexture1Url;
638 Texture normalTexture = LoadTexture( imageUrl.c_str() );
641 mTextureSet.SetTexture( NORMAL_TEXTURE_INDEX, normalTexture );
642 mTextureSet.SetSampler( NORMAL_TEXTURE_INDEX, sampler );
645 if( !mTexture2Url.empty() )
647 // Setup gloss map texture.
648 std::string imageUrl = mImagesUrl + mTexture2Url;
651 Texture glossTexture = LoadTexture( imageUrl.c_str() );
654 mTextureSet.SetTexture( GLOSS_TEXTURE_INDEX, glossTexture );
655 mTextureSet.SetSampler( GLOSS_TEXTURE_INDEX, sampler );
661 int Model3dView::GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType )
663 int objectProperties = 0;
665 if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
666 illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
668 objectProperties |= ObjLoader::TEXTURE_COORDINATES;
671 if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
673 objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
676 return objectProperties;
679 } // namespace Internal
680 } // namespace Toolkit