From: Andrew Poor Date: Wed, 1 Jun 2016 15:49:24 +0000 (+0100) Subject: Implemented a mesh renderer to display 3D objects from files. X-Git-Tag: dali_1.1.40~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=b00bd1f5f0925dcdf424567116cc208efc48d769 Implemented a mesh renderer to display 3D objects from files. Change-Id: I6adb4086a563b45e5644302181c4b898f2d5f100 --- diff --git a/automated-tests/resources/Cube.obj b/automated-tests/resources/Cube.obj new file mode 100644 index 0000000..e9bc9b4 --- /dev/null +++ b/automated-tests/resources/Cube.obj @@ -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 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 index 0000000..f699daf --- /dev/null +++ b/automated-tests/resources/ToyRobot-Metal-Simple.mtl @@ -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 index 0000000..cab3ae2 --- /dev/null +++ b/automated-tests/resources/ToyRobot-Metal.mtl @@ -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 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 index 0000000..93d98cd Binary files /dev/null and b/automated-tests/resources/tbcol.png differ diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp index d524b81..0983366 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp @@ -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() == "mesh" ); + + value = resultMap.Find( "objectUrl", Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == TEST_OBJ_FILE_NAME ); + + value = resultMap.Find( "materialUrl", Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == TEST_MTL_FILE_NAME ); + + value = resultMap.Find( "texturesPath", Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == TEST_RESOURCE_LOCATION ); + + value = resultMap.Find( "shaderType", Property::STRING ); + DALI_TEST_CHECK( value ); + DALI_TEST_CHECK( value->Get() == "textureless" ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp index 89bc1a1..d813261 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp @@ -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( "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( "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( "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( "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( "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( "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( "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( "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(), 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( "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( "mixColor", actualValue ) ); + DALI_TEST_EQUALS( actualValue, Color::GREEN, TEST_LOCATION ); + + //****** + + END_TEST; +} diff --git a/dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h b/dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h index c6fc451..fb52bf3 100644 --- a/dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h +++ b/dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h @@ -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. */ diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp index d395fb2..eac2d89 100644 --- a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp +++ b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp @@ -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 diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h index 8e44911..9c24faa 100644 --- a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h +++ b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h @@ -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 diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp b/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp index bc4e174..aaf7c60 100644 --- a/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp +++ b/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp @@ -19,6 +19,7 @@ #include "obj-loader.h" // EXTERNAL INCLUDES +#include #include #include #include @@ -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& vertex, Dali::Vector& normal, Dali::Vector& tangent) { - normal.Clear(); - normal.Resize(vertex.Size()); - Dali::Vector tangents; tangents.Resize( vertex.Size() ); @@ -172,12 +174,16 @@ void ObjLoader::CreateGeometryArray(Dali::Vector & 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 & 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; } diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.h b/dali-toolkit/internal/controls/model3d-view/obj-loader.h index 0a9ea25..0336323 100644 --- a/dali-toolkit/internal/controls/model3d-view/obj-loader.h +++ b/dali-toolkit/internal/controls/model3d-view/obj-loader.h @@ -20,10 +20,7 @@ // EXTERNAL INCLUDES #include - -// INTERNAL INCLUDES -#include - +#include 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::max(), std::numeric_limits::max(), std::numeric_limits::max() ); + pointMax = Vector3( std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::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 mBiTangents; Dali::Vector mTriangles; - void CalculateTangentArray(const Dali::Vector& vertex, - const Dali::Vector& texcoord, - Dali::Vector& triangle, - Dali::Vector& normal, - Dali::Vector& tangent); + void CalculateTangentArray( const Dali::Vector& vertex, + const Dali::Vector& texcoord, + Dali::Vector& triangle, + Dali::Vector& normal, + Dali::Vector& tangent ); - void CenterAndScale(bool center, Dali::Vector& points); + void CenterAndScale( bool center, Dali::Vector& points ); - void CreateGeometryArray(Dali::Vector & vertices, - Dali::Vector & textures, - Dali::Vector & verticesExt, - Dali::Vector & indices); + void CreateGeometryArray( Dali::Vector & vertices, + Dali::Vector & textures, + Dali::Vector & verticesExt, + Dali::Vector & 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 index 0000000..8b3256d --- /dev/null +++ b/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.cpp @@ -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 +#include +#include +#include +#include + +//INTERNAL INCLUDES +#include +#include +#include +#include + +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& 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 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 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 index 0000000..ede12fb --- /dev/null +++ b/dali-toolkit/internal/controls/renderers/mesh/mesh-renderer.h @@ -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 +#include + +// INTERNAL INCLUDES +#include +#include + +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& 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__ */ diff --git a/dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp b/dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp index fb62e8c..fe00209 100644 --- a/dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp +++ b/dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -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 - diff --git a/dali-toolkit/internal/controls/renderers/renderer-factory-impl.h b/dali-toolkit/internal/controls/renderers/renderer-factory-impl.h index b9d5cf1..87e321f 100644 --- a/dali-toolkit/internal/controls/renderers/renderer-factory-impl.h +++ b/dali-toolkit/internal/controls/renderers/renderer-factory-impl.h @@ -54,6 +54,7 @@ public: IMAGE, N_PATCH, SVG, + MESH, UNDEFINED }; diff --git a/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp b/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp index ef01bd1..a5eb87a 100644 --- a/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp +++ b/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp @@ -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 diff --git a/dali-toolkit/internal/controls/renderers/renderer-string-constants.h b/dali-toolkit/internal/controls/renderers/renderer-string-constants.h index ebaf29f..51e13f0 100644 --- a/dali-toolkit/internal/controls/renderers/renderer-string-constants.h +++ b/dali-toolkit/internal/controls/renderers/renderer-string-constants.h @@ -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 diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index e5d0dc1..a33845e 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -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 \ diff --git a/dali-toolkit/public-api/controls/model3d-view/model3d-view.h b/dali-toolkit/public-api/controls/model3d-view/model3d-view.h index 536df51..85b8aa8 100644 --- a/dali-toolkit/public-api/controls/model3d-view/model3d-view.h +++ b/dali-toolkit/public-api/controls/model3d-view/model3d-view.h @@ -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 index 0000000..d5e8ca0 Binary files /dev/null and b/docs/content/images/renderers/mesh-renderer.png differ diff --git a/docs/content/shared-javascript-and-cpp-documentation/control-renderers.md b/docs/content/shared-javascript-and-cpp-documentation/control-renderers.md index b19b5dd..6930b03 100644 --- a/docs/content/shared-javascript-and-cpp-documentation/control-renderers.md +++ b/docs/content/shared-javascript-and-cpp-documentation/control-renderers.md @@ -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 */