Implemented a mesh renderer to display 3D objects from files. 91/72591/22
authorAndrew Poor <andrew.poor@samsung.com>
Wed, 1 Jun 2016 15:49:24 +0000 (16:49 +0100)
committerAndrew Poor <andrew.poor@samsung.com>
Wed, 22 Jun 2016 17:18:49 +0000 (18:18 +0100)
Change-Id: I6adb4086a563b45e5644302181c4b898f2d5f100

23 files changed:
automated-tests/resources/Cube.obj [new file with mode: 0644]
automated-tests/resources/TB-gloss.png [new file with mode: 0644]
automated-tests/resources/ToyRobot-Metal-Simple.mtl [new file with mode: 0644]
automated-tests/resources/ToyRobot-Metal.mtl [new file with mode: 0644]
automated-tests/resources/tb-norm.png [new file with mode: 0644]
automated-tests/resources/tbcol.png [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp
dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h
dali-toolkit/internal/controls/model3d-view/obj-loader.cpp
dali-toolkit/internal/controls/model3d-view/obj-loader.h
dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.h [new file with mode: 0644]
dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-impl.h
dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp
dali-toolkit/internal/controls/renderers/renderer-string-constants.h
dali-toolkit/internal/file.list
dali-toolkit/public-api/controls/model3d-view/model3d-view.h
docs/content/images/renderers/mesh-renderer.png [new file with mode: 0644]
docs/content/shared-javascript-and-cpp-documentation/control-renderers.md

diff --git a/automated-tests/resources/Cube.obj b/automated-tests/resources/Cube.obj
new file mode 100644 (file)
index 0000000..e9bc9b4
--- /dev/null
@@ -0,0 +1,42 @@
+# cube.obj
+#
+
+g cube
+
+v  0.0  0.0  0.0
+v  0.0  0.0  1.0
+v  0.0  1.0  0.0
+v  0.0  1.0  1.0
+v  1.0  0.0  0.0
+v  1.0  0.0  1.0
+v  1.0  1.0  0.0
+v  1.0  1.0  1.0
+
+vt  0.0  0.0
+vt  0.3  0.3
+vt  0.0  1.0
+vt  0.3  0.7
+vt  1.0  0.0
+vt  0.7  0.3
+vt  1.0  1.0
+vt  0.7  0.7
+
+vn  0.0  0.0  1.0
+vn  0.0  0.0 -1.0
+vn  0.0  1.0  0.0
+vn  0.0 -1.0  0.0
+vn  1.0  0.0  0.0
+vn -1.0  0.0  0.0
+
+f  1/1/2  7/7/2  5/5/2
+f  1/1/2  3/3/2  7/7/2
+f  1/1/6  4/4/6  3/3/6
+f  1/1/6  2/2/6  4/4/6
+f  3/3/3  8/8/3  7/7/3
+f  3/3/3  4/4/3  8/8/3
+f  5/5/5  7/7/5  8/8/5
+f  5/5/5  8/8/5  6/6/5
+f  1/1/4  5/5/4  6/6/4
+f  1/1/4  6/6/4  2/2/4
+f  2/2/1  6/6/1  8/8/1
+f  2/2/1  8/8/1  4/4/1
diff --git a/automated-tests/resources/TB-gloss.png b/automated-tests/resources/TB-gloss.png
new file mode 100644 (file)
index 0000000..9ed4b6c
Binary files /dev/null and b/automated-tests/resources/TB-gloss.png differ
diff --git a/automated-tests/resources/ToyRobot-Metal-Simple.mtl b/automated-tests/resources/ToyRobot-Metal-Simple.mtl
new file mode 100644 (file)
index 0000000..f699daf
--- /dev/null
@@ -0,0 +1,9 @@
+newmtl lambert3SG
+illum 4
+Kd 0.00 0.00 0.00
+Ka 0.00 0.00 0.00
+Tf 1.00 1.00 1.00
+map_Kd tbcol.png
+Ni 1.00
+Ks 0.00 0.00 0.00
+Ns 3.66
diff --git a/automated-tests/resources/ToyRobot-Metal.mtl b/automated-tests/resources/ToyRobot-Metal.mtl
new file mode 100644 (file)
index 0000000..cab3ae2
--- /dev/null
@@ -0,0 +1,11 @@
+newmtl lambert3SG
+illum 4
+Kd 0.00 0.00 0.00
+Ka 0.00 0.00 0.00
+Tf 1.00 1.00 1.00
+map_Kd tbcol.png
+bump tb-norm.png -bm 0.05
+Ni 1.00
+Ks 0.00 0.00 0.00
+map_Ks TB-gloss.png
+Ns 3.66
diff --git a/automated-tests/resources/tb-norm.png b/automated-tests/resources/tb-norm.png
new file mode 100644 (file)
index 0000000..884cc90
Binary files /dev/null and b/automated-tests/resources/tb-norm.png differ
diff --git a/automated-tests/resources/tbcol.png b/automated-tests/resources/tbcol.png
new file mode 100644 (file)
index 0000000..93d98cd
Binary files /dev/null and b/automated-tests/resources/tbcol.png differ
index d524b81..0983366 100644 (file)
@@ -30,6 +30,9 @@ namespace
 const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.jpg";
 const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
+const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/";
 }
 
 void dali_control_renderer_startup(void)
@@ -625,3 +628,46 @@ int UtcDaliControlRendererGetPropertyMap7(void)
 
   END_TEST;
 }
+
+//Mesh renderer
+int UtcDaliControlRendererGetPropertyMap8(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliControlRendererGetPropertyMap8: MeshRenderer" );
+
+  //Request MeshRenderer using a property map.
+  RendererFactory factory = RendererFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType", "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_LOCATION );
+  propertyMap.Insert( "shaderType", "textureless" );
+  ControlRenderer meshRenderer = factory.GetControlRenderer( propertyMap );
+
+  Property::Map resultMap;
+  meshRenderer.CreatePropertyMap( resultMap );
+
+  //Check values in the result map are identical to the initial map's values.
+  Property::Value* value = resultMap.Find( "rendererType", Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == "mesh" );
+
+  value = resultMap.Find( "objectUrl", Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_OBJ_FILE_NAME );
+
+  value = resultMap.Find( "materialUrl", Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_MTL_FILE_NAME );
+
+  value = resultMap.Find( "texturesPath", Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_RESOURCE_LOCATION );
+
+  value = resultMap.Find( "shaderType", Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == "textureless" );
+
+  END_TEST;
+}
index 89bc1a1..d813261 100644 (file)
@@ -32,8 +32,10 @@ typedef NinePatchImage::StretchRanges StretchRanges;
 
 const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
 const char* TEST_NPATCH_FILE_NAME =  "gallery_image_01.9.jpg";
