New control to load OBJ files 88/44288/19
authorDavid Fumanal <d.fumanal@samsung.com>
Mon, 20 Jul 2015 13:33:50 +0000 (14:33 +0100)
committerDavid Fumanal <d.fumanal@samsung.com>
Wed, 12 Aug 2015 16:13:15 +0000 (09:13 -0700)
Change-Id: I349f36808c8d2f521adab2a280167643e8d2206f

12 files changed:
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp [new file with mode: 0644]
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/dali-toolkit.h
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/obj-loader.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/obj-loader.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/model3d-view/model3d-view.h [new file with mode: 0644]
dali-toolkit/public-api/file.list

index 8f40f82..446bb36 100644 (file)
@@ -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 (file)
index 0000000..15737f4
--- /dev/null
@@ -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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+
+
+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;
+}
index 3ec8f92..948b4cf 100644 (file)
@@ -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)
index a8a3e1f..7f40633 100644 (file)
@@ -31,6 +31,7 @@
 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.h>
 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
 #include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
 #include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h>
 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
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 (file)
index 0000000..b8dfc75
--- /dev/null
@@ -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 <dali/public-api/object/type-registry.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraint-source.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+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<Vector3>( 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<char> 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<char> 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<Vector3>( 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 (file)
index 0000000..2202409
--- /dev/null
@@ -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 <dali/devel-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+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<Toolkit::Internal::Model3dView&>(handle);
+}
+
+inline const Toolkit::Internal::Model3dView& GetImpl( const Toolkit::Model3dView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::Model3dView&>(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 (file)
index 0000000..c950b9d
--- /dev/null
@@ -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 <string>
+#include <sstream>
+#include <string.h>
+
+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<Vector3>& vertex,
+                                      const Dali::Vector<Vector2>& texcoord,
+                                      Dali::Vector<TriIndex>& triangle,
+                                      Dali::Vector<Vector3>& normal,
+                                      Dali::Vector<Vector3>& 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<Vector3>& 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<Vertex> & vertices,
+                                    Dali::Vector<Vector2> & textures,
+                                    Dali::Vector<VertexExt> & verticesExt,
+                                    Dali::Vector<int> & 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<Vertex> vertices;
+  Dali::Vector<Vector2> textures;
+  Dali::Vector<VertexExt> verticesExt;
+  Dali::Vector<int> 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 (file)
index 0000000..eac63c3
--- /dev/null
@@ -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 <dali/devel-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+
+
+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<Vector3> mPoints;
+  Dali::Vector<Vector2> mTextures;
+  Dali::Vector<Vector2> mTextures2;
+  Dali::Vector<Vector3> mNormals;
+  Dali::Vector<Vector3> mTangents;
+  Dali::Vector<Vector3> mBiTangents;
+  Dali::Vector<TriIndex> mTriangles;
+
+  void CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
+                             const Dali::Vector<Vector2>& texcoord,
+                             Dali::Vector<TriIndex>& triangle,
+                             Dali::Vector<Vector3>& normal,
+                             Dali::Vector<Vector3>& tangent);
+
+  void CenterAndScale(bool center, Dali::Vector<Vector3>& points);
+
+
+  void CreateGeometryArray(Dali::Vector<Vertex> & vertices,
+                           Dali::Vector<Vector2> & textures,
+                           Dali::Vector<VertexExt> & verticesExt,
+                           Dali::Vector<int> & indices);
+
+};
+
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+
+
+#endif // __DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H__
index 3b04cf6..0b71ff8 100644 (file)
@@ -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 (file)
index 0000000..e1dc94c
--- /dev/null
@@ -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 <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h>
+
+// 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<Model3dView, Internal::Model3dView>(handle);
+}
+
+Model3dView::Model3dView( Internal::Model3dView& implementation )
+ : Control( implementation )
+{
+}
+
+Model3dView::Model3dView( Dali::Internal::CustomActor* internal )
+ : Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Model3dView>( 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 (file)
index 0000000..94ec859
--- /dev/null
@@ -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 <dali-toolkit/public-api/controls/control.h>
+
+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__
index 5e096b9..1b1194c 100755 (executable)
@@ -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