From: David Fumanal Date: Mon, 20 Jul 2015 13:33:50 +0000 (+0100) Subject: New control to load OBJ files X-Git-Tag: dali_1.1.0~4^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=f758f35a6f525b556a101b0785f797e3ee3c4b1a New control to load OBJ files Change-Id: I349f36808c8d2f521adab2a280167643e8d2206f --- diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 8f40f82..446bb36 100644 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -48,6 +48,7 @@ SET(TC_SOURCES utc-Dali-StyleManager.cpp utc-Dali-SuperBlurView.cpp utc-Dali-Toolkit.cpp + utc-Dali-Model3dView.cpp ) # Append list of test harness files (Won't get parsed for test cases) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp new file mode 100644 index 0000000..15737f4 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include + + +using namespace Dali; +using namespace Dali::Toolkit; + + +void model_view_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void model_view_cleanup(void) +{ + test_return_value = TET_PASS; +} + +namespace +{ +const char * TEST_OBJ_FILE_NAME = "Dino.obj"; +const char * TEST_MTL_FILE_NAME = "Dino.mtl"; +//const char * TEST_IMG_PATH = ""; +} + +// Negative test case for a method +int UtcDaliModelViewUninitialized(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliModel3dViewUninitialized"); + + Toolkit::Model3dView view; + + try + { + // New() must be called to create a Model3dView or it wont be valid. + Actor a = Actor::New(); + view.Add( a ); + DALI_TEST_CHECK( false ); + } + catch (Dali::DaliException& e) + { + // Tests that a negative test of an assertion succeeds + DALI_TEST_PRINT_ASSERT( e ); + DALI_TEST_CHECK(!view); + } + END_TEST; +} + +// Positive test case for a method +int UtcDaliModelViewNew(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliModel3dViewNew"); + + Toolkit::Model3dView view = Toolkit::Model3dView::New(); + DALI_TEST_CHECK( view ); + + Toolkit::Model3dView view2 = Toolkit::Model3dView::New("","",""); + DALI_TEST_CHECK( view2 ); + END_TEST; +} + +// Positive test case for a method +int UtcDaliModelViewDownCast(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliModelViewDownCast"); + + Toolkit::Model3dView view = Toolkit::Model3dView::New(); + BaseHandle handle(view); + + Toolkit::Model3dView modelView = Toolkit::Model3dView::DownCast( handle ); + DALI_TEST_CHECK( view ); + DALI_TEST_CHECK( modelView ); + DALI_TEST_CHECK( modelView == view ); + END_TEST; +} + + +// Positive test case for a method +int UtcDaliModelViewPropertyNames(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliModel3dViewPropertyNames"); + + Toolkit::Model3dView view = Toolkit::Model3dView::New(); + DALI_TEST_CHECK( view ); + + view.SetProperty( Model3dView::Property::GEOMETRY_URL, Dali::Property::Value( TEST_OBJ_FILE_NAME ) ); + Property::Value val = view.GetProperty( Model3dView::Property::GEOMETRY_URL ); + std::string obj_file_name; + DALI_TEST_CHECK( val.Get( obj_file_name ) ); + DALI_TEST_EQUALS( obj_file_name, TEST_OBJ_FILE_NAME, TEST_LOCATION ); + + view.SetProperty( Model3dView::Property::MATERIAL_URL, Dali::Property::Value( TEST_MTL_FILE_NAME ) ); + val = view.GetProperty( Model3dView::Property::MATERIAL_URL ); + DALI_TEST_CHECK( val.Get( obj_file_name ) ); + DALI_TEST_EQUALS( obj_file_name, TEST_MTL_FILE_NAME, TEST_LOCATION ); + + //modelView.SetProperty( Model3dView::Property::MTL_URL, Dali::Property::Value( mtlUrl ) ); + //modelView.SetProperty( Model3dView::Property::IMAGES_URL, Dali::Property::Value( imagesUrl ) ); + + END_TEST; +} + +// Positive test case for a method +int UtcDaliModelViewAddRemove(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliModel3dViewAddRemove"); + + Toolkit::Model3dView view = Toolkit::Model3dView::New(); + DALI_TEST_CHECK( view ); + + Actor actor = Actor::New(); + DALI_TEST_CHECK( !actor.OnStage() ); + + + view.SetParentOrigin(ParentOrigin::CENTER); + view.SetSize(Stage::GetCurrent().GetSize()); + view.Add(actor); + Stage::GetCurrent().Add(view); + + DALI_TEST_CHECK( actor.OnStage() ); + + view.Remove(actor); + + DALI_TEST_CHECK( !actor.OnStage() ); + END_TEST; +} + + +int UtcDaliModelCopyAndAssignment(void) +{ + ToolkitTestApplication application; + + Model3dView view = Toolkit::Model3dView::New(); + DALI_TEST_CHECK( view ); + + Model3dView copy( view ); + DALI_TEST_CHECK( view == copy ); + + Model3dView assign; + DALI_TEST_CHECK( ! assign ); + + assign = copy; + DALI_TEST_CHECK( assign == view ); + + END_TEST; +} + +int UtcDaliModelTypeRegistry(void) +{ + ToolkitTestApplication application; + + TypeRegistry typeRegistry = TypeRegistry::Get(); + DALI_TEST_CHECK( typeRegistry ); + + TypeInfo typeInfo = typeRegistry.GetTypeInfo( "Model3dView" ); + DALI_TEST_CHECK( typeInfo ); + + BaseHandle handle = typeInfo.CreateInstance(); + DALI_TEST_CHECK( handle ); + + Model3dView view = Model3dView::DownCast( handle ); + DALI_TEST_CHECK( view ); + + END_TEST; +} + +int UtcDaliModelOnSizeSet(void) +{ + ToolkitTestApplication application; + + Model3dView view = Toolkit::Model3dView::New(); + + Stage::GetCurrent().Add( view ); + + application.SendNotification(); + application.Render(); + + Vector3 size( 200.0f, 300.0f, 0.0f ); + view.SetSize( size ); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION ); + + END_TEST; +} diff --git a/build/tizen/dali-toolkit/Makefile.am b/build/tizen/dali-toolkit/Makefile.am index 3ec8f92..948b4cf 100644 --- a/build/tizen/dali-toolkit/Makefile.am +++ b/build/tizen/dali-toolkit/Makefile.am @@ -126,6 +126,7 @@ publicapibuttonsdir = $(publicapicontrolsdir)/buttons publicapidefaultcontrolsdir = $(publicapicontrolsdir)/default-controls publicapigaussianblurviewdir = $(publicapicontrolsdir)/gaussian-blur-view publicapiimageviewdir = $(publicapicontrolsdir)/image-view +publicapimodel3dviewdir = $(publicapicontrolsdir)/model3d-view publicapiscrollbardir = $(publicapicontrolsdir)/scroll-bar publicapiscrollabledir = $(publicapicontrolsdir)/scrollable publicapiscrollviewdir = $(publicapicontrolsdir)/scrollable/scroll-view @@ -145,6 +146,7 @@ publicapidefaultcontrols_HEADERS = $(public_api_default_controls_header_file publicapigaussianblurview_HEADERS = $(public_api_gaussian_blur_view_header_files) publicapiimageview_HEADERS = $(public_api_image_view_header_files) publicapiitemview_HEADERS = $(public_api_item_view_header_files) +publicapimodel3dview_HEADERS = $(public_api_model3d_view_header_files) publicapiscrollbar_HEADERS = $(public_api_scroll_bar_header_files) publicapiscrollable_HEADERS = $(public_api_scrollable_header_files) publicapiscrollview_HEADERS = $(public_api_scroll_view_header_files) diff --git a/dali-toolkit/dali-toolkit.h b/dali-toolkit/dali-toolkit.h index a8a3e1f..7f40633 100644 --- a/dali-toolkit/dali-toolkit.h +++ b/dali-toolkit/dali-toolkit.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp new file mode 100644 index 0000000..b8dfc75 --- /dev/null +++ b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "model3d-view-impl.h" + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace +{ + +// Type registration +BaseHandle Create() +{ + return Toolkit::Model3dView::New(); +} + +// Setup properties, signals and actions using the type-registry. +DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Model3dView, Toolkit::Control, Create ); + +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometry-url", STRING, GEOMETRY_URL) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "material-url", STRING, MATERIAL_URL) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "images-url", STRING, IMAGES_URL) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illumination-type", INTEGER, ILLUMINATION_TYPE) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0-url", STRING, TEXTURE0_URL) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1-url", STRING, TEXTURE1_URL) +DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2-url", STRING, TEXTURE2_URL) + +DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "light-position", VECTOR3, LIGHT_POSITION) + +DALI_TYPE_REGISTRATION_END() + + +#define MAKE_SHADER(A)#A + +// Diffuse illumination shader + +const char* SIMPLE_VERTEX_SHADER = MAKE_SHADER( + attribute highp vec3 aPosition;\n + attribute highp vec2 aTexCoord;\n + attribute highp vec3 aNormal;\n + varying mediump vec3 vIllumination;\n + uniform mediump vec3 uSize;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump mat4 uModelView;\n + uniform mediump mat3 uNormalMatrix; + uniform mediump mat4 uObjectMatrix;\n + uniform mediump vec3 uLightPosition;\n + \n + void main()\n + {\n + vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n + vertexPosition = uObjectMatrix * vertexPosition;\n + vertexPosition = uMvpMatrix * vertexPosition;\n + \n + //Illumination in Model-View space - Transform attributes and uniforms\n + vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n + vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n + \n + vec3 normalInterp = uNormalMatrix * aNormal;\n + \n + vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n + vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n + \n + vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n + \n + float lightDiffuse = dot( vecToLight, normalInterp );\n + lightDiffuse = max(0.0,lightDiffuse);\n + vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n + \n + gl_Position = vertexPosition;\n + }\n +); + +const char* SIMPLE_FRAGMENT_SHADER = MAKE_SHADER( + precision mediump float;\n + varying mediump vec3 vIllumination;\n + uniform lowp vec4 uColor;\n + \n + void main()\n + {\n + gl_FragColor.rgb = vIllumination.rgb * uColor.rgb;\n + gl_FragColor.a = uColor.a;\n + }\n +); + +// Diffuse and specular illumination shader with albedo texture + +const char* VERTEX_SHADER = MAKE_SHADER( + attribute highp vec3 aPosition;\n + attribute highp vec2 aTexCoord;\n + attribute highp vec3 aNormal;\n + varying mediump vec2 vTexCoord;\n + varying mediump vec3 vIllumination;\n + varying mediump float vSpecular;\n + uniform mediump vec3 uSize;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump mat4 uModelView; + uniform mediump mat3 uNormalMatrix; + uniform mediump mat4 uObjectMatrix;\n + uniform mediump vec3 uLightPosition;\n + \n + void main() + {\n + vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n + vertexPosition = uObjectMatrix * vertexPosition;\n + vertexPosition = uMvpMatrix * vertexPosition;\n + \n + //Illumination in Model-View space - Transform attributes and uniforms\n + vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n + vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n + \n + vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n + vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n + \n + vec3 normalInterp = normalize(uNormalMatrix * aNormal);\n + \n + vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n + vec3 viewDir = normalize(-vertPos); + \n + vec3 halfVector = normalize(viewDir + vecToLight); + \n + float lightDiffuse = dot( vecToLight, normalInterp );\n + lightDiffuse = max(0.0,lightDiffuse);\n + vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n + \n + // this is blinn phong + //float specAngle = max(dot(halfVector, normalInterp), 0.0);\n + //vSpecular = pow(specAngle, 16.0);\n + \n + // this is phong (for comparison) + vec3 reflectDir = reflect(-vecToLight, normalInterp); + float specAngle = max(dot(reflectDir, viewDir), 0.0); + // note that the exponent is different here + vSpecular = pow(specAngle, 16.0/4.0); + \n + vTexCoord = aTexCoord;\n + gl_Position = vertexPosition;\n + }\n +); + +const char* FRAGMENT_SHADER = MAKE_SHADER( + precision mediump float;\n + varying mediump vec2 vTexCoord;\n + varying mediump vec3 vIllumination;\n + varying mediump float vSpecular;\n + uniform sampler2D sDiffuse;\n + uniform lowp vec4 uColor;\n + \n + void main()\n + {\n + vec4 texture = texture2D( sDiffuse, vTexCoord );\n + gl_FragColor.rgb = vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3;\n + gl_FragColor.a = texture.a * uColor.a;\n + }\n +); + +// Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader + +const char* NRMMAP_VERTEX_SHADER = MAKE_SHADER( + attribute highp vec3 aPosition;\n + attribute highp vec2 aTexCoord;\n + attribute highp vec3 aNormal;\n + attribute highp vec3 aTangent;\n + attribute highp vec3 aBiNormal;\n + varying mediump vec2 vTexCoord;\n + varying mediump vec3 vLightDirection;\n + varying mediump vec3 vHalfVector;\n + uniform mediump vec3 uSize;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump mat4 uModelView; + uniform mediump mat3 uNormalMatrix; + uniform mediump mat4 uObjectMatrix;\n + uniform mediump vec3 uLightPosition;\n + \n + void main() + {\n + vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n + vertexPosition = uObjectMatrix * vertexPosition;\n + vertexPosition = uMvpMatrix * vertexPosition;\n + \n + vTexCoord = aTexCoord;\n + \n + vec3 vNormal = normalize(uNormalMatrix * aNormal);\n + vec3 vTangent = normalize(uNormalMatrix * aTangent);\n + vec3 vBiNormal = normalize(uNormalMatrix * aBiNormal);\n + \n + vec4 vertPos4 = uModelView * vec4(aPosition.xyz, 1.0);\n + vec3 vertPos = vec3(vertPos4) / vertPos4.w;\n + \n + vec4 lightPos4 = uModelView * vec4(uLightPosition, 1.0);\n + vec3 lightPos = vec3(lightPos4) / lightPos4.w;\n + \n + vec3 vecToLight = lightPos - vertPos; + vLightDirection.x = dot(vecToLight, vTangent); + vLightDirection.y = dot(vecToLight, vBiNormal); + vLightDirection.z = dot(vecToLight, vNormal); + vLightDirection = normalize(vLightDirection); + \n + vec3 viewDir = normalize(vertPos); + \n + vec3 halfVector = normalize(viewDir + vecToLight); + vHalfVector.x = dot (halfVector, vTangent); + vHalfVector.y = dot (halfVector, vBiNormal); + vHalfVector.z = dot (halfVector, vNormal); + \n + gl_Position = vertexPosition;\n + + //vHalfVector = aTangent; + }\n +); + +const char* NRMMAP_FRAGMENT_SHADER = MAKE_SHADER( + precision mediump float;\n + varying mediump vec2 vTexCoord;\n + varying mediump vec3 vLightDirection;\n + varying mediump vec3 vHalfVector;\n + uniform sampler2D sDiffuse;\n + uniform sampler2D sNormal;\n + uniform sampler2D sGloss;\n + uniform lowp vec4 uColor;\n + \n + void main()\n + {\n + vec4 texture = texture2D( sDiffuse, vTexCoord );\n + vec4 nrmMap = texture2D( sNormal, vTexCoord ) * 2.0 - 1.0;\n + vec4 glossMap = texture2D( sGloss, vTexCoord );\n + \n + vec3 normalizedLightDirection = normalize(vLightDirection);\n + float lightDiffuse = max( 0.0, dot( nrmMap.xyz, normalizedLightDirection ) );\n + lightDiffuse = lightDiffuse * 0.5 + 0.5;\n + \n + float shininess = pow (max (dot (vHalfVector, nrmMap.xyz), 0.0), 16.0) ; + \n + gl_FragColor.rgb = texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb;\n + gl_FragColor.a = texture.a * uColor.a;\n + + //gl_FragColor.rgb = vHalfVector.rgb; + }\n +); + + +} // anonymous namespace + +using namespace Dali; + +void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up) +{ + Vector3 vZ = target - eye; + vZ.Normalize(); + + Vector3 vX = up.Cross(vZ); + vX.Normalize(); + + Vector3 vY = vZ.Cross(vX); + vY.Normalize(); + + result.SetInverseTransformComponents(vX, vY, vZ, eye); +} + + +Model3dView::Model3dView() + : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ) +{ + mTexture0Url = ""; + mTexture1Url = ""; + mTexture2Url = ""; + + mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP; + + mCameraFOV = Math::PI_OVER_180 * 45.f; + + mControlSize = Vector2(100.,100.); +} + +Model3dView::~Model3dView() +{ +} + +Toolkit::Model3dView Model3dView::New() +{ + Model3dView* impl = new Model3dView(); + + Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView( *impl ); + + // Second-phase init of the implementation + // This can only be done after the CustomActor connection has been made... + impl->Initialize(); + + return handle; +} + +void Model3dView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) +{ + Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) ); + + if( model3dView ) + { + Model3dView& impl( GetImpl( model3dView ) ); + switch( index ) + { + case Toolkit::Model3dView::Property::GEOMETRY_URL: + { + if( value.Get(impl.mObjUrl) ) + { + impl.LoadGeometry(); + impl.CreateGeometry(); + } + break; + } + case Toolkit::Model3dView::Property::MATERIAL_URL: + { + if( value.Get(impl.mMaterialUrl) ) + { + impl.LoadMaterial(); + impl.CreateMaterial(); + } + break; + } + case Toolkit::Model3dView::Property::IMAGES_URL: + { + if( value.Get(impl.mImagesUrl) ) + { + impl.LoadTextures(); + } + break; + } + case Toolkit::Model3dView::Property::ILLUMINATION_TYPE: + { + int illuminationType; + if( value.Get(illuminationType) ) + { + impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType); + impl.CreateGeometry(); + impl.CreateMaterial(); + impl.LoadTextures(); + } + break; + } + case Toolkit::Model3dView::Property::TEXTURE0_URL: + { + value.Get(impl.mTexture0Url); + break; + } + case Toolkit::Model3dView::Property::TEXTURE1_URL: + { + value.Get(impl.mTexture1Url); + break; + } + case Toolkit::Model3dView::Property::TEXTURE2_URL: + { + value.Get(impl.mTexture2Url); + break; + } + } + } +} + +Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index index ) +{ + Property::Value value; + + Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) ); + + if( model3dView ) + { + Model3dView& impl( GetImpl( model3dView ) ); + switch( index ) + { + case Toolkit::Model3dView::Property::GEOMETRY_URL: + { + value = impl.mObjUrl; + break; + } + case Toolkit::Model3dView::Property::MATERIAL_URL: + { + value = impl.mMaterialUrl; + break; + } + case Toolkit::Model3dView::Property::IMAGES_URL: + { + value = impl.mImagesUrl; + break; + } + case Toolkit::Model3dView::Property::ILLUMINATION_TYPE: + { + value = int(impl.mIlluminationType); + break; + } + case Toolkit::Model3dView::Property::TEXTURE0_URL: + { + value = impl.mTexture0Url; + break; + } + case Toolkit::Model3dView::Property::TEXTURE1_URL: + { + value = impl.mTexture1Url; + break; + } + case Toolkit::Model3dView::Property::TEXTURE2_URL: + { + value = impl.mTexture2Url; + break; + } + } + } + + return value; +} + +///////////////////////////////////////////////////////////// + + +void Model3dView::OnStageConnection( int depth ) +{ + CustomActor self = Self(); + self.AddRenderer( mRenderer ); + + if( mObjLoader.IsSceneLoaded() ) + { + mMesh = mObjLoader.CreateGeometry(mIlluminationType); + + CreateMaterial(); + LoadTextures(); + + mRenderer.SetGeometry( mMesh ); + + //create constraint for lightPosition Property with uLightPosition in the shader + Vector3 lightPosition( 0, 0, 0 ); + Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition ); + Constraint constraint = Constraint::New( mShader, lightProperty, EqualToConstraint() ); + constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) ); + constraint.Apply(); + } +} + +/////////////////////////////////////////////////////////// +// +// Private methods +// + +void Model3dView::OnInitialize() +{ + //Create empty versions of the geometry and material so we always have a Renderer + Geometry mesh = Geometry::New(); + Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) ); + Material material = Material::New( shader ); + mRenderer = Renderer::New( mesh, material ); +} + +void Model3dView::LoadGeometry() +{ + //Load file in adaptor + std::streampos fileSize; + Dali::Vector fileContent; + + if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT)) + { + mObjLoader.ClearArrays(); + + std::string materialUrl; + mObjLoader.Load(fileContent.Begin(), fileSize, materialUrl); + + //Get size information from the obj loaded + mSceneCenter = mObjLoader.GetCenter(); + mSceneSize = mObjLoader.GetSize(); + } + else + { + //Error + } +} + +void Model3dView::LoadMaterial() +{ + //Load file in adaptor + std::streampos fileSize; + Dali::Vector fileContent; + + if( FileLoader::ReadFile(mMaterialUrl, fileSize, fileContent, FileLoader::TEXT) ) + { + mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url); + } + else + { + //Error + } +} + +void Model3dView::Load() +{ + LoadGeometry(); + LoadMaterial(); +} + +void Model3dView::OnRelayout( const Vector2& size, RelayoutContainer& container ) +{ + UpdateView(); +} + +void Model3dView::UpdateView() +{ + if( mObjLoader.IsSceneLoaded() ) + { + //The object will always be centred + + Matrix scaleMatrix; + scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0)); + + mShader.RegisterProperty( "uObjectMatrix", scaleMatrix ); + } +} + +void Model3dView::CreateGeometry() +{ + if( mObjLoader.IsSceneLoaded() ) + { + mMesh = mObjLoader.CreateGeometry(mIlluminationType); + + if( mRenderer ) + { + mRenderer.SetGeometry( mMesh ); + } + } +} + +void Model3dView::UpdateShaderUniforms() +{ + if( mShader ) + { + //Update shader related info, uniforms, etc. for the new shader + UpdateView(); + + Vector3 lightPosition( 0, 0, 0 ); + Dali::Property::Index lightProperty = mShader.RegisterProperty( "lightPosition", lightPosition ); + + CustomActor self = Self(); + + //create constraint for lightPosition Property with uLightPosition in the shader + if( lightProperty ) + { + Constraint constraint = Constraint::New( mShader, lightProperty, EqualToConstraint() ); + constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) ); + constraint.Apply(); + } + } +} + +void Model3dView::CreateMaterial() +{ + if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "")) + { + if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP)) + { + mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) ); + } + else if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE) + { + mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) ); + } + else + { + mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) ); + } + } + else + { + mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) ); + } + + mMaterial = Material::New( mShader ); + + mMaterial.SetFaceCullingMode(Material::NONE); + + if( mRenderer ) + { + mRenderer.SetMaterial( mMaterial ); + } + + UpdateShaderUniforms(); +} + +void Model3dView::LoadTextures() +{ + if( !mMaterial ) + return ; + + if( mTexture0Url != "" ) + { + std::string imgUrl = mImagesUrl + mTexture0Url; + + //Load textures + Image tex0 = ResourceImage::New( imgUrl ); + if( tex0 ) + { + Sampler sampler = Sampler::New( tex0, "sDiffuse" ); + sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT); + sampler.SetAffectsTransparency(false); + + mMaterial.AddSampler( sampler ); + } + } + + if( (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) ) + { + std::string imgUrl = mImagesUrl + mTexture1Url; + + //Load textures + Image tex1 = ResourceImage::New( imgUrl ); + if (tex1) + { + Sampler sampler = Sampler::New( tex1, "sNormal" ); + sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT); + sampler.SetAffectsTransparency(false); + sampler.SetFilterMode(Sampler::LINEAR,Sampler::LINEAR); + + mMaterial.AddSampler( sampler ); + } + } + + if( (mTexture2Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) ) + { + std::string imgUrl = mImagesUrl + mTexture2Url; + + //Load textures + Image tex2 = ResourceImage::New( imgUrl ); + if( tex2 ) + { + Sampler sampler = Sampler::New( tex2, "sGloss" ); + sampler.SetWrapMode(Sampler::REPEAT,Sampler::REPEAT); + sampler.SetAffectsTransparency(false); + sampler.SetFilterMode(Sampler::LINEAR,Sampler::LINEAR); + + mMaterial.AddSampler( sampler ); + } + } +} + +} // namespace Internal +} // namespace Toolkit +} // namespace Dali diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h new file mode 100644 index 0000000..2202409 --- /dev/null +++ b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h @@ -0,0 +1,195 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_MODEL3D_VIEW_H__ +#define __DALI_TOOLKIT_INTERNAL_MODEL3D_VIEW_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +class Model3dView; + +namespace Internal +{ +/** + * @brief Impl class for Model3dView. + * + * All the geometry loaded with the control is automatically centered and scaled to fit + * the size of all the other controls. So the max is (0.5,0.5) and the min is (-0.5,-0.5) +*/ +class Model3dView : public Control +{ +public: + + /** + * @brief Create a new Model3dView. + * + * @return A public handle to the newly allocated Model3dView. + */ + static Toolkit::Model3dView New(); + + // Properties + + /** + * @brief Called when a property of an object of this type is set. + * + * @param[in] object The object whose property is set. + * @param[in] index The property index. + * @param[in] value The new property value. + */ + static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ); + + /** + * @brief Called to retrieve a property of an object of this type. + * + * @param[in] object The object whose property is to be retrieved. + * @param[in] index The property index. + * @return The current value of the property. + */ + static Property::Value GetProperty( BaseObject* object, Property::Index index ); + + /** + * @copydoc Control::OnRelayout + */ + virtual void OnRelayout( const Vector2& size, RelayoutContainer& container ); + + /** + * @brief Called to load both geometry (.obj) and material (.mtl) files + * + */ + void Load(); + +protected: + + /** + * @brief Construct a new Model3dView. + */ + Model3dView(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + virtual ~Model3dView(); + +private: + + /** + * @copydoc Toolkit::Control::OnInitialize() + */ + virtual void OnInitialize(); + + /** + * @copydoc CustomActorImpl::OnStageConnection() + */ + virtual void OnStageConnection( int depth ); + +private: + + /** + * @brief Load geometry (.obj) from file + */ + void LoadGeometry(); + + /** + * @brief Load material (.mtl) from file + */ + void LoadMaterial(); + + /** + * @brief Create Geometry class from the loaded geometry + */ + void CreateGeometry(); + + /** + * @brief Create Material and Shader classes from the loaded material + */ + void CreateMaterial(); + + /** + * @brief Load samplers and add them to Material + */ + void LoadTextures(); + + /** + * @brief Set matrix to shader to orientate geometry + */ + void UpdateView(); + + /** + * @brief Update shader uniforms + */ + void UpdateShaderUniforms(); + + + ObjLoader mObjLoader; + + //Properties + std::string mObjUrl; + std::string mMaterialUrl; + std::string mImagesUrl; + std::string mTexture0Url; + std::string mTexture1Url; + std::string mTexture2Url; + Vector3 mLightPosition; + float mCameraFOV; + Toolkit::Model3dView::IlluminationType mIlluminationType; + + //Size + Vector2 mControlSize; + Vector3 mSceneCenter; + Vector3 mSceneSize; + + //Render members + Shader mShader; + Material mMaterial; + Geometry mMesh; + Renderer mRenderer; +}; + +} // namespace Internal + +// Helpers for public-api forwarding methods +inline Toolkit::Internal::Model3dView& GetImpl( Toolkit::Model3dView& obj ) +{ + DALI_ASSERT_ALWAYS(obj); + Dali::RefObject& handle = obj.GetImplementation(); + return static_cast(handle); +} + +inline const Toolkit::Internal::Model3dView& GetImpl( const Toolkit::Model3dView& obj ) +{ + DALI_ASSERT_ALWAYS(obj); + const Dali::RefObject& handle = obj.GetImplementation(); + return static_cast(handle); +} + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_INTERNAL_MODEL_VIEW_H__ diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp b/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp new file mode 100644 index 0000000..c950b9d --- /dev/null +++ b/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "obj-loader.h" + +// EXTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +using namespace Dali; + +ObjLoader::ObjLoader() +{ + mSceneLoaded = false; + mMaterialLoaded = false; + mSceneAABB.Init(); +} + +ObjLoader::~ObjLoader() +{ + ClearArrays(); +} + +bool ObjLoader::IsSceneLoaded() +{ + return mSceneLoaded; +} + +bool ObjLoader::IsMaterialLoaded() +{ + return mMaterialLoaded; +} + +//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle) +void ObjLoader::CalculateTangentArray(const Dali::Vector& vertex, + const Dali::Vector& texcoord, + Dali::Vector& triangle, + Dali::Vector& normal, + Dali::Vector& tangent) +{ + normal.Clear(); + normal.Resize(vertex.Size()); + + Vector3 *tan1 = new Vector3[vertex.Size() * 2]; + + memset(tan1, 0, normal.Size() * sizeof(Vector3) * 2); + memset(&normal[0], 0, normal.Size() * sizeof(Vector3) * 2); + + for (unsigned long a = 0; a < triangle.Size(); a++) + { + Vector3 Tangent, Bitangent, Normal; + + const Vector3& v0 = vertex[triangle[a].pntIndex[0]]; + const Vector3& v1 = vertex[triangle[a].pntIndex[1]]; + const Vector3& v2 = vertex[triangle[a].pntIndex[2]]; + + Vector3 Edge1 = v1 - v0; + Vector3 Edge2 = v2 - v0; + + Normal = Edge1.Cross(Edge2); + + const Vector2& w0 = texcoord[triangle[a].texIndex[0]]; + const Vector2& w1 = texcoord[triangle[a].texIndex[1]]; + const Vector2& w2 = texcoord[triangle[a].texIndex[2]]; + + float DeltaU1 = w1.x - w0.x; + float DeltaV1 = w1.y - w0.y; + float DeltaU2 = w2.x - w0.x; + float DeltaV2 = w2.y - w0.y; + + float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1); + + Tangent.x = f * (DeltaV2 * Edge1.x - DeltaV1 * Edge2.x); + Tangent.y = f * (DeltaV2 * Edge1.y - DeltaV1 * Edge2.y); + Tangent.z = f * (DeltaV2 * Edge1.z - DeltaV1 * Edge2.z); + + tan1[triangle[a].pntIndex[0]] += Tangent; + tan1[triangle[a].pntIndex[1]] += Tangent; + tan1[triangle[a].pntIndex[2]] += Tangent; + + normal[triangle[a].pntIndex[0]] += Normal; + normal[triangle[a].pntIndex[1]] += Normal; + normal[triangle[a].pntIndex[2]] += Normal; + } + + for (unsigned long a = 0; a < triangle.Size(); a++) + { + for (unsigned long j = 0; j < 3; j++) + { + triangle[a].nrmIndex[j] = triangle[a].pntIndex[j]; + } + } + + for (unsigned long a = 0; a < normal.Size(); a++) + { + normal[a].Normalize(); + + const Vector3& n = normal[a]; + const Vector3& t = tan1[a]; + + // Gram-Schmidt orthogonalize + Vector3 calc = t - n * n.Dot(t); + calc.Normalize(); + tangent[a] = Vector3(calc.x,calc.y,calc.z); + } + + delete[] tan1; +} + + +void ObjLoader::CenterAndScale(bool center, Dali::Vector& points) +{ + BoundingVolume newAABB; + + Vector3 sceneSize = GetSize(); + + float biggestDimension = sceneSize.x; + if( sceneSize.y > biggestDimension ) + { + biggestDimension = sceneSize.y; + } + if( sceneSize.z > biggestDimension ) + { + biggestDimension = sceneSize.z; + } + + + newAABB.Init(); + for( unsigned int ui = 0; ui < points.Size(); ++ui) + { + points[ui] = points[ui] - GetCenter(); + points[ui] = points[ui] / biggestDimension; + newAABB.ConsiderNewPointInVolume(points[ui]); + } + + mSceneAABB = newAABB; +} + +void ObjLoader::CreateGeometryArray(Dali::Vector & vertices, + Dali::Vector & textures, + Dali::Vector & verticesExt, + Dali::Vector & indices) +{ + //If we don't have tangents, calculate them + //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex + //TODO: Use a better function to calculate tangents + if( mTangents.Size() == 0 ) + { + mTangents.Resize(mNormals.Size()); + mBiTangents.Resize(mNormals.Size()); + CalculateTangentArray(mPoints, mTextures, mTriangles, mNormals, mTangents); + for (unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui ) + { + mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]); + } + } + + //Check the number of points textures and normals + if ((mPoints.Size() == mTextures.Size()) && (mTextures.Size() == mNormals.Size())) + { + //We create the vertices array. For now we just copy points info + for (unsigned int ui = 0 ; ui < mPoints.Size() ; ++ui ) + { + Vertex vertex; + vertex.position = mPoints[ui]; + vertices.PushBack(vertex); + + textures.PushBack(Vector2()); + verticesExt.PushBack(VertexExt()); + } + + //We copy the indices + for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui ) + { + for (int j = 0 ; j < 3 ; ++j) + { + indices.PushBack(mTriangles[ui].pntIndex[j]); + + vertices[mTriangles[ui].pntIndex[j]].normal = mNormals[mTriangles[ui].nrmIndex[j]]; + + textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]]; + + verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]]; + verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]]; + } + } + } + else + { + //We have to normalize the arrays so we can draw we just one index array + for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui ) + { + for (int j = 0 ; j < 3 ; ++j) + { + Vertex vertex; + vertex.position = mPoints[mTriangles[ui].pntIndex[j]]; + vertex.normal = mNormals[mTriangles[ui].nrmIndex[j]]; + vertices.PushBack(vertex); + + textures.PushBack(mTextures[mTriangles[ui].texIndex[j]]); + + VertexExt vertexExt; + vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]]; + vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]]; + verticesExt.PushBack(vertexExt); + } + } + } +} + +bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& materialFile) +{ + Vector3 point; + Vector2 texture; + std::string vet[4], name; + int ptIdx[4]; + int nrmIdx[4]; + int texIdx[4]; + TriIndex triangle,triangle2; + int pntAcum = 0, texAcum = 0, nrmAcum = 0; + bool iniObj = false; + int face = 0; + + //Init AABB for the file + mSceneAABB.Init(); + + std::string strMatActual; + + std::string input = objBuffer; + std::istringstream ss(input); + ss.imbue(std::locale("C")); + + + std::string line; + std::getline(ss, line); + + while (std::getline(ss, line)) + { + std::istringstream isline(line, std::istringstream::in); + std::string tag; + + isline >> tag; + + if (tag == "v") + { + //Two different objects in the same file + isline >> point.x; + isline >> point.y; + isline >> point.z; + mPoints.PushBack(point); + + mSceneAABB.ConsiderNewPointInVolume(point); + } + else if (tag == "vn") + { + isline >> point.x; + isline >> point.y; + isline >> point.z; + + mNormals.PushBack(point); + } + else if (tag == "#_#tangent") + { + isline >> point.x; + isline >> point.y; + isline >> point.z; + + mTangents.PushBack(point); + } + else if (tag == "#_#binormal") + { + isline >> point.x; + isline >> point.y; + isline >> point.z; + + mBiTangents.PushBack(point); + } + else if (tag == "vt") + { + isline >> texture.x; + isline >> texture.y; + + texture.y = 1.0-texture.y; + mTextures.PushBack(texture); + } + else if (tag == "#_#vt1") + { + isline >> texture.x; + isline >> texture.y; + + texture.y = 1.0-texture.y; + mTextures2.PushBack(texture); + } + else if (tag == "s") + { + } + else if (tag == "f") + { + if (!iniObj) + { + //name assign + + iniObj = true; + } + + int numIndices = 0; + while( isline >> vet[numIndices] ) + { + numIndices++; + } + + char separator; + char separator2; + //File could not have texture Coordinates + if (strstr(vet[0].c_str(),"//")) + { + for( int i = 0 ; i < numIndices; i++) + { + std::istringstream isindex(vet[i]); + isindex >> ptIdx[i] >> separator >> nrmIdx[i]; + texIdx[i] = 0; + } + } + else if (strstr(vet[0].c_str(),"/")) + { + for( int i = 0 ; i < numIndices; i++) + { + std::istringstream isindex(vet[i]); + isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i]; + } + } + else + { + for( int i = 0 ; i < numIndices; i++) + { + std::istringstream isindex(vet[i]); + isindex >> ptIdx[i]; + texIdx[i] = 0; + nrmIdx[i] = 0; + } + } + + //If it is a triangle + if( numIndices == 3 ) + { + for( int i = 0 ; i < 3; i++) + { + triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum; + triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum; + triangle.texIndex[i] = texIdx[i] - 1 - texAcum; + } + mTriangles.PushBack(triangle); + face++; + } + //If on the other hand it is a quad, we will create two triangles + else if( numIndices == 4 ) + { + for( int i = 0 ; i < 3; i++) + { + triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum; + triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum; + triangle.texIndex[i] = texIdx[i] - 1 - texAcum; + } + mTriangles.PushBack(triangle); + face++; + + for( int i = 0 ; i < 3; i++) + { + int idx = (i+2) % numIndices; + triangle2.pntIndex[i] = ptIdx[idx] - 1 - pntAcum; + triangle2.nrmIndex[i] = nrmIdx[idx] - 1 - nrmAcum; + triangle2.texIndex[i] = texIdx[idx] - 1 - texAcum; + } + mTriangles.PushBack(triangle2); + face++; + } + } + else if (tag == "usemtl") + { + isline >> strMatActual; + } + else if (tag == "mtllib") + { + isline >> strMatActual; + } + else if (tag == "g") + { + isline >> name; + } + else + { + } + } + + if (iniObj) + { + pntAcum += (int)mPoints.Size(); + texAcum += (int)mTextures.Size(); + nrmAcum += (int)mNormals.Size(); + + CenterAndScale(true, mPoints); + + face = 0; + + mSceneLoaded = true; + + return true; + } + + return false; + +} + +void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url) +{ + float fR,fG,fB; + + std::string info; + + std::string input = objBuffer; + std::istringstream ss(input); + ss.imbue(std::locale("C")); + + std::string line; + std::getline(ss, line); + + while (std::getline(ss, line)) + { + std::istringstream isline(line, std::istringstream::in); + std::string tag; + + isline >> tag; + + if (tag == "newmtl") //name of the material + { + isline >> info; + } + else if (tag == "Kd") //diffuse color + { + isline >> fR >> fG >> fB; + } + else if (tag == "Kd") //Ambient color + { + isline >> fR >> fG >> fB; + } + else if (tag == "Tf") //color + { + } + else if (tag == "Ni") + { + } + else if (tag == "map_Kd") + { + isline >> info; + texture0Url = info; + } + else if (tag == "bump") + { + isline >> info; + texture1Url = info; + } + else if (tag == "map_Ks") + { + isline >> info; + texture2Url = info; + } + } + + mMaterialLoaded = true; +} + +Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType) +{ + Dali::Vector vertices; + Dali::Vector textures; + Dali::Vector verticesExt; + Dali::Vector indices; + + CreateGeometryArray(vertices, textures, verticesExt, indices); + + //All vertices need at least Position and Normal + Property::Map vertexFormat; + vertexFormat["aPosition"] = Property::VECTOR3; + vertexFormat["aNormal"] = Property::VECTOR3; + PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat, vertices.Size() ); + surfaceVertices.SetData( &vertices[0] ); + + Geometry surface = Geometry::New(); + surface.AddVertexBuffer( surfaceVertices ); + + //Some need texture coordinates + if( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) || (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) ) + { + Property::Map textureFormat; + textureFormat["aTexCoord"] = Property::VECTOR2; + PropertyBuffer extraVertices = PropertyBuffer::New( textureFormat, textures.Size() ); + extraVertices.SetData( &textures[0] ); + + surface.AddVertexBuffer( extraVertices ); + } + + //Some need tangent and bitangent + if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) + { + Property::Map vertexExtFormat; + vertexExtFormat["aTangent"] = Property::VECTOR3; + vertexExtFormat["aBiNormal"] = Property::VECTOR3; + PropertyBuffer extraVertices = PropertyBuffer::New( vertexExtFormat, verticesExt.Size() ); + extraVertices.SetData( &verticesExt[0] ); + + surface.AddVertexBuffer( extraVertices ); + } + + if (indices.Size()) + { + //Indices + Property::Map indicesVertexFormat; + indicesVertexFormat["aIndices"] = Property::INTEGER; + PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, indices.Size() ); + indicesToVertices.SetData(&indices[0]); + + surface.SetIndexBuffer ( indicesToVertices ); + } + + surface.SetRequiresDepthTesting(true); + //surface.SetProperty(Geometry::Property::GEOMETRY_HALF_EXTENTS, GetSize() * 0.5); + + vertices.Clear(); + verticesExt.Clear(); + indices.Clear(); + + return surface; +} + +Vector3 ObjLoader::GetCenter() +{ + Vector3 center = GetSize() * 0.5 + mSceneAABB.pointMin; + return center; +} + +Vector3 ObjLoader::GetSize() +{ + Vector3 size = mSceneAABB.pointMax - mSceneAABB.pointMin; + return size; +} + +void ObjLoader::ClearArrays() +{ + mPoints.Clear(); + mTextures.Clear(); + mNormals.Clear(); + mTangents.Clear(); + mBiTangents.Clear(); + + mTriangles.Clear(); + + mSceneLoaded = false; +} + +} // namespace Internal +} // namespace Toolkit +} // namespace Dali diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.h b/dali-toolkit/internal/controls/model3d-view/obj-loader.h new file mode 100644 index 0000000..eac63c3 --- /dev/null +++ b/dali-toolkit/internal/controls/model3d-view/obj-loader.h @@ -0,0 +1,157 @@ +#ifndef __DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H__ +#define __DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + + +namespace Dali +{ + +namespace Toolkit +{ + +class ObjLoader; + +namespace Internal +{ +class ObjLoader +{ +public: + + struct TriIndex + { + int pntIndex[3]; + int nrmIndex[3]; + int texIndex[3]; + }; + + struct Vertex + { + Vertex() + {} + + Vertex( const Vector3& position, const Vector3& normal, const Vector2& textureCoord ) + : position( position ), normal( normal ) + {} + + Vector3 position; + Vector3 normal; + }; + + struct VertexExt + { + VertexExt() + {} + + VertexExt( const Vector3& tangent, const Vector3& binormal ) + : tangent( tangent), bitangent (binormal) + {} + + Vector3 tangent; + Vector3 bitangent; + }; + + struct BoundingVolume + { + void Init() + { + pointMin = Vector3(999999.9,999999.9,999999.9); + pointMax = Vector3(-999999.9,-999999.9,-999999.9); + } + + void ConsiderNewPointInVolume(const Vector3& position) + { + pointMin.x = std::min(position.x, pointMin.x); + pointMin.y = std::min(position.y, pointMin.y); + pointMin.z = std::min(position.z, pointMin.z); + + pointMax.x = std::max(position.x, pointMax.x); + pointMax.y = std::max(position.y, pointMax.y); + pointMax.z = std::max(position.z, pointMax.z); + } + + Vector3 pointMin; + Vector3 pointMax; + }; + + ObjLoader(); + virtual ~ObjLoader(); + + bool IsSceneLoaded(); + bool IsMaterialLoaded(); + + bool Load(char* objBuffer, std::streampos fileSize, std::string& materialFile); + + void LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url); + + Geometry CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType); + + Vector3 GetCenter(); + Vector3 GetSize(); + + void ClearArrays(); + +private: + + BoundingVolume mSceneAABB; + + bool mSceneLoaded; + bool mMaterialLoaded; + + Dali::Vector mPoints; + Dali::Vector mTextures; + Dali::Vector mTextures2; + Dali::Vector mNormals; + Dali::Vector mTangents; + Dali::Vector mBiTangents; + Dali::Vector mTriangles; + + void CalculateTangentArray(const Dali::Vector& vertex, + const Dali::Vector& texcoord, + Dali::Vector& triangle, + Dali::Vector& normal, + Dali::Vector& tangent); + + void CenterAndScale(bool center, Dali::Vector& points); + + + void CreateGeometryArray(Dali::Vector & vertices, + Dali::Vector & textures, + Dali::Vector & verticesExt, + Dali::Vector & indices); + +}; + + + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + + + + +#endif // __DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H__ diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 3b04cf6..0b71ff8 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -25,6 +25,8 @@ toolkit_src_files = \ $(toolkit_src_dir)/controls/image-view/image-view-impl.cpp \ $(toolkit_src_dir)/controls/magnifier/magnifier-impl.cpp \ $(toolkit_src_dir)/controls/popup/confirmation-popup-impl.cpp \ + $(toolkit_src_dir)/controls/model3d-view/model3d-view-impl.cpp \ + $(toolkit_src_dir)/controls/model3d-view/obj-loader.cpp \ $(toolkit_src_dir)/controls/popup/popup-impl.cpp \ $(toolkit_src_dir)/controls/page-turn-view/page-turn-portrait-view-impl.cpp \ $(toolkit_src_dir)/controls/page-turn-view/page-turn-effect.cpp \ diff --git a/dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp b/dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp new file mode 100644 index 0000000..e1dc94c --- /dev/null +++ b/dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER + +#include + +// INTERNAL INCLUDES +#include + +// EXTERNAL INCLUDES + +namespace Dali +{ + +namespace Toolkit +{ + +Model3dView::Model3dView() +{} + +Model3dView::Model3dView( const Model3dView& model3dView ) +: Control( model3dView ) +{ +} + +Model3dView& Model3dView::operator=( const Model3dView& model3dView ) +{ + if( &model3dView != this ) + { + Control::operator=( model3dView ); + } + return *this; +} + +Model3dView::~Model3dView() +{ +} + +Model3dView Model3dView::New() +{ + return Internal::Model3dView::New(); +} + +Model3dView Model3dView::New( const std::string& objUrl, const std::string& mtlUrl, const std::string& imagesUrl ) +{ + Model3dView model3dView = Internal::Model3dView::New(); + model3dView.SetProperty( Model3dView::Property::GEOMETRY_URL, Dali::Property::Value( objUrl ) ); + model3dView.SetProperty( Model3dView::Property::MATERIAL_URL, Dali::Property::Value( mtlUrl ) ); + model3dView.SetProperty( Model3dView::Property::IMAGES_URL, Dali::Property::Value( imagesUrl ) ); + + return model3dView; +} + +Model3dView Model3dView::DownCast( BaseHandle handle ) +{ + return Control::DownCast(handle); +} + +Model3dView::Model3dView( Internal::Model3dView& implementation ) + : Control( implementation ) +{ +} + +Model3dView::Model3dView( Dali::Internal::CustomActor* internal ) + : Control( internal ) +{ + VerifyCustomActorPointer( internal ); +} + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/public-api/controls/model3d-view/model3d-view.h b/dali-toolkit/public-api/controls/model3d-view/model3d-view.h new file mode 100644 index 0000000..94ec859 --- /dev/null +++ b/dali-toolkit/public-api/controls/model3d-view/model3d-view.h @@ -0,0 +1,156 @@ +#ifndef __DALI_TOOLKIT_MODEL3D_VIEW_H__ +#define __DALI_TOOLKIT_MODEL3D_VIEW_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal DALI_INTERNAL +{ +class Model3dView; +} +/** + * @brief Model3dView is a control for displaying 3d geometry. + * + * All the geometry loaded with the control is automatically centered and scaled to fit + * the size of all the other controls. So the max is (0.5,0.5) and the min is (-0.5,-0.5) +*/ +class DALI_IMPORT_API Model3dView : public Control +{ +public: + + /** + * @brief The start and end property ranges for this control. + */ + enum PropertyRange + { + PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, + PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000, ///< Reserve property indices + + ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX, + ANIMATABLE_PROPERTY_END_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000 ///< Reserve animatable property indices + }; + + /** + * @brief An enumeration of properties belonging to the TextLabel class. + */ + struct Property + { + enum + { + GEOMETRY_URL = PROPERTY_START_INDEX, ///< name "geometry-url", The path to the geometry file, type STRING + MATERIAL_URL, ///< name "material-url", The path to the material file, type STRING + IMAGES_URL, ///< name "images-url", The path to the images directory, type STRING + ILLUMINATION_TYPE, ///< name "illumination-type", The type of illumination, type INTEGER + TEXTURE0_URL, ///< name "texture0-url", The path to first texture, type STRING + TEXTURE1_URL, ///< name "texture1-url", The path to second texture, type STRING + TEXTURE2_URL, ///< name "texture2-url", The path to third texture, type STRING + + LIGHT_POSITION = ANIMATABLE_PROPERTY_START_INDEX ///< name "light-position", The coordinates of the light, type Vector3 + }; + }; + + enum IlluminationType + { + DIFFUSE, + DIFFUSE_WITH_TEXTURE, + DIFFUSE_WITH_NORMAL_MAP + }; + + + /** + * @brief Create a new instance of a Model3dView control. + * + * @return A handle to the new Model3dView control. + */ + static Model3dView New(); + + /** + * @brief Create a new instance of a Model3dView control. + * + * @return A handle to the new Model3dView control. + */ + static Model3dView New( const std::string& objUrl, const std::string& mtlUrl, const std::string& imagesUrl ); + + + /** + * @brief Create an uninitialized Model3dView + * + * Only derived versions can be instantiated. Calling member + * functions with an uninitialized Dali::Object is not allowed. + */ + Model3dView(); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~Model3dView(); + + /** + * @brief Copy constructor. + */ + Model3dView( const Model3dView& model3dView ); + + /** + * @brief Assignment operator. + */ + Model3dView& operator=( const Model3dView& model3dView ); + + /** + * @brief Downcast an Object handle to Model3dView. + * + * If handle points to a Model3dView the downcast produces valid + * handle. If not the returned handle is left uninitialized. + * + * @param[in] handle Handle to an object + * @return handle to a Model3dView or an uninitialized handle + */ + static Model3dView DownCast( BaseHandle handle ); + +public: // Not intended for application developers + + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * + * @param[in] implementation The Control implementation. + */ + DALI_INTERNAL Model3dView( Internal::Model3dView& implementation ); + + /** + * @brief Allows the creation of this Control from an Internal::CustomActor pointer. + * + * @param[in] internal A pointer to the internal CustomActor. + */ + DALI_INTERNAL Model3dView( Dali::Internal::CustomActor* internal ); + +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_MODEL3D_VIEW_H__ diff --git a/dali-toolkit/public-api/file.list b/dali-toolkit/public-api/file.list index 5e096b9..1b1194c 100755 --- a/dali-toolkit/public-api/file.list +++ b/dali-toolkit/public-api/file.list @@ -10,6 +10,7 @@ public_api_src_files = \ $(public_api_src_dir)/controls/buttons/radio-button.cpp \ $(public_api_src_dir)/controls/default-controls/solid-color-actor.cpp \ $(public_api_src_dir)/controls/image-view/image-view.cpp \ + $(public_api_src_dir)/controls/model3d-view/model3d-view.cpp \ $(public_api_src_dir)/controls/scroll-bar/scroll-bar.cpp \ $(public_api_src_dir)/controls/scrollable/item-view/default-item-layout.cpp \ $(public_api_src_dir)/controls/scrollable/item-view/item-layout.cpp \ @@ -50,6 +51,9 @@ public_api_buttons_header_files = \ public_api_default_controls_header_files = \ $(public_api_src_dir)/controls/default-controls/solid-color-actor.h +public_api_model3d_view_header_files = \ + $(public_api_src_dir)/controls/model3d-view/model3d-view.h + public_api_gaussian_blur_view_header_files = \ $(public_api_src_dir)/controls/gaussian-blur-view/gaussian-blur-view.h