-
 const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
+const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
 
 Integration::Bitmap* CreateBitmap( unsigned int imageWidth, unsigned int imageHeight, unsigned int initialColor, Pixel::Format pixelFormat )
 {
@@ -933,6 +935,381 @@ int UtcDaliRendererFactoryGetSvgRenderer(void)
   END_TEST;
 }
 
+//Test if mesh loads correctly when supplied with only the bare minimum requirements, an object file.
+int UtcDaliRendererFactoryGetMeshRenderer1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRenderer1:  Request mesh renderer with a valid object file only" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  application.SendNotification();
+  application.Render( 0 );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh loads correctly when supplied with an object file as well as a blank material file and images directory.
+int UtcDaliRendererFactoryGetMeshRenderer2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRenderer2:  Request mesh renderer with blank material file and images directory" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", "" );
+  propertyMap.Insert( "texturesPath", "" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh loads correctly when supplied with all parameters, an object file, a material file and a directory location.
+int UtcDaliRendererFactoryGetMeshRenderer3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRenderer3:  Request mesh renderer with all parameters correct" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh renderer can load a correctly supplied mesh without a normal map or gloss map in the material file.
+int UtcDaliRendererFactoryGetMeshRenderer4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRenderer4:  Request mesh renderer with diffuse texture but not normal or gloss." );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", TEST_SIMPLE_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh renderer handles the case of lacking an object file.
+int UtcDaliRendererFactoryGetMeshRendererN1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRendererN1:  Request mesh renderer without object file" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  //Test to see if the object has not been loaded, as expected.
+  Matrix scaleMatrix;
+  DALI_TEST_CHECK( ! gl.GetUniformValue<Matrix>( "uObjectMatrix", scaleMatrix ) );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh renderer handles the case of being passed invalid material and images urls.
+int UtcDaliRendererFactoryGetMeshRendererN2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRendererN2:  Request mesh renderer with invalid material and images urls" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", "invalid" );
+  propertyMap.Insert( "texturesPath", "also invalid" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  //Test to see if the object has not been loaded, as expected.
+  Matrix scaleMatrix;
+  DALI_TEST_CHECK( ! gl.GetUniformValue<Matrix>( "uObjectMatrix", scaleMatrix ) );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+//Test if mesh renderer handles the case of being passed an invalid object url
+int UtcDaliRendererFactoryGetMeshRendererN3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryGetMeshRendererN3:  Request mesh renderer with invalid object url" );
+
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Set up renderer properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( "rendererType",  "mesh" );
+  propertyMap.Insert( "objectUrl", "invalid" );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+
+  ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
+  DALI_TEST_CHECK( controlRenderer );
+
+  //Add renderer to an actor on stage.
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+  controlRenderer.SetOnStage( actor );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  //Test to see if the object has not been loaded, as expected.
+  Matrix scaleMatrix;
+  DALI_TEST_CHECK( ! gl.GetUniformValue<Matrix>( "uObjectMatrix", scaleMatrix ) );
+
+  controlRenderer.SetOffStage( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
 int UtcDaliRendererFactoryResetRenderer1(void)
 {
   ToolkitTestApplication application;
@@ -1052,3 +1429,84 @@ int UtcDaliRendererFactoryResetRenderer3(void)
 
   END_TEST;
 }
+
+//Test resetting mesh and primitive shape renderers
+int UtcDaliRendererFactoryResetRenderer4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliRendererFactoryResetRenderer4:  Mesh and primitive renderers" );
+
+  Actor actor = Actor::New();
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  RendererFactory factory = RendererFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map map;
+
+  //******
+
+  //Start with basic color renderer
+  ControlRenderer controlRenderer = factory.GetControlRenderer( Color::RED );
+  DALI_TEST_CHECK( controlRenderer );
+
+  TestControlRendererRender( application, actor, controlRenderer );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Ensure set correctly.
+  Vector4 actualValue( Vector4::ZERO );
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "mixColor", actualValue ) );
+  DALI_TEST_EQUALS( actualValue, Color::RED, TEST_LOCATION );
+
+  //******
+
+  //Reset to mesh renderer
+  map.Insert( "rendererType", "mesh" );
+  map.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  map.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  map.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+  factory.ResetRenderer( controlRenderer, actor, map );
+  application.SendNotification();
+  application.Render( 0 );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Tell the platform abstraction that the required resources have been loaded.
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetAllResourceRequestsAsLoaded();
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Ensure set correctly.
+  controlRenderer.CreatePropertyMap( map );
+  DALI_TEST_EQUALS( map.Find( "objectUrl", Property::STRING )->Get<std::string>(), TEST_OBJ_FILE_NAME, TEST_LOCATION );
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  //******
+
+  //Reset back to color renderer
+  factory.ResetRenderer( controlRenderer, actor, Color::GREEN );
+  application.SendNotification();
+  application.Render( 0 );
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  //Ensure set correctly.
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "mixColor", actualValue ) );
+  DALI_TEST_EQUALS( actualValue, Color::GREEN, TEST_LOCATION );
+
+  //******
+
+  END_TEST;
+}
index c6fc451..fb52bf3 100644 (file)
@@ -112,7 +112,7 @@ public:
    * else the renderer would be a handle to a newly created internal color renderer.
    *
    * @param[in] renderer The ControlRenderer to reset
-   * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor
+   * @param[in] actor The Actor the renderer is applied to, empty if the renderer has not been applied to any Actor
    * @param[in] color The color to be rendered.
    */
   void ResetRenderer( ControlRenderer& renderer, Actor& actor, const Vector4& color );
@@ -151,7 +151,7 @@ public:
    * else the renderer would be a handle to a newly created internal image renderer.
    *
    * @param[in] renderer The ControlRenderer to reset
-   * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor
+   * @param[in] actor The Actor the renderer is applied to, empty if the renderer has not been applied to any Actor
    * @param[in] image The Image to be rendered.
    */
   void ResetRenderer( ControlRenderer& renderer, Actor& actor, const Image& image );
@@ -173,14 +173,13 @@ public:
    * else the renderer would be a handle to a newly created internal image renderer.
    *
    * @param[in] renderer The ControlRenderer to reset
-   * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor
+   * @param[in] actor The Actor the renderer is applied to, empty if the renderer has not been applied to any Actor
    * @param[in] url The URL to the resource to be rendered.
    * @param[in] size The width and height to fit the loaded image to.
    */
   void ResetRenderer( ControlRenderer& renderer, Actor& actor, const std::string& url,
                       ImageDimensions size = ImageDimensions() );
 
-
   /**
    * @brief Request the current control renderer from the property map, merging the property map with the renderer
    *
@@ -188,7 +187,7 @@ public:
    * else the renderer would be a handle to a newly created internal renderer.
    *
    * @param[in] renderer The ControlRenderer to reset
-   * @param[in] actor The Actor the renderer is applied to if, empty if the renderer has not been applied to any Actor
+   * @param[in] actor The Actor the renderer is applied to, empty if the renderer has not been applied to any Actor
    * @param[in] propertyMap The map contains the properties required by the control renderer
    *            Depends on the content of the map, different kind of renderer would be returned.
    */
index d395fb2..eac2d89 100644 (file)
@@ -423,7 +423,7 @@ void Model3dView::OnStageConnection( int depth )
 
   if( mObjLoader.IsSceneLoaded() )
   {
-    mMesh = mObjLoader.CreateGeometry( mIlluminationType );
+    mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ) );
 
     CreateMaterial();
     LoadTextures();
@@ -462,9 +462,7 @@ void Model3dView::LoadGeometry()
   if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
   {
     mObjLoader.ClearArrays();
-
-    std::string materialUrl;
-    mObjLoader.Load(fileContent.Begin(), fileSize, materialUrl);
+    mObjLoader.LoadObject(fileContent.Begin(), fileSize);
 
     //Get size information from the obj loaded
     mSceneCenter = mObjLoader.GetCenter();
@@ -520,7 +518,7 @@ void Model3dView::CreateGeometry()
 {
   if( mObjLoader.IsSceneLoaded() )
   {
-    mMesh = mObjLoader.CreateGeometry( mIlluminationType );
+    mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ) );
 
     if( mRenderer )
     {
@@ -629,6 +627,24 @@ void Model3dView::LoadTextures()
   }
 }
 
+int Model3dView::GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType )
+{
+  int objectProperties = 0;
+
+  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
+      illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  {
+    objectProperties |= ObjLoader::TEXTURE_COORDINATES;
+  }
+
+  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  {
+    objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINOMIALS;
+  }
+
+  return objectProperties;
+}
+
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali
index 8e44911..9c24faa 100644 (file)
@@ -146,6 +146,15 @@ private:
   void UpdateShaderUniforms();
 
 
+  /*
+   * @brief Given a specific shader type, find out which properties are necessary for it.
+   *
+   * @param[in] illuminationType The type of shader we intend to use.
+   * @return A bitmask of the properties we require to be loaded to use the given shader.
+   */
+  int GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType );
+
+
   ObjLoader mObjLoader;
 
   //Properties
index bc4e174..aaf7c60 100644 (file)
@@ -19,6 +19,7 @@
 #include "obj-loader.h"
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
 #include <string>
 #include <sstream>
 #include <string.h>
@@ -32,6 +33,10 @@ namespace Toolkit
 namespace Internal
 {
 
+namespace
+{
+  const int MAX_POINT_INDICES = 4;
+}
 using namespace Dali;
 
 ObjLoader::ObjLoader()
@@ -39,8 +44,8 @@ ObjLoader::ObjLoader()
   mSceneLoaded = false;
   mMaterialLoaded = false;
   mHasTexturePoints = false;
-  mHasNormalMap = false;
   mHasDiffuseMap = false;
+  mHasNormalMap = false;
   mHasSpecularMap = false;
   mSceneAABB.Init();
 }
@@ -67,9 +72,6 @@ void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
                                       Dali::Vector<Vector3>& normal,
                                       Dali::Vector<Vector3>& tangent)
 {
-  normal.Clear();
-  normal.Resize(vertex.Size());
-
   Dali::Vector<Vector3> tangents;
   tangents.Resize( vertex.Size() );
 
@@ -172,12 +174,16 @@ void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
   //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex
   //In the case of a textureless object, we don't need tangents for our shader and so we skip this step
   //TODO: Use a better function to calculate tangents
-
   if( mTangents.Size() == 0 && mHasTexturePoints )
   {
-    mTangents.Resize( mNormals.Size() );
-    mBiTangents.Resize( mNormals.Size() );
+    mNormals.Clear();
+
+    mNormals.Resize( mPoints.Size() );
+    mTangents.Resize( mPoints.Size() );
+    mBiTangents.Resize( mPoints.Size() );
+
     CalculateTangentArray( mPoints, mTextures, mTriangles, mNormals, mTangents );
+
     for ( unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
     {
       mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]);
@@ -275,14 +281,14 @@ void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
   }
 }
 
-bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& materialFile )
+bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
 {
   Vector3 point;
   Vector2 texture;
-  std::string vet[4], name;
-  int ptIdx[4];
-  int nrmIdx[4];
-  int texIdx[4];
+  std::string vet[MAX_POINT_INDICES], name;
+  int ptIdx[MAX_POINT_INDICES];
+  int nrmIdx[MAX_POINT_INDICES];
+  int texIdx[MAX_POINT_INDICES];
   TriIndex triangle,triangle2;
   int pntAcum = 0, texAcum = 0, nrmAcum = 0;
   bool iniObj = false;
@@ -372,7 +378,7 @@ bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& mat
       }
 
       int numIndices = 0;
-      while( isline >> vet[numIndices] )
+      while( isline >> vet[numIndices] && numIndices < MAX_POINT_INDICES )
       {
         numIndices++;
       }
@@ -476,9 +482,6 @@ bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& mat
     {
       isline >> name;
     }
-    else
-    {
-    }
   }
 
   if ( iniObj )
@@ -490,11 +493,10 @@ bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& mat
   }
 
   return false;
-
 }
 
-void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& texture0Url,
-                              std::string& texture1Url, std::string& texture2Url )
+void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl,
+                              std::string& normalTextureUrl, std::string& glossTextureUrl )
 {
   float fR,fG,fB;
 
@@ -518,11 +520,15 @@ void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::str
     {
       isline >> info;
     }
+    else if ( tag == "Ka" ) //ambient color
+    {
+      isline >> fR >> fG >> fB;
+    }
     else if ( tag == "Kd" ) //diffuse color
     {
       isline >> fR >> fG >> fB;
     }
-    else if ( tag == "Kd" ) //Ambient color
+    else if ( tag == "Ks" ) //specular color
     {
       isline >> fR >> fG >> fB;
     }
@@ -535,19 +541,19 @@ void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::str
     else if ( tag == "map_Kd" )
     {
       isline >> info;
-      texture0Url = info;
+      diffuseTextureUrl = info;
       mHasDiffuseMap = true;
     }
     else if ( tag == "bump" )
     {
       isline >> info;
-      texture1Url = info;
+      normalTextureUrl = info;
       mHasNormalMap = true;
     }
     else if ( tag == "map_Ks" )
     {
       isline >> info;
-      texture2Url = info;
+      glossTextureUrl = info;
       mHasSpecularMap = true;
     }
   }
@@ -555,7 +561,7 @@ void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::str
   mMaterialLoaded = true;
 }
 
-Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illuminationType )
+Geometry ObjLoader::CreateGeometry( int objectProperties )
 {
   Geometry surface = Geometry::New();
 
@@ -575,8 +581,7 @@ Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illum
   surface.AddVertexBuffer( surfaceVertices );
 
   //Some need texture coordinates
-  if( ( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) ||
-        (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) ) && mHasTexturePoints && mHasDiffuseMap )
+  if( ( objectProperties & TEXTURE_COORDINATES ) && mHasTexturePoints && mHasDiffuseMap )
   {
     Property::Map textureFormat;
     textureFormat["aTexCoord"] = Property::VECTOR2;
@@ -587,7 +592,7 @@ Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illum
   }
 
   //Some need tangent and bitangent
-  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP && mHasTexturePoints )
+  if( ( objectProperties & TANGENTS ) && ( objectProperties & BINOMIALS ) && mHasTexturePoints )
   {
     Property::Map vertexExtFormat;
     vertexExtFormat["aTangent"] = Property::VECTOR3;
@@ -598,15 +603,12 @@ Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illum
     surface.AddVertexBuffer( extraVertices );
   }
 
+  //If indices are required, we set them.
   if ( indices.Size() )
   {
     surface.SetIndexBuffer ( &indices[0], indices.Size() );
   }
 
-  vertices.Clear();
-  verticesExt.Clear();
-  indices.Clear();
-
   return surface;
 }
 
index 0a9ea25..0336323 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/rendering/renderer.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
-
+#include <limits>
 
 namespace Dali
 {
@@ -65,7 +62,7 @@ public:
     {}
 
     VertexExt( const Vector3& tangent, const Vector3& binormal )
-    : tangent( tangent), bitangent (binormal)
+    : tangent( tangent), bitangent( binormal )
     {}
 
     Vector3 tangent;
@@ -76,36 +73,45 @@ public:
   {
     void Init()
     {
-      pointMin = Vector3(999999.9,999999.9,999999.9);
-      pointMax = Vector3(-999999.9,-999999.9,-999999.9);
+      pointMin = Vector3( std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() );
+      pointMax = Vector3( std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min() );
     }
 
-    void ConsiderNewPointInVolume(const Vector3& position)
+    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);
+      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);
+      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;
   };
 
+  //Defines bit masks to declare which properties are needed by anyone requesting a geometry.
+  enum ObjectProperties
+  {
+    TEXTURE_COORDINATES = 1 << 0,
+    TANGENTS = 1 << 1,
+    BINOMIALS = 1 << 2
+  };
+
   ObjLoader();
   virtual ~ObjLoader();
 
   bool      IsSceneLoaded();
   bool      IsMaterialLoaded();
 
-  bool      Load(char* objBuffer, std::streampos fileSize, std::string& materialFile);
+  bool      LoadObject( char* objBuffer, std::streampos fileSize );
 
-  void      LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url);
+  void      LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl,
+                          std::string& normalTextureUrl, std::string& glossTextureUrl );
 
-  Geometry  CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType);
+  Geometry  CreateGeometry( int objectProperties );
 
   Vector3   GetCenter();
   Vector3   GetSize();
@@ -138,19 +144,19 @@ private:
   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 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 CenterAndScale( bool center, Dali::Vector<Vector3>& points );
 
 
-  void CreateGeometryArray(Dali::Vector<Vertex> & vertices,
-                           Dali::Vector<Vector2> & textures,
-                           Dali::Vector<VertexExt> & verticesExt,
-                           Dali::Vector<unsigned short> & indices);
+  void CreateGeometryArray( Dali::Vector<Vertex> & vertices,
+                            Dali::Vector<Vector2> & textures,
+                            Dali::Vector<VertexExt> & verticesExt,
+                            Dali::Vector<unsigned short> & indices );
 
 };
 
diff --git a/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.cpp b/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.cpp
new file mode 100644 (file)
index 0000000..8b3256d
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2016 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 "mesh-renderer.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <fstream>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+//Defines ordering of textures for shaders.
+//All shaders, if including certain texture types, must include them in the same order.
+//Within the texture set for the renderer, textures are ordered in the same manner.
+enum TextureIndex
+{
+  DIFFUSE_INDEX = 0u,
+  NORMAL_INDEX = 1u,
+  GLOSS_INDEX = 2u
+};
+
+const char * const RENDERER_TYPE_VALUE( "mesh" ); //String label for which type of control renderer this is.
+const char * const LIGHT_POSITION( "uLightPosition" ); //Shader property
+const char * const OBJECT_MATRIX( "uObjectMatrix" ); //Shader property
+
+//Shaders
+//If a shader requires certain textures, they must be listed in order,
+//as detailed in the TextureIndex enum documentation.
+
+//A basic shader that doesn't use textures at all.
+const char* SIMPLE_VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute highp vec3 aPosition;\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
+
+  void main()\n
+  {\n
+    vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
+    vec3 normal = uNormalMatrix * mat3( uObjectMatrix ) * aNormal;\n
+    vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
+    vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+
+    float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
+    vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
+
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the texture-less shader.
+const char* SIMPLE_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying mediump vec3 vIllumination;\n
+  uniform lowp vec4 uColor;\n
+
+  void main()\n
+  {\n
+    gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a );\n
+  }\n
+);
+
+//Diffuse and specular illumination shader with albedo texture. Texture is index 0.
+const char* VERTEX_SHADER = DALI_COMPOSE_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
+
+  void main()
+  {\n
+    vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
+    vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
+    vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
+    vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );\n
+
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+    vec3 viewDir = normalize( -vertPos.xyz );
+
+    vec3 halfVector = normalize( viewDir + vecToLight );
+
+    float lightDiffuse = dot( vecToLight, normal );\n
+    lightDiffuse = max( 0.0,lightDiffuse );\n
+    vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
+
+    vec3 reflectDir = reflect( -vecToLight, normal );
+    vSpecular = pow( max( dot( reflectDir, viewDir ), 0.0 ), 4.0 );
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the diffuse and specular illumination shader with albedo texture
+const char* FRAGMENT_SHADER = DALI_COMPOSE_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
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a );\n
+  }\n
+);
+
+//Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader.
+//Diffuse (albedo) texture is index 0, normal is 1, gloss is 2. They must be declared in this order.
+const char* NORMAL_MAP_VERTEX_SHADER = DALI_COMPOSE_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
+
+  void main()
+  {\n
+    vec4 vertexPosition = vec4( aPosition * min( uSize.x, uSize.y ), 1.0 );\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    vec4 vertPos = uModelView * vec4( aPosition.xyz, 1.0 );\n
+    vec4 centre = uModelView * vec4( 0.0, 0.0, 0.0, 1.0 );\n
+    vec4 lightPos = vec4( centre.x, centre.y, uLightPosition.z, 1.0 );\n
+
+    vec3 tangent = normalize( uNormalMatrix * aTangent );
+    vec3 binormal = normalize( uNormalMatrix * aBiNormal );
+    vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );
+
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+    vLightDirection.x = dot( vecToLight, tangent );
+    vLightDirection.y = dot( vecToLight, binormal );
+    vLightDirection.z = dot( vecToLight, normal );
+
+    vec3 viewDir = normalize( -vertPos.xyz );
+    vec3 halfVector = normalize( viewDir + vecToLight );
+    vHalfVector.x = dot( halfVector, tangent );
+    vHalfVector.y = dot( halfVector, binormal );
+    vHalfVector.z = dot( halfVector, normal );
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the shader that uses all textures (diffuse, normal and gloss maps)
+const char* NORMAL_MAP_FRAGMENT_SHADER = DALI_COMPOSE_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
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
+    vec4 glossMap = texture2D( sGloss, vTexCoord );\n
+
+    float lightDiffuse = max( 0.0, dot( normal, normalize( vLightDirection ) ) );\n
+    lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
+
+    float shininess = pow ( max ( dot ( normalize( vHalfVector ), normal ), 0.0 ), 16.0 )  ;
+
+    gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a );\n
+  }\n
+);
+
+} // namespace
+
+MeshRenderer::MeshRenderer( RendererFactoryCache& factoryCache )
+: ControlRenderer( factoryCache ),
+  mShaderType( ALL_TEXTURES ),
+  mUseTexture( true )
+{
+}
+
+MeshRenderer::~MeshRenderer()
+{
+}
+
+void MeshRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
+{
+  Property::Value* objectUrl = propertyMap.Find( OBJECT_URL );
+  if( !objectUrl || !objectUrl->Get( mObjectUrl ) )
+  {
+    DALI_LOG_ERROR( "Fail to provide object URL to the MeshRenderer object.\n" );
+  }
+
+  Property::Value* materialUrl = propertyMap.Find( MATERIAL_URL );
+
+  if( !materialUrl || !materialUrl->Get( mMaterialUrl ) || mMaterialUrl.empty() )
+  {
+    mUseTexture = false;
+  }
+
+  Property::Value* imagesUrl = propertyMap.Find( TEXTURES_PATH );
+  if( !imagesUrl || !imagesUrl->Get( mTexturesPath ) )
+  {
+    //Default behaviour is to assume files are in the same directory,
+    // or have their locations detailed in full when supplied.
+    mTexturesPath.clear();
+  }
+
+  Property::Value* shaderType = propertyMap.Find( SHADER_TYPE );
+  if( shaderType && shaderType->Get( mShaderTypeString ) )
+  {
+    if( mShaderTypeString == "textureless" )
+    {
+      mShaderType = TEXTURELESS;
+    }
+    else if( mShaderTypeString == "diffuseTexture" )
+    {
+      mShaderType = DIFFUSE_TEXTURE;
+    }
+    else if( mShaderTypeString == "allTextures" )
+    {
+      mShaderType = ALL_TEXTURES;
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Unknown shader type provided to the MeshRenderer object.\n");
+    }
+  }
+}
+
+void MeshRenderer::SetSize( const Vector2& size )
+{
+  ControlRenderer::SetSize( size );
+
+  // ToDo: renderer responds to the size change
+}
+
+void MeshRenderer::SetClipRect( const Rect<int>& clipRect )
+{
+  ControlRenderer::SetClipRect( clipRect );
+
+  //ToDo: renderer responds to the clipRect change
+}
+
+void MeshRenderer::SetOffset( const Vector2& offset )
+{
+  //ToDo: renderer applies the offset
+}
+
+void MeshRenderer::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+}
+
+void MeshRenderer::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( OBJECT_URL, mObjectUrl );
+  map.Insert( MATERIAL_URL, mMaterialUrl );
+  map.Insert( TEXTURES_PATH, mTexturesPath );
+  map.Insert( SHADER_TYPE, mShaderTypeString );
+}
+
+void MeshRenderer::InitializeRenderer()
+{
+  //Try to load the geometry from the file.
+  if( !LoadGeometry() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  //If a texture is used by the obj file, load the supplied material file.
+  if( mObjLoader.IsTexturePresent() && !mMaterialUrl.empty() )
+  {
+    if( !LoadMaterial() )
+    {
+      SupplyEmptyGeometry();
+      return;
+    }
+  }
+
+  //Now that the required parts are loaded, create the geometry for the object.
+  if( !CreateGeometry() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  CreateShader();
+
+  //Load the various texture files supplied by the material file.
+  if( !LoadTextures() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  mImpl->mRenderer = Renderer::New( mGeometry, mShader );
+  mImpl->mRenderer.SetTextures( mTextureSet );
+  mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+}
+
+void MeshRenderer::SupplyEmptyGeometry()
+{
+  mGeometry = Geometry::New();
+  mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  mImpl->mRenderer = Renderer::New( mGeometry, mShader );
+
+  DALI_LOG_ERROR( "Initialisation error in mesh renderer.\n" );
+}
+
+void MeshRenderer::UpdateShaderUniforms()
+{
+  Stage stage = Stage::GetCurrent();
+
+  Vector3 lightPosition( 0, 0, stage.GetSize().width );
+  mShader.RegisterProperty( LIGHT_POSITION, lightPosition );
+
+  Matrix scaleMatrix;
+  scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  mShader.RegisterProperty( OBJECT_MATRIX, scaleMatrix );
+}
+
+void MeshRenderer::CreateShader()
+{
+  if( mShaderType == ALL_TEXTURES )
+  {
+    mShader = Shader::New( NORMAL_MAP_VERTEX_SHADER, NORMAL_MAP_FRAGMENT_SHADER );
+  }
+  else if( mShaderType == DIFFUSE_TEXTURE )
+  {
+    mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+  }
+  else //Textureless
+  {
+    mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  }
+
+  UpdateShaderUniforms();
+}
+
+bool MeshRenderer::CreateGeometry()
+{
+  //Determine if we need to use a simpler shader to handle the provided data
+  if( mShaderType == ALL_TEXTURES )
+  {
+    if( !mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent() )
+    {
+      mShaderType = DIFFUSE_TEXTURE;
+    }
+  }
+  if( !mObjLoader.IsTexturePresent() || !mObjLoader.IsDiffuseMapPresent() || !mUseTexture )
+  {
+    mShaderType = TEXTURELESS;
+  }
+
+  int objectProperties = 0;
+
+  if( mShaderType == DIFFUSE_TEXTURE ||
+      mShaderType == ALL_TEXTURES )
+  {
+    objectProperties |= ObjLoader::TEXTURE_COORDINATES;
+  }
+
+  if( mShaderType == ALL_TEXTURES )
+  {
+    objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINOMIALS;
+  }
+
+  //Create geometry with attributes required by shader.
+  mGeometry = mObjLoader.CreateGeometry( objectProperties );
+
+  if( mGeometry )
+  {
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to load geometry in mesh renderer.\n" );
+  return false;
+}
+
+bool MeshRenderer::LoadGeometry()
+{
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if( FileLoader::ReadFile( mObjectUrl, fileSize, fileContent, FileLoader::TEXT ) )
+  {
+    mObjLoader.ClearArrays();
+    mObjLoader.LoadObject( fileContent.Begin(), fileSize );
+
+    //Get size information from the obj loaded
+    mSceneCenter = mObjLoader.GetCenter();
+    mSceneSize = mObjLoader.GetSize();
+
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to find object to load in mesh renderer.\n" );
+  return false;
+}
+
+bool MeshRenderer::LoadMaterial()
+{
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if( FileLoader::ReadFile( mMaterialUrl, fileSize, fileContent, FileLoader::TEXT ) )
+  {
+    //Load data into obj (usable) form
+    mObjLoader.LoadMaterial( fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl );
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to find texture set to load in mesh renderer.\n" );
+  mUseTexture = false;
+  return false;
+}
+
+bool MeshRenderer::LoadTextures()
+{
+  mTextureSet = TextureSet::New();
+
+  if( !mDiffuseTextureUrl.empty() )
+  {
+    std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
+
+    //Load textures
+    Image diffuseTexture = ResourceImage::New( imageUrl );
+    if( diffuseTexture )
+    {
+      mTextureSet.SetImage( DIFFUSE_INDEX, diffuseTexture );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Failed to load diffuse map texture in mesh renderer.\n");
+      return false;
+    }
+  }
+
+  if( !mNormalTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
+  {
+    std::string imageUrl = mTexturesPath + mNormalTextureUrl;
+
+    //Load textures
+    Image normalTexture = ResourceImage::New( imageUrl );
+    if( normalTexture )
+    {
+      mTextureSet.SetImage( NORMAL_INDEX, normalTexture );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Failed to load normal map texture in mesh renderer.\n");
+      return false;
+    }
+  }
+
+  if( !mGlossTextureUrl.empty() && ( mShaderType == ALL_TEXTURES ) )
+  {
+    std::string imageUrl = mTexturesPath + mGlossTextureUrl;
+
+    //Load textures
+    Image glossTexture = ResourceImage::New( imageUrl );
+    if( glossTexture )
+    {
+      mTextureSet.SetImage( GLOSS_INDEX, glossTexture );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Failed to load gloss map texture in mesh renderer.\n");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.h b/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.h
new file mode 100644 (file)
index 0000000..ede12fb
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef __DALI_TOOLKIT_INTERNAL_MESH_RENDERER_H__
+#define __DALI_TOOLKIT_INTERNAL_MESH_RENDERER_H__
+
+/*
+ * Copyright (c) 2016 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 <fstream>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * The renderer which renders a 3D object to the control's quad
+ *
+ * The following Property::Map keys are required to create a MeshRender
+ *
+ * | %Property Name  | Type        | Representing                            |
+ * |-----------------|-------------|-----------------------------------------|
+ * | objectUrl       | STRING      | A URL to the .obj file                  |
+ * | materialUrl     | STRING      | A URL to the .mtl file                  |
+ * | texturesPath    | STRING      | A URL of the path to the texture images |
+ * | shaderType      | STRING      | An enum of shader types                 |
+ */
+class MeshRenderer: public ControlRenderer
+{
+public:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the RendererFactoryCache object
+   */
+  MeshRenderer( RendererFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~MeshRenderer();
+
+public:  // from ControlRenderer
+
+  /**
+   * @copydoc ControlRenderer::SetSize
+   */
+  virtual void SetSize( const Vector2& size );
+
+  /**
+   * @copydoc ControlRenderer::SetClipRect
+   */
+  virtual void SetClipRect( const Rect<int>& clipRect );
+
+  /**
+   * @copydoc ControlRenderer::SetOffset
+   */
+  virtual void SetOffset( const Vector2& offset );
+
+  /**
+   * @copydoc ControlRenderer::CreatePropertyMap
+   */
+  virtual void DoCreatePropertyMap( Property::Map& map ) const;
+
+protected:
+
+  /**
+   * @copydoc ControlRenderer::DoInitialize
+   */
+  virtual void DoInitialize( Actor& actor, const Property::Map& propertyMap );
+
+  /**
+   * @copydoc ControlRenderer::DoSetOnStage
+   */
+  virtual void DoSetOnStage( Actor& actor );
+
+public:
+
+  /**
+   * Declare whether a texture map should be used for the object, if it's present. Defaults to true.
+   * @param[in] useTexture boolean declaration.
+   */
+  void SetUseTexture( bool useTexture );
+
+  /**
+   * Declare whether a normal map should be used for the object, if it's present. Defaults to true.
+   * @param[in] useNormalMap boolean declaration.
+   */
+  void SetUseNormalMap( bool useNormalMap );
+
+private:
+
+  //Corresponds to the shader that will be used by the mesh renderer.
+  enum ShaderType
+  {
+    TEXTURELESS,
+    DIFFUSE_TEXTURE,
+    ALL_TEXTURES
+  };
+
+  /**
+   * @brief Provide an empty geometry for the renderer to use.
+   * @details For use in error cases where the initialisation has failed for varying reasons.
+   */
+  void SupplyEmptyGeometry();
+
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  /**
+   * @brief Create a shader for the object to use.
+   */
+  void CreateShader();
+
+  /**
+   * @brief Update shader related info, uniforms, etc. for the new shader.
+   */
+  void UpdateShaderUniforms();
+
+  /**
+   * @brief Use the object URL stored in the renderer to load and create the geometry of the object.
+   * @return Boolean of success of operation.
+   */
+  bool CreateGeometry();
+
+  /**
+   * @brief Use the object URL stored in the renderer to load the geometry of the object.
+   * @return Boolean of success of operation.
+   */
+  bool LoadGeometry();
+
+  /**
+   * @brief Use the material URL stored in the renderer to load the material of the object.
+   * @return Boolean of success of operation.
+   */
+  bool LoadMaterial();
+
+  /**
+   * @brief Use the image and texture URL components to load the different types of texture.
+   * @return Boolean of success of operation. Returns false if any texture fails to load from a url.
+   */
+  bool LoadTextures();
+
+private:
+
+  // Undefined
+  MeshRenderer( const MeshRenderer& meshRenderer );
+
+  // Undefined
+  MeshRenderer& operator=( const MeshRenderer& meshRenderer );
+
+private:
+
+  std::string mObjectUrl;
+  std::string mMaterialUrl;
+
+  std::string mDiffuseTextureUrl;
+  std::string mNormalTextureUrl;
+  std::string mGlossTextureUrl;
+  std::string mTexturesPath;
+
+  std::string mShaderTypeString;
+
+  Shader mShader;
+  Geometry mGeometry;
+  TextureSet mTextureSet;
+
+  ObjLoader mObjLoader;
+  Vector3 mSceneCenter;
+  Vector3 mSceneSize;
+  ShaderType mShaderType;
+
+  bool mUseTexture;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* __DALI_TOOLKIT_INTERNAL_MESH_RENDERER_H__ */
index fb62e8c..fe00209 100644 (file)
@@ -32,6 +32,7 @@
 #include <dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/image/image-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/svg/svg-renderer.h>
+#include <dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
@@ -82,7 +83,7 @@ RendererFactory::RendererType RendererFactory::GetRendererType( const Property::
   std::string typeValue ;
   if( type && type->Get( typeValue ))
   {
-    if( typeValue ==  COLOR_RENDERER )
+    if( typeValue == COLOR_RENDERER )
     {
       rendererType = COLOR;
     }
@@ -90,14 +91,18 @@ RendererFactory::RendererType RendererFactory::GetRendererType( const Property::
     {
       rendererType = BORDER;
     }
-    else if( typeValue ==  GRADIENT_RENDERER )
+    else if( typeValue == GRADIENT_RENDERER )
     {
       rendererType = GRADIENT;
     }
-    else if( typeValue ==  IMAGE_RENDERER )
+    else if( typeValue == IMAGE_RENDERER )
     {
       rendererType = IMAGE;
     }
+    else if( typeValue == MESH_RENDERER )
+    {
+      rendererType = MESH;
+    }
   }
 
   // check the url if exist, to decide the renderer type
@@ -177,6 +182,11 @@ Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Ma
       rendererPtr = new SvgRenderer( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
       break;
     }
+    case MESH:
+    {
+      rendererPtr = new MeshRenderer( *( mFactoryCache.Get() ) );
+      break;
+    }
     case UNDEFINED:
     default:
     {
@@ -444,12 +454,13 @@ void RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, Actor&
 
     //If there's no renderer type specified or if there hasn't been a renderer type change then we can reuse the renderer
     if( type == UNDEFINED ||
-        ( type == IMAGE    && typeid( controlRenderer ) == typeid( ImageRenderer ) ) ||
-        ( type == N_PATCH  && typeid( controlRenderer ) == typeid( NPatchRenderer ) ) ||
-        ( type == COLOR    && typeid( controlRenderer ) == typeid( ColorRenderer ) )||
-        ( type == GRADIENT && typeid( controlRenderer ) == typeid( GradientRenderer ) ) ||
-        ( type == BORDER   && typeid( controlRenderer ) == typeid( BorderRenderer ) ) ||
-        ( type == SVG      && typeid( controlRenderer ) == typeid( SvgRenderer ) ) )
+        ( type == IMAGE     && typeid( controlRenderer ) == typeid( ImageRenderer ) ) ||
+        ( type == N_PATCH   && typeid( controlRenderer ) == typeid( NPatchRenderer ) ) ||
+        ( type == COLOR     && typeid( controlRenderer ) == typeid( ColorRenderer ) ) ||
+        ( type == GRADIENT  && typeid( controlRenderer ) == typeid( GradientRenderer ) ) ||
+        ( type == BORDER    && typeid( controlRenderer ) == typeid( BorderRenderer ) ) ||
+        ( type == SVG       && typeid( controlRenderer ) == typeid( SvgRenderer ) ) ||
+        ( type == MESH      && typeid( controlRenderer ) == typeid( MeshRenderer ) ) )
     {
       controlRenderer.Initialize( actor, propertyMap );
       return;
@@ -485,4 +496,3 @@ void RendererFactory::CreateAtlasManager()
 } // namespace Toolkit
 
 } // namespace Dali
-
index ef01bd1..a5eb87a 100644 (file)
@@ -32,9 +32,17 @@ const char * const COLOR_RENDERER("color");
 const char * const BORDER_RENDERER("border");
 const char * const GRADIENT_RENDERER("gradient");
 const char * const IMAGE_RENDERER("image");
+const char * const MESH_RENDERER("mesh");
 
 const char * const IMAGE_URL_NAME("url");
 const char * const ATLAS_RECT_UNIFORM_NAME ( "uAtlasRect" );
+const char * const COLOR( "color" );
+
+//Mesh properties
+const char * const OBJECT_URL( "objectUrl" );
+const char * const MATERIAL_URL( "materialUrl" );
+const char * const TEXTURES_PATH( "texturesPath" );
+const char * const SHADER_TYPE( "shaderType" );
 
 } // namespace Internal
 
index ebaf29f..51e13f0 100644 (file)
@@ -32,9 +32,17 @@ extern const char * const COLOR_RENDERER;
 extern const char * const BORDER_RENDERER;
 extern const char * const GRADIENT_RENDERER;
 extern const char * const IMAGE_RENDERER;
+extern const char * const MESH_RENDERER;
 
 extern const char * const IMAGE_URL_NAME;
 extern const char * const ATLAS_RECT_UNIFORM_NAME;
+extern const char * const COLOR;
+
+//Mesh properties
+extern const char * const OBJECT_URL;
+extern const char * const MATERIAL_URL;
+extern const char * const TEXTURES_PATH;
+extern const char * const SHADER_TYPE;
 
 } // namespace Internal
 
index e5d0dc1..a33845e 100644 (file)
@@ -27,6 +27,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/renderers/gradient/gradient-renderer.cpp \
    $(toolkit_src_dir)/controls/renderers/svg/svg-rasterize-thread.cpp \
    $(toolkit_src_dir)/controls/renderers/svg/svg-renderer.cpp \
+   $(toolkit_src_dir)/controls/renderers/mesh/mesh-renderer.cpp \
    $(toolkit_src_dir)/controls/alignment/alignment-impl.cpp \
    $(toolkit_src_dir)/controls/bloom-view/bloom-view-impl.cpp \
    $(toolkit_src_dir)/controls/bubble-effect/bubble-emitter-impl.cpp \
index 536df51..85b8aa8 100644 (file)
@@ -83,7 +83,6 @@ public:
     DIFFUSE_WITH_NORMAL_MAP
   };
 
-
   /**
    * @brief Create a new instance of a Model3dView control.
    *
diff --git a/docs/content/images/renderers/mesh-renderer.png b/docs/content/images/renderers/mesh-renderer.png
new file mode 100644 (file)
index 0000000..d5e8ca0
Binary files /dev/null and b/docs/content/images/renderers/mesh-renderer.png differ
index b19b5dd..6930b03 100644 (file)
@@ -14,6 +14,7 @@ DALi provides the following renderers:
  + [Gradient](@ref gradient-renderer)
  + [Image](@ref image-renderers)
  + [Border](@ref border-renderer)
+ + [Mesh](@ref mesh-renderer)
  
 Controls can provide properties that allow users to specify the renderer type.
 Setting renderer properties are done via a property map.
@@ -423,6 +424,42 @@ control.background =
 };
 ~~~
 
+___________________________________________________________________________________________________
+
+## Mesh Renderer {#mesh-renderer}
+
+Renders a mesh using a .obj file, optionally with textures provided by a mtl file. Scaled to fit the control.
+
+![ ](../assets/img/renderers/mesh-renderer.png)
+![ ](renderers/mesh-renderer.png)
+
+### Properties Supported
+
+**RendererType** "mesh"
+
+| Property Name | Type    | Required           | Description                                                          |
+|---------------|:-------:|:------------------:|----------------------------------------------------------------------|
+| objectUrl     | STRING  | Yes                | The location of the .obj file.                                       |
+| materialUrl   | STRING  | No                 | The location of the .mtl file. Leave blank for a textureless object. |
+| texturesPath  | STRING  | If using material  | Path to the directory textures (including gloss and normal) are stored in.   |
+| shaderType    | STRING  | No                 | Sets the type of shader to be used with the mesh. Note that if anything the shader requires is missing, it will use a simpler one that it can handle with what has been supplied.\n Possible values: "textureless", "diffuseTexture", "allTextures".  |
+
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ "rendererType" ] = "mesh";
+map[ "objectUrl"    ] = "home/models/Dino.obj";
+map[ "materialUrl"  ] = "home/models/Dino.mtl";
+map[ "texturesPath" ] = "home/images/";
+
+control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
+~~~
+
 @class _Guide_Control_Renderers
 
 */