<ui-application appid="ray-marching.example" exec="/usr/apps/com.samsung.dali-demo/bin/ray-marching.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
<label>Ray Marching example</label>
</ui-application>
+ <ui-application appid="reflection-demo.example" exec="/usr/apps/com.samsung.dali-demo/bin/reflection-demo.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
+ <label>Reflection effect</label>
+ </ui-application>
<ui-application appid="refraction-effect.example" exec="/usr/apps/com.samsung.dali-demo/bin/refraction-effect.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
<label>Refraction effect</label>
</ui-application>
demo.AddExample(Example("metaball-refrac.example", DALI_DEMO_STR_TITLE_METABALL_REFRAC));
demo.AddExample(Example("motion-blur.example", DALI_DEMO_STR_TITLE_MOTION_BLUR));
demo.AddExample(Example("page-turn-view.example", DALI_DEMO_STR_TITLE_PAGE_TURN));
+ demo.AddExample(Example("reflection-demo.example", DALI_DEMO_STR_TITLE_REFLECTION));
demo.AddExample(Example("refraction-effect.example", DALI_DEMO_STR_TITLE_REFRACTION));
demo.AddExample(Example("renderer-stencil.example", DALI_DEMO_STR_TITLE_RENDERER_STENCIL));
demo.AddExample(Example("shadows-and-lights.example", DALI_DEMO_STR_TITLE_LIGHTS_AND_SHADOWS));
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+
+#include "gltf-scene.h"
+
+#include "pico-json.h"
+
+namespace
+{
+// string contains enum type index encoded matching glTFAttributeType
+const std::vector<std::string> GLTF_STR_ATTRIBUTE_TYPE = {
+ "POSITION",
+ "NORMAL",
+ "TEXCOORD_0"
+};
+
+const std::vector<std::pair<std::string, uint32_t>> GLTF_STR_COMPONENT_TYPE = {
+ std::make_pair( "VEC2", 2 ),
+ std::make_pair( "VEC3", 3 ),
+ std::make_pair( "VEC4", 4 ),
+ std::make_pair( "SCALAR", 1 )
+};
+
+glTFAttributeType glTFAttributeTypeStrToEnum( const std::string& name )
+{
+ int index = -1;
+ auto iter = std::find_if( GLTF_STR_ATTRIBUTE_TYPE.begin(), GLTF_STR_ATTRIBUTE_TYPE.end(),
+ [name, &index]( const std::string& val )
+ {
+ index++;
+ return val == name;
+ });
+ if( iter == GLTF_STR_ATTRIBUTE_TYPE.end() )
+ {
+ return glTFAttributeType::UNDEFINED;
+ }
+
+ return static_cast<glTFAttributeType>(index);
+}
+
+uint32_t glTFComponentTypeStrToNum( const std::string& name )
+{
+ auto iter = std::find_if( GLTF_STR_COMPONENT_TYPE.begin(), GLTF_STR_COMPONENT_TYPE.end(),
+ [name]( const std::pair<std::string, uint32_t>& val )
+ {
+ return val.first == name;
+ });
+ if( iter == GLTF_STR_COMPONENT_TYPE.end() )
+ {
+ return 0;
+ }
+
+ return iter->second;
+}
+
+template<class T>
+struct JsonResult
+{
+ bool success;
+ T result;
+ operator T() const
+ {
+ return static_cast<T>(result);
+ }
+};
+
+template<>
+struct JsonResult<bool>
+{
+ bool success;
+ bool result;
+
+ operator bool() const
+ {
+ return result;
+ }
+};
+
+template<class Expected, class Converted = Expected>
+JsonResult<picojson::value> JsonFindValue( const picojson::object& object, const std::string& name )
+{
+ auto iter = find_if(object.begin(), object.end(), [name](decltype(*object.begin())& item)
+ {
+ return item.first == name;
+ });
+
+ if(iter == object.end())
+ {
+ return {false};
+ }
+
+ return {true, iter->second};
+};
+
+
+template<class Expected, class Converted = Expected>
+JsonResult<Converted> JsonGetValue( const picojson::value& val, const std::string& name, const Converted& onFail )
+{
+ if( val.contains(name) )
+ {
+ return {true, static_cast<Converted>(val.get(name).get<Expected>())};
+ }
+ return {false, onFail};
+}
+
+template<class Expected, class Converted = Expected>
+bool JsonGetValueOut( const picojson::value& val, const std::string& name, Converted& writeOut )
+{
+ if( val.contains(name) )
+ {
+ writeOut = static_cast<Converted>(val.get(name).get<Expected>());
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Safe json value accessor
+ */
+template<class Expected, class Converted = Expected>
+JsonResult<std::vector<Converted>> JsonGetArray( const picojson::value& val, const std::string& name, std::vector<Converted> valueOnFail = {} )
+{
+ if(val.contains(name) )
+ {
+ const auto& array = val.get(name).get<picojson::array>();
+ std::vector<Converted> result{};
+ for( const auto& item : array )
+ {
+ result.emplace_back( static_cast<Converted>(item.get<Expected>()) );
+ }
+ return {true, result};
+ }
+ return {false, valueOnFail};
+}
+
+}
+
+glTF::glTF(const std::string& filename)
+{
+ LoadFromFile(filename);
+ ParseJSON();
+}
+
+void glTF::LoadFromFile( const std::string& filename )
+{
+ std::string jsonFile( filename );
+ jsonFile += ".gltf";
+ std::string binFile( filename );
+ binFile += ".bin";
+
+ // load binary
+
+ GLTF_LOG("LoadFromFile: %s", binFile.c_str());
+ mBuffer = LoadFile(binFile);
+ jsonBuffer = LoadFile(jsonFile);
+
+ // Log errors
+ if(mBuffer.empty())
+ {
+ GLTF_LOG("Error, buffer empty!");
+ }
+ else
+ {
+ GLTF_LOG( "GLTF[BIN]: %s loaded, size = %d", binFile.c_str(), int(mBuffer.size()));
+ }
+ if(jsonBuffer.empty())
+ {
+ GLTF_LOG("Error, buffer GLTF empty!");
+ }
+ else
+ {
+ GLTF_LOG( "GLTF: %s loaded, size = %d", binFile.c_str(), int(mBuffer.size()));
+ }
+
+ // Abort if errors
+ if(jsonBuffer.empty() || mBuffer.empty())
+ {
+ return;
+ }
+
+ // parse json
+ auto err = picojson::parse(jsonNode, std::string(reinterpret_cast<char*>(jsonBuffer.data())));
+ if(!err.empty())
+ {
+ GLTF_LOG( "GLTF: Error parsing %s, error: %s", jsonFile.c_str(), err.c_str());
+ return;
+ }
+ else
+ {
+ GLTF_LOG( "GLTF: %s loaded, size = %d", jsonFile.c_str(), int(jsonBuffer.size()));
+ }
+}
+
+bool glTF::ParseJSON()
+{
+ if (!jsonNode.is<picojson::object>())
+ {
+ return false;
+ }
+
+ // Add dummy first node to nodes (scene node)
+ mNodes.emplace_back();
+
+ // Sources for textures to be resolved later
+ std::vector<uint32_t> textureSources{};
+ std::vector<glTF_Texture> images{};
+
+ for( auto& val : jsonNode.get<picojson::object>() )
+ {
+ GLTF_LOG( "node: %s", val.first.c_str());
+
+ // Parse bufferviews
+ if( val.first == "bufferViews" )
+ {
+ auto bufferViews = val.second;
+ for( auto& view : bufferViews.get<picojson::array>() )
+ {
+ auto bufferIndex = uint32_t(view.get("buffer").get<double>());
+ auto byteLength = uint32_t(view.get("byteLength").get<double>());
+ auto byteOffset = uint32_t(view.get("byteOffset").get<double>());
+
+ glTF_BufferView bufferView{};
+ bufferView.bufferIndex = bufferIndex;
+ bufferView.byteLength = byteLength;
+ bufferView.byteOffset = byteOffset;
+
+ mBufferViews.emplace_back( bufferView );
+ }
+ }
+
+ // parse accessors
+ else if( val.first == "accessors" )
+ {
+ for( const auto& accessor : val.second.get<picojson::array>() )
+ {
+ auto gltfAccessor = glTF_Accessor{};
+ gltfAccessor.bufferView = uint32_t(accessor.get( "bufferView" ).get<double>());
+ gltfAccessor.componentType = uint32_t(accessor.get( "componentType" ).get<double>());
+ gltfAccessor.count = uint32_t(accessor.get( "count" ).get<double>());
+ gltfAccessor.type = accessor.get( "type" ).get<std::string>();
+ gltfAccessor.componentSize = glTFComponentTypeStrToNum( gltfAccessor.type );
+ mAccessors.emplace_back( gltfAccessor );
+ }
+ }
+
+ // parse meshes
+ else if( val.first == "meshes" )
+ {
+ for( const auto& mesh : val.second.get<picojson::array>() )
+ {
+ glTF_Mesh gltfMesh{};
+ gltfMesh.name = mesh.get( "name" ).get<std::string>();
+
+ // get primitives (in this implementation assuming single mesh consists of
+ // one and only one primitive)
+ const auto& primitive = mesh.get("primitives").get<picojson::array>()[0];
+ const auto& attrs = primitive.get("attributes").get<picojson::object>();
+ for( const auto& attr : attrs )
+ {
+ auto type = glTFAttributeTypeStrToEnum( attr.first );
+ auto bvIndex = uint32_t(attr.second.get<double>());
+ gltfMesh.attributes.emplace_back( std::make_pair( type, bvIndex ) );
+ GLTF_LOG("GLTF: ATTR: type: %d, index: %d", int(type), int(bvIndex));
+ }
+
+ gltfMesh.indices = uint32_t(primitive.get("indices").get<double>());
+ gltfMesh.material = uint32_t(primitive.get("material").get<double>());
+ mMeshes.emplace_back( gltfMesh );
+ }
+ }
+ // parse cameras
+ else if( val.first == "cameras" )
+ {
+ glTF_Camera tgifCamera{};
+ for( const auto& camera : val.second.get<picojson::array>() )
+ {
+ tgifCamera.name = camera.get( "name" ).to_str();
+ tgifCamera.isPerspective = (camera.get( "type" ).to_str() == "perspective" );
+ if(tgifCamera.isPerspective)
+ {
+ const auto& perspective = camera.get( "perspective" );
+ tgifCamera.yfov = static_cast<float>(perspective.get( "yfov" ).get<double>());
+ tgifCamera.zfar = static_cast<float>(perspective.get( "zfar" ).get<double>());
+ tgifCamera.znear = static_cast<float>(perspective.get( "znear" ).get<double>());
+ }
+
+ mCameras.emplace_back( tgifCamera );
+ }
+ }
+ // parse nodes
+ else if( val.first == "nodes" )
+ {
+ auto nodeIndex = 1u;
+ for( const auto& node : val.second.get<picojson::array>() )
+ {
+ glTF_Node gltfNode{};
+ gltfNode.name = node.get( "name" ).to_str();
+ auto rotation = JsonGetArray<double, float>( node, "rotation", {0.0f, 0.0f, 0.0f, 1.0f} );
+ auto translation = JsonGetArray<double, float>( node, "translation", {0.0f, 0.0f, 0.0f} );
+ auto scale = JsonGetArray<double, float>( node, "scale", {1.0f, 1.0f, 1.0f} );
+ std::copy( rotation.result.begin(), rotation.result.end(), gltfNode.rotationQuaternion );
+ std::copy( translation.result.begin(), translation.result.end(), gltfNode.translation );
+ std::copy( scale.result.begin(), scale.result.end(), gltfNode.scale );
+
+ auto children = JsonGetArray<double, uint32_t>( node, "children" );
+ if(children.success)
+ {
+ gltfNode.children = std::move(children.result);
+ }
+ gltfNode.index = nodeIndex;
+ gltfNode.cameraId = 0xffffffff;
+ gltfNode.meshId = 0xffffffff;
+
+ auto cameraId = JsonGetValue<double, uint32_t>( node, "camera", 0xffffffff );
+ if( cameraId.success )
+ {
+ gltfNode.cameraId = cameraId.result;
+ }
+ auto meshId = JsonGetValue<double, uint32_t>( node, "mesh", 0xffffffff );
+ if( meshId.success )
+ {
+ gltfNode.meshId = meshId.result;
+ }
+ mNodes.emplace_back( gltfNode );
+ ++nodeIndex;
+ }
+
+ }
+ // parse scenes, note: only first scene is being parsed
+ else if( val.first == "scenes" )
+ {
+ auto& sceneNode = mNodes[0];
+ const auto& scene = val.second.get<picojson::array>()[0];
+ sceneNode.name = JsonGetValue<std::string>( scene, "name", std::string() );
+ auto result = JsonGetArray<double, uint32_t>( scene, "nodes" );
+ sceneNode.children = result.result;
+ sceneNode.index = 0;
+ }
+ else if( val.first == "materials" )
+ {
+ for( const auto& node : val.second.get<picojson::array>() )
+ {
+ // Get pbr material, base color texture
+ glTF_Material material{};
+ material.doubleSided = JsonGetValue<bool>( node, "doubleSided", false ).result;
+ material.name = JsonGetValue<std::string>( node, "name", std::string() ).result;
+ if( node.contains("pbrMetallicRoughness") )
+ {
+ const auto& node0 = node.get("pbrMetallicRoughness");
+ if(node0.contains("baseColorTexture"))
+ {
+ const auto& node1 = node0.get("baseColorTexture");
+ auto index = uint32_t(node1.get("index").get<double>());
+ auto texCoord = uint32_t(node1.get("texCoord").get<double>());
+ material.pbrMetallicRoughness.enabled = true;
+ material.pbrMetallicRoughness.baseTextureColor.index = index;
+ material.pbrMetallicRoughness.baseTextureColor.texCoord = texCoord;
+ }
+ }
+ mMaterials.emplace_back( material );
+ }
+ }
+ else if( val.first == "textures" )
+ {
+ for(const auto& item : val.second.get<picojson::array>() )
+ {
+ auto source = JsonGetValue<double, uint32_t>( item, "source", 0xffffffff );
+ textureSources.emplace_back( source.result );
+ }
+ }
+ else if( val.first == "images" )
+ {
+ for(const auto& item : val.second.get<picojson::array>() )
+ {
+ glTF_Texture tex{};
+ JsonGetValueOut<std::string>( item, "name", tex.name );
+ JsonGetValueOut<std::string>( item, "uri", tex.uri );
+ images.emplace_back( tex );
+ }
+ }
+ }
+
+ // Resolve cross-referencing
+ for( const auto& source : textureSources )
+ {
+ mTextures.emplace_back( images[source] );
+ }
+
+ return true;
+}
+
+glTF_Buffer glTF::LoadFile( const std::string& filename )
+{
+ Dali::FileStream fileStream( filename.c_str(), Dali::FileStream::READ | Dali::FileStream::BINARY );
+ FILE* fin = fileStream.GetFile();
+ std::vector<unsigned char> buffer;
+ if( fin )
+ {
+ fseek( fin, 0, SEEK_END );
+ auto size = ftell(fin);
+ fseek( fin, 0, SEEK_SET );
+ buffer.resize(unsigned(size));
+ auto result = fread( buffer.data(), 1, size_t(size), fin );
+ if( result < 0 )
+ {
+ GLTF_LOG("LoadFile: Result: %d", int(result));
+ // return empty buffer
+ return {};
+ }
+ }
+ else
+ {
+ GLTF_LOG("LoadFile: Can't open file: errno = %d", errno);
+ }
+
+ return buffer;
+}
+
+std::vector<const glTF_Mesh*> glTF::GetMeshes() const
+{
+ std::vector<const glTF_Mesh*> retval;
+ for( auto& mesh : mMeshes )
+ {
+ retval.emplace_back( &mesh );
+ }
+ return retval;
+}
+
+std::vector<const glTF_Camera*> glTF::GetCameras()
+{
+ std::vector<const glTF_Camera*> cameras;
+ for( const auto& cam : mCameras )
+ {
+ cameras.emplace_back( &cam );
+ }
+ return cameras;
+}
+
+std::vector<unsigned char> glTF::GetMeshAttributeBuffer( const glTF_Mesh& mesh, const std::vector<glTFAttributeType>& attrTypes )
+{
+ // find buffer views
+ struct Data
+ {
+ uint32_t accessorIndex{0u};
+ uint32_t byteStride{0u};
+ char* srcPtr{ nullptr };
+ };
+ std::vector<Data> data{};
+ for( const auto& attrType : attrTypes )
+ {
+ std::find_if( mesh.attributes.begin(), mesh.attributes.end(), [&data, &attrType]( const std::pair<glTFAttributeType, uint32_t>& item ){
+ if( item.first == attrType )
+ {
+ data.emplace_back();
+ data.back().accessorIndex = item.second;
+ }
+ return false;
+ });
+ }
+
+ if(data.empty())
+ {
+ return {};
+ }
+
+ // number of attributes is same for the whole mesh so using very first
+ // accessor
+
+ glTF_Buffer retval{};
+
+ // data is interleaved
+ if( data.size() > 1 )
+ {
+ auto attributeCount = mAccessors[data[0].accessorIndex].count;// / mAccessors[data[0].accessorIndex].componentSize;
+ uint32_t attributeStride = 0;
+ // now find buffer view stride for particular accessor
+ for( auto& item : data )
+ {
+ auto& accessor = mAccessors[item.accessorIndex];
+
+ // Update byte stride for this buffer view
+ auto& bufferView = mBufferViews[accessor.bufferView];
+ item.byteStride = bufferView.byteLength / attributeCount;
+ attributeStride += item.byteStride;
+ item.srcPtr = reinterpret_cast<char*>(mBuffer.data()) + bufferView.byteOffset;
+ }
+
+ // now allocate final buffer and interleave data
+ retval.resize( attributeStride * attributeCount );
+ auto* dstPtr = retval.data();
+ for( auto i = 0u; i < attributeCount; ++i )
+ {
+ for(auto& item : data )
+ {
+ std::copy( item.srcPtr,
+ item.srcPtr + item.byteStride,
+ reinterpret_cast<char*>(dstPtr) );
+ dstPtr += item.byteStride;
+ item.srcPtr += item.byteStride;
+ }
+ }
+ }
+ else // copy data directly as single buffer
+ {
+ auto& bufferView = mBufferViews[mAccessors[data[0].accessorIndex].bufferView];
+ retval.resize( bufferView.byteLength );
+ std::copy( mBuffer.begin() + bufferView.byteOffset,
+ mBuffer.begin() + bufferView.byteOffset + bufferView.byteLength,
+ retval.begin());
+
+ }
+ return retval;
+}
+
+
+const glTF_Mesh* glTF::FindMeshByName( const std::string& name ) const
+{
+ for( const auto& mesh : mMeshes )
+ {
+ if(mesh.name == name)
+ return &mesh;
+ }
+ return nullptr;
+}
+
+uint32_t glTF::GetMeshAttributeCount( const glTF_Mesh* mesh ) const
+{
+ const auto& accessor = mAccessors[mesh->attributes[0].second];
+ return accessor.count;// / accessor.componentSize;
+}
+
+std::vector<uint16_t> glTF::GetMeshIndexBuffer( const glTF_Mesh* mesh ) const
+{
+ // check GL component type
+ const auto& accessor = mAccessors[mesh->indices];
+ if( accessor.componentType == 0x1403 ) // GL_UNSIGNED_SHORT
+ {
+ std::vector<uint16_t> retval{};
+ retval.resize( accessor.count );
+ const auto& bufferView = mBufferViews[accessor.bufferView];
+ const auto* srcPtr = reinterpret_cast<const uint16_t*>
+ (reinterpret_cast<const char*>(mBuffer.data()) + bufferView.byteOffset);
+ std::copy( srcPtr, srcPtr + accessor.count, retval.data() );
+ return retval;
+ }
+ return {};
+}
+
+const glTF_Node* glTF::FindNodeByName( const std::string& name ) const
+{
+ auto iter = std::find_if( mNodes.begin(), mNodes.end(), [name]( const glTF_Node& node )
+ {
+ return !name.compare( node.name );
+ });
+
+ if(iter == mNodes.end())
+ {
+ return nullptr;
+ }
+
+ return &*iter;
+}
+
+const std::vector<glTF_Material>& glTF::GetMaterials() const
+{
+ return mMaterials;
+}
+
+const std::vector<glTF_Texture>& glTF::GetTextures() const
+{
+ return mTextures;
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+#ifndef GLTF_SCENE_H
+#define GLTF_SCENE_H
+
+#include <dali/integration-api/debug.h>
+
+#include <string>
+
+#include "pico-json.h"
+
+#define GLTF_LOG(...) {DALI_LOG_ERROR( __VA_ARGS__ );}
+
+enum class glTFAttributeType
+{
+ POSITION = 0,
+ NORMAL = 1,
+ TEXCOORD_0 = 2,
+ UNDEFINED,
+};
+
+struct glTF_Camera
+{
+ std::string name;
+
+ // perspective setup
+ float yfov;
+ float zfar;
+ float znear;
+
+ bool isPerspective;
+};
+
+struct glTF_BufferView
+{
+ uint32_t bufferIndex;
+ uint32_t byteLength;
+ uint32_t byteOffset;
+ void* data;
+};
+
+struct glTF_Accessor
+{
+ uint32_t bufferView;
+ uint32_t componentType;
+ uint32_t count;
+ uint32_t componentSize;
+ std::string type;
+};
+
+struct glTF_Mesh
+{
+ std::string name;
+ std::vector<std::pair<glTFAttributeType, uint32_t>> attributes;
+ uint32_t indices;
+ uint32_t material;
+};
+
+struct glTF_Texture
+{
+ std::string uri;
+ std::string name;
+};
+
+struct glTF_Material
+{
+ bool doubleSided;
+ std::string name;
+ struct pbrMetallicRoughness
+ {
+ bool enabled {false};
+ struct baseTextureColor
+ {
+ uint32_t index;
+ uint32_t texCoord;
+ } baseTextureColor;
+ } pbrMetallicRoughness;
+};
+
+struct glTF_Node
+{
+ uint32_t index{0u};
+ std::string name{};
+ uint32_t meshId { 0xffffffff };
+ uint32_t cameraId{ 0xffffffff };
+ glTF_Node* parent { nullptr };
+ std::vector<uint32_t> children {};
+
+ // Transform
+ float rotationQuaternion[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ float translation[3] = { 0.0f, 0.0f, 0.0f };
+ float scale[3] = { 1.0f, 1.0f, 1.0f };
+};
+
+using glTF_Buffer = std::vector<unsigned char>;
+
+/**
+ * Simple glTF parser
+ *
+ * This implementation requires 2 files (it doesn't decode Base64 embedded in json)
+ */
+struct glTF
+{
+
+ glTF( const std::string& filename );
+ ~glTF() = default;
+
+ std::vector<const glTF_Mesh*> GetMeshes() const;
+
+ std::vector<const glTF_Camera*> GetCameras();
+
+ const std::vector<glTF_Material>& GetMaterials() const;
+
+ const std::vector<glTF_Texture>& GetTextures() const;
+
+ const std::vector<glTF_Node>& GetNodes() const
+ {
+ return mNodes;
+ }
+
+ /**
+ * MESH interface
+ */
+ /**
+ * Returns a copy of attribute buffer
+ * @return
+ */
+ std::vector<unsigned char> GetMeshAttributeBuffer( const glTF_Mesh& mesh, const std::vector<glTFAttributeType>& attrTypes );
+ uint32_t GetMeshAttributeCount( const glTF_Mesh* mesh ) const;
+ const glTF_Mesh* FindMeshByName( const std::string& name ) const;
+
+ /**
+ * Returns a copy of index buffer
+ * @return
+ */
+ std::vector<uint16_t> GetMeshIndexBuffer( const glTF_Mesh* mesh ) const;
+
+ const glTF_Node* FindNodeByName( const std::string& name ) const;
+
+private:
+
+ void LoadFromFile( const std::string& filename );
+
+ glTF_Buffer LoadFile( const std::string& filename );
+
+ bool ParseJSON();
+
+ std::vector<glTF_Mesh> mMeshes;
+ std::vector<glTF_Camera> mCameras;
+ std::vector<glTF_BufferView> mBufferViews;
+ std::vector<glTF_Accessor> mAccessors;
+ std::vector<glTF_Node> mNodes;
+ std::vector<glTF_Material> mMaterials;
+ std::vector<glTF_Texture> mTextures;
+ glTF_Buffer mBuffer;
+ glTF_Buffer jsonBuffer;
+
+ // json nodes
+ picojson::value jsonNode;
+};
+
+
+#endif //DALI_CMAKE_GLTF_SCENE_H
--- /dev/null
+/*
+ * Copyright 2009-2010 Cybozu Labs, Inc.
+ * Copyright 2011-2014 Kazuho Oku
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef picojson_h
+#define picojson_h
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cstddef>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <utility>
+
+// for isnan/isinf
+#if __cplusplus>=201103L
+# include <cmath>
+#else
+extern "C" {
+# ifdef _MSC_VER
+# include <float.h>
+# elif defined(__INTEL_COMPILER)
+# include <mathimf.h>
+# else
+# include <math.h>
+# endif
+}
+#endif
+
+#ifndef PICOJSON_USE_RVALUE_REFERENCE
+# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+# define PICOJSON_USE_RVALUE_REFERENCE 1
+# else
+# define PICOJSON_USE_RVALUE_REFERENCE 0
+# endif
+#endif//PICOJSON_USE_RVALUE_REFERENCE
+
+
+// experimental support for int64_t (see README.mkdn for detail)
+#ifdef PICOJSON_USE_INT64
+# define __STDC_FORMAT_MACROS
+# include <errno.h>
+# include <inttypes.h>
+#endif
+
+// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
+#ifndef PICOJSON_USE_LOCALE
+# define PICOJSON_USE_LOCALE 1
+#endif
+#if PICOJSON_USE_LOCALE
+extern "C" {
+# include <locale.h>
+}
+#endif
+
+#ifndef PICOJSON_ASSERT
+# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0)
+#endif
+
+#ifdef _MSC_VER
+#define SNPRINTF _snprintf_s
+ #pragma warning(push)
+ #pragma warning(disable : 4244) // conversion from int to char
+ #pragma warning(disable : 4127) // conditional expression is constant
+ #pragma warning(disable : 4702) // unreachable code
+#else
+#define SNPRINTF snprintf
+#endif
+
+namespace picojson {
+
+enum {
+ null_type,
+ boolean_type,
+ number_type,
+ string_type,
+ array_type,
+ object_type
+#ifdef PICOJSON_USE_INT64
+ , int64_type
+#endif
+};
+
+enum {
+ INDENT_WIDTH = 2
+};
+
+struct null {};
+
+class value {
+public:
+ typedef std::vector<value> array;
+ typedef std::map<std::string, value> object;
+ union _storage {
+ bool boolean_;
+ double number_;
+#ifdef PICOJSON_USE_INT64
+ int64_t int64_;
+#endif
+ std::string* string_;
+ array* array_;
+ object* object_;
+ };
+protected:
+ int type_;
+ _storage u_;
+public:
+ value();
+ value(int type, bool);
+ explicit value(bool b);
+#ifdef PICOJSON_USE_INT64
+ explicit value(int64_t i);
+#endif
+ explicit value(double n);
+ explicit value(const std::string& s);
+ explicit value(const array& a);
+ explicit value(const object& o);
+ explicit value(const char* s);
+ value(const char* s, size_t len);
+ ~value();
+ value(const value& x);
+ value& operator=(const value& x);
+#if PICOJSON_USE_RVALUE_REFERENCE
+ value(value&& x)throw();
+ value& operator=(value&& x)throw();
+#endif
+ void swap(value& x)throw();
+ template <typename T> bool is() const;
+ template <typename T> const T& get() const;
+ template <typename T> T& get();
+ template <typename T> void set(const T &);
+#if PICOJSON_USE_RVALUE_REFERENCE
+ template <typename T> void set(T &&);
+#endif
+ bool evaluate_as_boolean() const;
+ const value& get(size_t idx) const;
+ const value& get(const std::string& key) const;
+ value& get(size_t idx);
+ value& get(const std::string& key);
+
+ bool contains(size_t idx) const;
+ bool contains(const std::string& key) const;
+ std::string to_str() const;
+ template <typename Iter> void serialize(Iter os, bool prettify = false) const;
+ std::string serialize(bool prettify = false) const;
+private:
+ template <typename T> value(const T*); // intentionally defined to block implicit conversion of pointer to bool
+ template <typename Iter> static void _indent(Iter os, int indent);
+ template <typename Iter> void _serialize(Iter os, int indent) const;
+ std::string _serialize(int indent) const;
+ void clear();
+};
+
+typedef value::array array;
+typedef value::object object;
+
+inline value::value() : type_(null_type) {}
+
+inline value::value(int type, bool) : type_(type) {
+ switch (type) {
+#define INIT(p, v) case p##type: u_.p = v; break
+ INIT(boolean_, false);
+ INIT(number_, 0.0);
+#ifdef PICOJSON_USE_INT64
+ INIT(int64_, 0);
+#endif
+ INIT(string_, new std::string());
+ INIT(array_, new array());
+ INIT(object_, new object());
+#undef INIT
+ default: break;
+ }
+}
+
+inline value::value(bool b) : type_(boolean_type) {
+ u_.boolean_ = b;
+}
+
+#ifdef PICOJSON_USE_INT64
+inline value::value(int64_t i) : type_(int64_type) {
+ u_.int64_ = i;
+ }
+#endif
+
+inline value::value(double n) : type_(number_type) {
+ if (
+#ifdef _MSC_VER
+! _finite(n)
+#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf))
+std::isnan(n) || std::isinf(n)
+#else
+ isnan(n) || isinf(n)
+#endif
+ ) {
+ throw std::overflow_error("");
+ }
+ u_.number_ = n;
+}
+
+inline value::value(const std::string& s) : type_(string_type) {
+ u_.string_ = new std::string(s);
+}
+
+inline value::value(const array& a) : type_(array_type) {
+ u_.array_ = new array(a);
+}
+
+inline value::value(const object& o) : type_(object_type) {
+ u_.object_ = new object(o);
+}
+
+inline value::value(const char* s) : type_(string_type) {
+ u_.string_ = new std::string(s);
+}
+
+inline value::value(const char* s, size_t len) : type_(string_type) {
+ u_.string_ = new std::string(s, len);
+}
+
+inline void value::clear() {
+ switch (type_) {
+#define DEINIT(p) case p##type: delete u_.p; break
+ DEINIT(string_);
+ DEINIT(array_);
+ DEINIT(object_);
+#undef DEINIT
+ default: break;
+ }
+}
+
+inline value::~value() {
+ clear();
+}
+
+inline value::value(const value& x) : type_(x.type_) {
+ switch (type_) {
+#define INIT(p, v) case p##type: u_.p = v; break
+ INIT(string_, new std::string(*x.u_.string_));
+ INIT(array_, new array(*x.u_.array_));
+ INIT(object_, new object(*x.u_.object_));
+#undef INIT
+ default:
+ u_ = x.u_;
+ break;
+ }
+}
+
+inline value& value::operator=(const value& x) {
+ if (this != &x) {
+ value t(x);
+ swap(t);
+ }
+ return *this;
+}
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+inline value::value(value&& x)throw() : type_(null_type) {
+ swap(x);
+}
+inline value& value::operator=(value&& x)throw() {
+ swap(x);
+ return *this;
+}
+#endif
+inline void value::swap(value& x)throw() {
+ std::swap(type_, x.type_);
+ std::swap(u_, x.u_);
+}
+
+#define IS(ctype, jtype) \
+ template <> inline bool value::is<ctype>() const { \
+ return type_ == jtype##_type; \
+ }
+IS(null, null)
+IS(bool, boolean)
+#ifdef PICOJSON_USE_INT64
+IS(int64_t, int64)
+#endif
+IS(std::string, string)
+IS(array, array)
+IS(object, object)
+#undef IS
+template <> inline bool value::is<double>() const {
+ return type_ == number_type
+#ifdef PICOJSON_USE_INT64
+ || type_ == int64_type
+#endif
+ ;
+}
+
+#define GET(ctype, var) \
+ template <> inline const ctype& value::get<ctype>() const { \
+ PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
+ && is<ctype>()); \
+ return var; \
+ } \
+ template <> inline ctype& value::get<ctype>() { \
+ PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" \
+ && is<ctype>()); \
+ return var; \
+ }
+GET(bool, u_.boolean_)
+GET(std::string, *u_.string_)
+GET(array, *u_.array_)
+GET(object, *u_.object_)
+#ifdef PICOJSON_USE_INT64
+GET(double, (type_ == int64_type && (const_cast<value*>(this)->type_ = number_type, const_cast<value*>(this)->u_.number_ = u_.int64_), u_.number_))
+ GET(int64_t, u_.int64_)
+#else
+GET(double, u_.number_)
+#endif
+#undef GET
+
+#define SET(ctype, jtype, setter) \
+ template <> inline void value::set<ctype>(const ctype &_val) { \
+ clear(); \
+ type_ = jtype##_type; \
+ setter \
+ }
+SET(bool, boolean, u_.boolean_ = _val;)
+SET(std::string, string, u_.string_ = new std::string(_val);)
+SET(array, array, u_.array_ = new array(_val);)
+SET(object, object, u_.object_ = new object(_val);)
+SET(double, number, u_.number_ = _val;)
+#ifdef PICOJSON_USE_INT64
+SET(int64_t, int64, u_.int64_ = _val;)
+#endif
+#undef SET
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+#define MOVESET(ctype, jtype, setter) \
+ template <> inline void value::set<ctype>(ctype &&_val) { \
+ clear(); \
+ type_ = jtype##_type; \
+ setter \
+ }
+MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));)
+MOVESET(array, array, u_.array_ = new array(std::move(_val));)
+MOVESET(object, object, u_.object_ = new object(std::move(_val));)
+#undef MOVESET
+#endif
+
+inline bool value::evaluate_as_boolean() const {
+ switch (type_) {
+ case null_type:
+ return false;
+ case boolean_type:
+ return u_.boolean_;
+ case number_type:
+ return u_.number_ != 0;
+#ifdef PICOJSON_USE_INT64
+ case int64_type:
+ return u_.int64_ != 0;
+#endif
+ case string_type:
+ return ! u_.string_->empty();
+ default:
+ return true;
+ }
+}
+
+inline const value& value::get(size_t idx) const {
+ static value s_null;
+ PICOJSON_ASSERT(is<array>());
+ return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
+}
+
+inline value& value::get(size_t idx) {
+ static value s_null;
+ PICOJSON_ASSERT(is<array>());
+ return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
+}
+
+inline const value& value::get(const std::string& key) const {
+ static value s_null;
+ PICOJSON_ASSERT(is<object>());
+ object::const_iterator i = u_.object_->find(key);
+ return i != u_.object_->end() ? i->second : s_null;
+}
+
+inline value& value::get(const std::string& key) {
+ static value s_null;
+ PICOJSON_ASSERT(is<object>());
+ object::iterator i = u_.object_->find(key);
+ return i != u_.object_->end() ? i->second : s_null;
+}
+
+inline bool value::contains(size_t idx) const {
+ PICOJSON_ASSERT(is<array>());
+ return idx < u_.array_->size();
+}
+
+inline bool value::contains(const std::string& key) const {
+ PICOJSON_ASSERT(is<object>());
+ object::const_iterator i = u_.object_->find(key);
+ return i != u_.object_->end();
+}
+
+inline std::string value::to_str() const {
+ switch (type_) {
+ case null_type: return "null";
+ case boolean_type: return u_.boolean_ ? "true" : "false";
+#ifdef PICOJSON_USE_INT64
+ case int64_type: {
+ char buf[sizeof("-9223372036854775808")];
+ SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
+ return buf;
+ }
+#endif
+ case number_type: {
+ char buf[256];
+ double tmp;
+ SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
+#if PICOJSON_USE_LOCALE
+ char *decimal_point = localeconv()->decimal_point;
+ if (strcmp(decimal_point, ".") != 0) {
+ size_t decimal_point_len = strlen(decimal_point);
+ for (char *p = buf; *p != '\0'; ++p) {
+ if (strncmp(p, decimal_point, decimal_point_len) == 0) {
+ return std::string(buf, p) + "." + (p + decimal_point_len);
+ }
+ }
+ }
+#endif
+ return buf;
+ }
+ case string_type: return *u_.string_;
+ case array_type: return "array";
+ case object_type: return "object";
+ default: PICOJSON_ASSERT(0);
+#ifdef _MSC_VER
+ __assume(0);
+#endif
+ }
+ return std::string();
+}
+
+template <typename Iter> void copy(const std::string& s, Iter oi) {
+ std::copy(s.begin(), s.end(), oi);
+}
+
+template <typename Iter>
+struct serialize_str_char {
+ Iter oi;
+ void operator()(char c) {
+ switch (c) {
+#define MAP(val, sym) case val: copy(sym, oi); break
+ MAP('"', "\\\"");
+ MAP('\\', "\\\\");
+ MAP('/', "\\/");
+ MAP('\b', "\\b");
+ MAP('\f', "\\f");
+ MAP('\n', "\\n");
+ MAP('\r', "\\r");
+ MAP('\t', "\\t");
+#undef MAP
+ default:
+ if (static_cast<unsigned char>(c) < 0x20 || c == 0x7f) {
+ char buf[7];
+ SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff);
+ copy(buf, buf + 6, oi);
+ } else {
+ *oi++ = c;
+ }
+ break;
+ }
+ }
+};
+
+template <typename Iter> void serialize_str(const std::string& s, Iter oi) {
+ *oi++ = '"';
+ serialize_str_char<Iter> process_char = { oi };
+ std::for_each(s.begin(), s.end(), process_char);
+ *oi++ = '"';
+}
+
+template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
+ return _serialize(oi, prettify ? 0 : -1);
+}
+
+inline std::string value::serialize(bool prettify) const {
+ return _serialize(prettify ? 0 : -1);
+}
+
+template <typename Iter> void value::_indent(Iter oi, int indent) {
+ *oi++ = '\n';
+ for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
+ *oi++ = ' ';
+ }
+}
+
+template <typename Iter> void value::_serialize(Iter oi, int indent) const {
+ switch (type_) {
+ case string_type:
+ serialize_str(*u_.string_, oi);
+ break;
+ case array_type: {
+ *oi++ = '[';
+ if (indent != -1) {
+ ++indent;
+ }
+ for (array::const_iterator i = u_.array_->begin();
+ i != u_.array_->end();
+ ++i) {
+ if (i != u_.array_->begin()) {
+ *oi++ = ',';
+ }
+ if (indent != -1) {
+ _indent(oi, indent);
+ }
+ i->_serialize(oi, indent);
+ }
+ if (indent != -1) {
+ --indent;
+ if (! u_.array_->empty()) {
+ _indent(oi, indent);
+ }
+ }
+ *oi++ = ']';
+ break;
+ }
+ case object_type: {
+ *oi++ = '{';
+ if (indent != -1) {
+ ++indent;
+ }
+ for (object::const_iterator i = u_.object_->begin();
+ i != u_.object_->end();
+ ++i) {
+ if (i != u_.object_->begin()) {
+ *oi++ = ',';
+ }
+ if (indent != -1) {
+ _indent(oi, indent);
+ }
+ serialize_str(i->first, oi);
+ *oi++ = ':';
+ if (indent != -1) {
+ *oi++ = ' ';
+ }
+ i->second._serialize(oi, indent);
+ }
+ if (indent != -1) {
+ --indent;
+ if (! u_.object_->empty()) {
+ _indent(oi, indent);
+ }
+ }
+ *oi++ = '}';
+ break;
+ }
+ default:
+ copy(to_str(), oi);
+ break;
+ }
+ if (indent == 0) {
+ *oi++ = '\n';
+ }
+}
+
+inline std::string value::_serialize(int indent) const {
+ std::string s;
+ _serialize(std::back_inserter(s), indent);
+ return s;
+}
+
+template <typename Iter> class input {
+protected:
+ Iter cur_, end_;
+ bool consumed_;
+ int line_;
+public:
+ input(const Iter& first, const Iter& last) : cur_(first), end_(last), consumed_(false), line_(1) {}
+ int getc() {
+ if (consumed_) {
+ if (*cur_ == '\n') {
+ ++line_;
+ }
+ ++cur_;
+ }
+ if (cur_ == end_) {
+ consumed_ = false;
+ return -1;
+ }
+ consumed_ = true;
+ return *cur_ & 0xff;
+ }
+ void ungetc() {
+ consumed_ = false;
+ }
+ Iter cur() const {
+ if (consumed_) {
+ input<Iter> *self = const_cast<input<Iter>*>(this);
+ self->consumed_ = false;
+ ++self->cur_;
+ }
+ return cur_;
+ }
+ int line() const { return line_; }
+ void skip_ws() {
+ while (1) {
+ int ch = getc();
+ if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
+ ungetc();
+ break;
+ }
+ }
+ }
+ bool expect(int expect) {
+ skip_ws();
+ if (getc() != expect) {
+ ungetc();
+ return false;
+ }
+ return true;
+ }
+ bool match(const std::string& pattern) {
+ for (std::string::const_iterator pi(pattern.begin());
+ pi != pattern.end();
+ ++pi) {
+ if (getc() != *pi) {
+ ungetc();
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+template<typename Iter> inline int _parse_quadhex(input<Iter> &in) {
+ int uni_ch = 0, hex;
+ for (int i = 0; i < 4; i++) {
+ if ((hex = in.getc()) == -1) {
+ return -1;
+ }
+ if ('0' <= hex && hex <= '9') {
+ hex -= '0';
+ } else if ('A' <= hex && hex <= 'F') {
+ hex -= 'A' - 0xa;
+ } else if ('a' <= hex && hex <= 'f') {
+ hex -= 'a' - 0xa;
+ } else {
+ in.ungetc();
+ return -1;
+ }
+ uni_ch = uni_ch * 16 + hex;
+ }
+ return uni_ch;
+}
+
+template<typename String, typename Iter> inline bool _parse_codepoint(String& out, input<Iter>& in) {
+ int uni_ch;
+ if ((uni_ch = _parse_quadhex(in)) == -1) {
+ return false;
+ }
+ if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
+ if (0xdc00 <= uni_ch) {
+ // a second 16-bit of a surrogate pair appeared
+ return false;
+ }
+ // first 16-bit of surrogate pair, get the next one
+ if (in.getc() != '\\' || in.getc() != 'u') {
+ in.ungetc();
+ return false;
+ }
+ int second = _parse_quadhex(in);
+ if (! (0xdc00 <= second && second <= 0xdfff)) {
+ return false;
+ }
+ uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
+ uni_ch += 0x10000;
+ }
+ if (uni_ch < 0x80) {
+ out.push_back(uni_ch);
+ } else {
+ if (uni_ch < 0x800) {
+ out.push_back(0xc0 | (uni_ch >> 6));
+ } else {
+ if (uni_ch < 0x10000) {
+ out.push_back(0xe0 | (uni_ch >> 12));
+ } else {
+ out.push_back(0xf0 | (uni_ch >> 18));
+ out.push_back(0x80 | ((uni_ch >> 12) & 0x3f));
+ }
+ out.push_back(0x80 | ((uni_ch >> 6) & 0x3f));
+ }
+ out.push_back(0x80 | (uni_ch & 0x3f));
+ }
+ return true;
+}
+
+template<typename String, typename Iter> inline bool _parse_string(String& out, input<Iter>& in) {
+ while (1) {
+ int ch = in.getc();
+ if (ch < ' ') {
+ in.ungetc();
+ return false;
+ } else if (ch == '"') {
+ return true;
+ } else if (ch == '\\') {
+ if ((ch = in.getc()) == -1) {
+ return false;
+ }
+ switch (ch) {
+#define MAP(sym, val) case sym: out.push_back(val); break
+ MAP('"', '\"');
+ MAP('\\', '\\');
+ MAP('/', '/');
+ MAP('b', '\b');
+ MAP('f', '\f');
+ MAP('n', '\n');
+ MAP('r', '\r');
+ MAP('t', '\t');
+#undef MAP
+ case 'u':
+ if (! _parse_codepoint(out, in)) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ } else {
+ out.push_back(ch);
+ }
+ }
+ return false;
+}
+
+template <typename Context, typename Iter> inline bool _parse_array(Context& ctx, input<Iter>& in) {
+ if (! ctx.parse_array_start()) {
+ return false;
+ }
+ size_t idx = 0;
+ if (in.expect(']')) {
+ return ctx.parse_array_stop(idx);
+ }
+ do {
+ if (! ctx.parse_array_item(in, idx)) {
+ return false;
+ }
+ idx++;
+ } while (in.expect(','));
+ return in.expect(']') && ctx.parse_array_stop(idx);
+}
+
+template <typename Context, typename Iter> inline bool _parse_object(Context& ctx, input<Iter>& in) {
+ if (! ctx.parse_object_start()) {
+ return false;
+ }
+ if (in.expect('}')) {
+ return true;
+ }
+ do {
+ std::string key;
+ if (! in.expect('"')
+ || ! _parse_string(key, in)
+ || ! in.expect(':')) {
+ return false;
+ }
+ if (! ctx.parse_object_item(in, key)) {
+ return false;
+ }
+ } while (in.expect(','));
+ return in.expect('}');
+}
+
+template <typename Iter> inline std::string _parse_number(input<Iter>& in) {
+ std::string num_str;
+ while (1) {
+ int ch = in.getc();
+ if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-'
+ || ch == 'e' || ch == 'E') {
+ num_str.push_back(ch);
+ } else if (ch == '.') {
+#if PICOJSON_USE_LOCALE
+ num_str += localeconv()->decimal_point;
+#else
+ num_str.push_back('.');
+#endif
+ } else {
+ in.ungetc();
+ break;
+ }
+ }
+ return num_str;
+}
+
+template <typename Context, typename Iter> inline bool _parse(Context& ctx, input<Iter>& in) {
+ in.skip_ws();
+ int ch = in.getc();
+ switch (ch) {
+#define IS(ch, text, op) case ch: \
+ if (in.match(text) && op) { \
+ return true; \
+ } else { \
+ return false; \
+ }
+ IS('n', "ull", ctx.set_null());
+ IS('f', "alse", ctx.set_bool(false));
+ IS('t', "rue", ctx.set_bool(true));
+#undef IS
+ case '"':
+ return ctx.parse_string(in);
+ case '[':
+ return _parse_array(ctx, in);
+ case '{':
+ return _parse_object(ctx, in);
+ default:
+ if (('0' <= ch && ch <= '9') || ch == '-') {
+ double f;
+ char *endp;
+ in.ungetc();
+ std::string num_str = _parse_number(in);
+ if (num_str.empty()) {
+ return false;
+ }
+#ifdef PICOJSON_USE_INT64
+ {
+ errno = 0;
+ intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
+ if (errno == 0
+ && std::numeric_limits<int64_t>::min() <= ival
+ && ival <= std::numeric_limits<int64_t>::max()
+ && endp == num_str.c_str() + num_str.size()) {
+ ctx.set_int64(ival);
+ return true;
+ }
+ }
+#endif
+ f = strtod(num_str.c_str(), &endp);
+ if (endp == num_str.c_str() + num_str.size()) {
+ ctx.set_number(f);
+ return true;
+ }
+ return false;
+ }
+ break;
+ }
+ in.ungetc();
+ return false;
+}
+
+class deny_parse_context {
+public:
+ bool set_null() { return false; }
+ bool set_bool(bool) { return false; }
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t) { return false; }
+#endif
+ bool set_number(double) { return false; }
+ template <typename Iter> bool parse_string(input<Iter>&) { return false; }
+ bool parse_array_start() { return false; }
+ template <typename Iter> bool parse_array_item(input<Iter>&, size_t) {
+ return false;
+ }
+ bool parse_array_stop(size_t) { return false; }
+ bool parse_object_start() { return false; }
+ template <typename Iter> bool parse_object_item(input<Iter>&, const std::string&) {
+ return false;
+ }
+};
+
+class default_parse_context {
+protected:
+ value* out_;
+public:
+ default_parse_context(value* out) : out_(out) {}
+ bool set_null() {
+ *out_ = value();
+ return true;
+ }
+ bool set_bool(bool b) {
+ *out_ = value(b);
+ return true;
+ }
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t i) {
+ *out_ = value(i);
+ return true;
+ }
+#endif
+ bool set_number(double f) {
+ *out_ = value(f);
+ return true;
+ }
+ template<typename Iter> bool parse_string(input<Iter>& in) {
+ *out_ = value(string_type, false);
+ return _parse_string(out_->get<std::string>(), in);
+ }
+ bool parse_array_start() {
+ *out_ = value(array_type, false);
+ return true;
+ }
+ template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
+ array& a = out_->get<array>();
+ a.push_back(value());
+ default_parse_context ctx(&a.back());
+ return _parse(ctx, in);
+ }
+ bool parse_array_stop(size_t) { return true; }
+ bool parse_object_start() {
+ *out_ = value(object_type, false);
+ return true;
+ }
+ template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string& key) {
+ object& o = out_->get<object>();
+ default_parse_context ctx(&o[key]);
+ return _parse(ctx, in);
+ }
+private:
+ default_parse_context(const default_parse_context&);
+ default_parse_context& operator=(const default_parse_context&);
+};
+
+class null_parse_context {
+public:
+ struct dummy_str {
+ void push_back(int) {}
+ };
+public:
+ null_parse_context() {}
+ bool set_null() { return true; }
+ bool set_bool(bool) { return true; }
+#ifdef PICOJSON_USE_INT64
+ bool set_int64(int64_t) { return true; }
+#endif
+ bool set_number(double) { return true; }
+ template <typename Iter> bool parse_string(input<Iter>& in) {
+ dummy_str s;
+ return _parse_string(s, in);
+ }
+ bool parse_array_start() { return true; }
+ template <typename Iter> bool parse_array_item(input<Iter>& in, size_t) {
+ return _parse(*this, in);
+ }
+ bool parse_array_stop(size_t) { return true; }
+ bool parse_object_start() { return true; }
+ template <typename Iter> bool parse_object_item(input<Iter>& in, const std::string&) {
+ return _parse(*this, in);
+ }
+private:
+ null_parse_context(const null_parse_context&);
+ null_parse_context& operator=(const null_parse_context&);
+};
+
+// obsolete, use the version below
+template <typename Iter> inline std::string parse(value& out, Iter& pos, const Iter& last) {
+ std::string err;
+ pos = parse(out, pos, last, &err);
+ return err;
+}
+
+template <typename Context, typename Iter> inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) {
+ input<Iter> in(first, last);
+ if (! _parse(ctx, in) && err != NULL) {
+ char buf[64];
+ SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
+ *err = buf;
+ while (1) {
+ int ch = in.getc();
+ if (ch == -1 || ch == '\n') {
+ break;
+ } else if (ch >= ' ') {
+ err->push_back(ch);
+ }
+ }
+ }
+ return in.cur();
+}
+
+template <typename Iter> inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) {
+ default_parse_context ctx(&out);
+ return _parse(ctx, first, last, err);
+}
+
+inline std::string parse(value& out, const std::string& s) {
+ std::string err;
+ parse(out, s.begin(), s.end(), &err);
+ return err;
+}
+
+inline std::string parse(value& out, std::istream& is) {
+ std::string err;
+ parse(out, std::istreambuf_iterator<char>(is.rdbuf()),
+ std::istreambuf_iterator<char>(), &err);
+ return err;
+}
+
+template <typename T> struct last_error_t {
+ static std::string s;
+};
+template <typename T> std::string last_error_t<T>::s;
+
+inline void set_last_error(const std::string& s) {
+ last_error_t<bool>::s = s;
+}
+
+inline const std::string& get_last_error() {
+ return last_error_t<bool>::s;
+}
+
+inline bool operator==(const value& x, const value& y) {
+ if (x.is<null>())
+ return y.is<null>();
+#define PICOJSON_CMP(type) \
+ if (x.is<type>()) \
+ return y.is<type>() && x.get<type>() == y.get<type>()
+ PICOJSON_CMP(bool);
+ PICOJSON_CMP(double);
+ PICOJSON_CMP(std::string);
+ PICOJSON_CMP(array);
+ PICOJSON_CMP(object);
+#undef PICOJSON_CMP
+ PICOJSON_ASSERT(0);
+#ifdef _MSC_VER
+ __assume(0);
+#endif
+ return false;
+}
+
+inline bool operator!=(const value& x, const value& y) {
+ return ! (x == y);
+}
+}
+
+#if !PICOJSON_USE_RVALUE_REFERENCE
+namespace std {
+ template<> inline void swap(picojson::value& x, picojson::value& y)
+ {
+ x.swap(y);
+ }
+}
+#endif
+
+inline std::istream& operator>>(std::istream& is, picojson::value& x)
+{
+ picojson::set_last_error(std::string());
+ std::string err = picojson::parse(x, is);
+ if (! err.empty()) {
+ picojson::set_last_error(err);
+ is.setstate(std::ios::failbit);
+ }
+ return is;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const picojson::value& x)
+{
+ x.serialize(std::ostream_iterator<char>(os));
+ return os;
+}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/actors/camera-actor-devel.h>
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+
+#include <map>
+
+#include "gltf-scene.h"
+
+using namespace Dali;
+using Dali::Toolkit::TextLabel;
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+ attribute mediump vec3 aPosition;\n
+ attribute mediump vec3 aNormal;\n
+ attribute mediump vec2 aTexCoord;\n
+ uniform mediump mat4 uMvpMatrix;\n
+ uniform mediump mat3 uNormalMatrix;\n
+ uniform mediump vec3 uSize;\n
+ \n
+ varying mediump vec2 vTexCoord; \n
+ varying mediump vec3 vNormal; \n
+ varying mediump vec3 vPosition; \n
+ void main()\n
+{\n
+ mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
+ vertexPosition.xyz *= uSize;\n
+ vTexCoord = aTexCoord;\n
+ vNormal = normalize(uNormalMatrix * aNormal);\n
+ vPosition = aPosition; \n
+ gl_Position = uMvpMatrix * vertexPosition;\n
+}\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ uniform lowp vec4 uColor;\n
+ uniform sampler2D sTexture; \n
+ varying mediump vec3 vNormal;\n
+ varying mediump vec3 vPosition; \n
+ varying mediump vec2 vTexCoord; \n
+ \n
+ void main()\n
+{\n
+ gl_FragColor = texture2D(sTexture, vTexCoord) * 50.0;\n
+}\n
+);
+
+const char* FRAGMENT_SIMPLE_SHADER = DALI_COMPOSE_SHADER(
+ uniform lowp vec4 uColor;\n
+ uniform sampler2D sTexture; \n
+ varying mediump vec3 vNormal;\n
+ varying mediump vec3 vPosition; \n
+ varying mediump vec2 vTexCoord; \n
+ \n
+ void main()\n
+{\n
+ gl_FragColor = texture2D(sTexture, vTexCoord) * 2.0;\n
+}\n
+);
+
+const char* TEXTURED_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ uniform lowp vec4 uColor;\n
+ uniform sampler2D sTexture; \n
+ uniform mediump vec2 uScreenSize;\n
+
+ uniform mediump vec3 eyePos;\n
+ uniform mediump vec3 lightDir;\n
+
+ varying mediump vec3 vNormal;\n
+ varying mediump vec3 vPosition; \n
+ varying mediump vec2 vTexCoord; \n
+ \n
+ void main()\n
+{\n
+ mediump vec3 n = normalize( vNormal );\n
+ mediump vec3 l = normalize( lightDir );\n
+ mediump vec3 e = normalize( eyePos );\n
+ mediump float intensity = max(dot(n,l), 0.0);\n
+ gl_FragColor = texture2D(sTexture, vTexCoord) * intensity;\n
+}\n
+);
+
+const char* PLASMA_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ precision mediump float;\n
+ uniform sampler2D sTexture; \n
+
+ uniform float uTime;
+ uniform float uKFactor;
+ uniform mediump vec3 eyePos;\n
+ uniform mediump vec3 lightDir;\n
+ varying mediump vec3 vNormal;\n
+ varying mediump vec3 vPosition; \n
+ varying mediump vec2 vTexCoord; \n
+ \n
+ void main()\n
+{\n
+ mediump vec3 n = normalize( vNormal );\n
+ mediump vec3 l = normalize( lightDir );\n
+ mediump vec3 e = normalize( eyePos );\n
+ mediump float intensity = max(dot(n,l), 0.0);\n
+\n
+ const mediump float PI = 3.1415926535897932384626433832795;\n
+ mediump float v = 0.0;\n
+ mediump vec2 c = vTexCoord * uKFactor - uKFactor/2.0;\n
+ v += sin((c.x+uTime));\n
+ v += sin((c.y+uTime)/2.0);\n
+ v += sin((c.x+c.y+uTime)/2.0);\n
+ c += uKFactor/2.0 * vec2(sin(uTime/3.0), cos(uTime/2.0));\n
+ v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+uTime);\n
+ v = v/2.0;\n
+ mediump vec3 col = vec3(1, sin(PI*v), cos(PI*v));\n
+ gl_FragColor = (texture2D(sTexture, vTexCoord)) * (((col.r+col.g+col.b)/3.0)+1.0+intensity);\n
+}\n
+);
+
+const char* TEX_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ uniform lowp vec4 uColor;\n
+ uniform sampler2D sTexture0; \n
+ uniform sampler2D sTexture1; \n
+ uniform mediump vec3 eyePos;\n
+ uniform mediump vec3 lightDir;\n
+ uniform mediump vec2 uScreenSize;\n
+ varying mediump vec3 vNormal;\n
+ varying mediump vec3 vPosition; \n
+ varying mediump vec2 vTexCoord; \n
+ \n
+
+ mediump float rand(mediump vec2 co){\n
+ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n
+ }\n
+ \n
+ void main()\n
+{\n
+ mediump vec2 tx = (gl_FragCoord.xy / uScreenSize.xy);\n
+ mediump vec3 n = normalize( vNormal );\n
+ mediump vec3 l = normalize( lightDir );\n
+ mediump vec3 e = normalize( eyePos );\n
+ mediump float factor = gl_FragCoord.y / uScreenSize.y;\n
+ mediump float intensity = max(dot(n,l), 0.0);\n
+ mediump vec2 uv = tx;\n
+ gl_FragColor = ((texture2D(sTexture0, vTexCoord) * factor ) + \n
+ (texture2D(sTexture1, uv))) * intensity;\n
+}\n
+);
+
+struct Model
+{
+ Shader shader;
+ Geometry geometry;
+};
+
+// This example shows how to create and display mirrored reflection using CameraActor
+//
+class ReflectionExample : public ConnectionTracker
+{
+public:
+
+ ReflectionExample( Application& application )
+ : mApplication( application )
+ {
+ // Connect to the Application's Init signal
+ mApplication.InitSignal().Connect( this, &ReflectionExample::Create );
+ }
+
+ ~ReflectionExample() = default;
+
+private:
+
+ // The Init signal is received once (only) during the Application lifetime
+ void Create( Application& application )
+ {
+ // Get a handle to the stage
+ Stage stage = Stage::GetCurrent();
+ uint32_t stageWidth = uint32_t(stage.GetSize().x);
+ uint32_t stageHeight = uint32_t(stage.GetSize().y);
+
+ stage.GetRenderTaskList().GetTask(0).SetClearEnabled(false);
+ mLayer3D = Layer::New();
+ mLayer3D.SetSize( stageWidth, stageHeight );
+ stage.Add(mLayer3D);
+
+ mLayer3D.SetAnchorPoint( AnchorPoint::CENTER );
+ mLayer3D.SetParentOrigin( ParentOrigin::CENTER );
+ mLayer3D.SetBehavior( Layer::LAYER_3D );
+ mLayer3D.SetDepthTestDisabled( false );
+
+
+ auto gltf = glTF(DEMO_GAME_DIR "/reflection");
+
+ // Define direction of light
+ mLightDir = Vector3( 0.5, 0.5, -1 );
+
+ /**
+ * Instantiate texture sets
+ */
+ CreateTextureSetsFromGLTF( &gltf, DEMO_GAME_DIR );
+
+ /**
+ * Create models
+ */
+ CreateModelsFromGLTF( &gltf );
+
+ /**
+ * Create scene nodes
+ */
+ CreateSceneFromGLTF( stage, &gltf );
+
+ auto planeActor = mLayer3D.FindChildByName( "Plane" );
+ auto solarActor = mLayer3D.FindChildByName( "solar_root" );
+ auto backgroundActor = mLayer3D.FindChildByName( "background" );
+ ReplaceShader( backgroundActor, VERTEX_SHADER, FRAGMENT_SIMPLE_SHADER );
+ mCenterActor = mLayer3D.FindChildByName( "center" );
+ mCenterHorizActor = mLayer3D.FindChildByName( "center2" );
+
+ // Prepare Sun
+ auto sun = mLayer3D.FindChildByName( "sun" );
+ ReplaceShader( sun, VERTEX_SHADER, PLASMA_FRAGMENT_SHADER );
+ mSunTimeUniformIndex = sun.RegisterProperty( "uTime", 0.0f );
+ mSunKFactorUniformIndex = sun.RegisterProperty( "uKFactor", 0.0f );
+
+ mTickTimer = Timer::New( 16 );
+ mTickTimer.TickSignal().Connect( this, &ReflectionExample::TickTimerSignal);
+
+ // Milkyway
+ auto milkyway = mLayer3D.FindChildByName( "milkyway" );
+ ReplaceShader( milkyway, VERTEX_SHADER, FRAGMENT_SHADER );
+
+ auto renderTaskSourceActor = mLayer3D.FindChildByName( "RenderTaskSource" );
+
+ /**
+ * Access camera (it's a child of "Camera" node)
+ */
+ auto camera = mLayer3D.FindChildByName( "Camera_Orientation" );
+ auto cameraRef = mLayer3D.FindChildByName( "CameraReflection_Orientation" );
+
+ auto cameraActor = CameraActor::DownCast( camera );
+ mCamera3D = cameraActor;
+
+ auto cameraRefActor = CameraActor::DownCast( cameraRef );
+ cameraRefActor.SetProperty( DevelCameraActor::Property::REFLECTION_PLANE, Vector4(0.0f, -1.0f, 0.0f, 0.0f));
+ mReflectionCamera3D = cameraRefActor;
+
+ auto task3D = stage.GetRenderTaskList().CreateTask();
+ task3D.SetSourceActor( mLayer3D );
+ task3D.SetViewport( Rect<int>(0, 0, stageWidth, stageHeight ) );
+ task3D.SetCameraActor( cameraActor );
+ task3D.SetClearColor( Color::BLACK );
+ task3D.SetClearEnabled( true );
+ task3D.SetExclusive( false );
+ task3D.SetCameraActor( cameraActor );
+
+ /**
+ * Change shader to textured
+ */
+ Shader texShader = CreateShader( VERTEX_SHADER, TEX_FRAGMENT_SHADER );
+ planeActor.RegisterProperty( "uScreenSize", Vector2(stageWidth, stageHeight) );
+ auto renderer = planeActor.GetRendererAt(0);
+ auto textureSet = renderer.GetTextures();
+ renderer.SetShader( texShader );
+
+ Texture fbTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, stageWidth, stageHeight );
+ textureSet.SetTexture( 1u, fbTexture );
+
+ auto fb = FrameBuffer::New(stageWidth, stageHeight,
+ FrameBuffer::Attachment::DEPTH );
+
+ fb.AttachColorTexture( fbTexture );
+
+ auto renderTask = stage.GetRenderTaskList().CreateTask();
+ renderTask.SetFrameBuffer( fb );
+ renderTask.SetSourceActor( renderTaskSourceActor );
+ renderTask.SetViewport( Rect<int>(0, 0, stageWidth, stageHeight ) );
+ renderTask.SetCameraActor( cameraRefActor );
+ renderTask.SetClearColor( Color::BLACK );
+ renderTask.SetClearEnabled( true );
+ renderTask.SetExclusive( false );
+
+ mAnimation = Animation::New(30.0f );
+ mAnimation.AnimateBy(Property(solarActor, Actor::Property::ORIENTATION ),
+ Quaternion( Degree(359), Vector3(0.0, 1.0, 0.0)));
+ mAnimation.AnimateBy(Property(milkyway, Actor::Property::ORIENTATION ),
+ Quaternion( Degree(-359), Vector3(0.0, 1.0, 0.0)));
+ mAnimation.SetLooping(true );
+ mAnimation.Play();
+
+ Actor panScreen = Actor::New();
+ auto stageSize = stage.GetSize();
+ panScreen.SetSize( stageSize.width, stageSize.height );
+ panScreen.SetAnchorPoint( AnchorPoint::CENTER );
+ panScreen.SetParentOrigin( ParentOrigin::CENTER );
+ auto camera2d = stage.GetRenderTaskList().GetTask(0).GetCameraActor();
+ panScreen.SetPosition( 0, 0, camera2d.GetNearClippingPlane() );
+ camera2d.Add(panScreen);
+ camera2d.RotateBy( Degree(180.0f), Vector3( 0.0, 1.0, 0.0 ) );
+ mPanGestureDetector = PanGestureDetector::New();
+ mPanGestureDetector.Attach( panScreen );
+ mPanGestureDetector.DetectedSignal().Connect( this, &ReflectionExample::OnPan );
+
+ // Respond to key events
+ stage.KeyEventSignal().Connect( this, &ReflectionExample::OnKeyEvent );
+
+ mTickTimer.Start();
+ }
+
+ void CreateSceneFromGLTF( Stage stage, glTF* gltf )
+ {
+ const auto& nodes = gltf->GetNodes();
+
+ // for each node create nodes and children
+ // resolve parents later
+ std::vector<Actor> actors;
+ actors.reserve( nodes.size() );
+ for( const auto& node : nodes )
+ {
+ auto actor = node.cameraId != 0xffffffff ? CameraActor::New( stage.GetSize() ) : Actor::New();
+
+ actor.SetSize( 1, 1, 1 );
+ actor.SetName( node.name );
+ actor.SetAnchorPoint( AnchorPoint::CENTER );
+ actor.SetParentOrigin( ParentOrigin::CENTER );
+ actor.SetPosition( node.translation[0], node.translation[1], node.translation[2] );
+ actor.SetScale( node.scale[0], node.scale[1], node.scale[2] );
+ actor.SetOrientation( Quaternion(node.rotationQuaternion[3],
+ node.rotationQuaternion[0],
+ node.rotationQuaternion[1],
+ node.rotationQuaternion[2]));
+
+ actors.emplace_back( actor );
+
+ // Initially add each actor to the very first one
+ if(actors.size() > 1)
+ {
+ actors[0].Add(actor);
+ }
+
+ // If mesh, create and add renderer
+ if(node.meshId != 0xffffffff)
+ {
+ const auto& model = mModels[node.meshId].get();
+ auto renderer = Renderer::New( model->geometry, model->shader );
+
+ // if textured, add texture set
+ auto materialId = gltf->GetMeshes()[node.meshId]->material;
+ if( materialId != 0xffffffff )
+ {
+ if( gltf->GetMaterials()[materialId].pbrMetallicRoughness.enabled )
+ {
+ renderer.SetTextures( mTextureSets[materialId] );
+ }
+ }
+
+ actor.AddRenderer( renderer );
+ }
+
+ // Reset and attach main camera
+ if( node.cameraId != 0xffffffff )
+ {
+ mCameraPos = Vector3(node.translation[0], node.translation[1], node.translation[2]);
+ auto quatY = Quaternion( Degree(180.0f), Vector3( 0.0, 1.0, 0.0) );
+ auto cameraActor = CameraActor::DownCast( actor );
+ cameraActor.SetOrientation( Quaternion(node.rotationQuaternion[3],
+ node.rotationQuaternion[0],
+ node.rotationQuaternion[1],
+ node.rotationQuaternion[2] )
+ * quatY
+ );
+ cameraActor.SetProjectionMode( Camera::PERSPECTIVE_PROJECTION );
+
+ const auto camera = gltf->GetCameras()[node.cameraId];
+ cameraActor.SetNearClippingPlane( camera->znear );
+ cameraActor.SetFarClippingPlane( camera->zfar );
+ cameraActor.SetFieldOfView( camera->yfov );
+
+ cameraActor.SetProperty( CameraActor::Property::INVERT_Y_AXIS, true);
+ cameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+ cameraActor.SetParentOrigin( ParentOrigin::CENTER );
+
+ mCameras.emplace_back( cameraActor );
+ }
+ }
+
+ // Resolve hierarchy dependencies
+ auto i = 0u;
+ for( const auto& node : nodes )
+ {
+ if(!node.children.empty())
+ {
+ for(const auto& childId : node.children)
+ {
+ actors[i].Add( actors[childId+1] );
+ }
+ }
+ ++i;
+ }
+
+ mActors = std::move(actors);
+
+ // Add root actor to the stage
+ mLayer3D.Add( mActors[0] );
+
+ for( auto& actor : mActors )
+ {
+ actor.RegisterProperty( "lightDir", mLightDir );
+ actor.RegisterProperty( "eyePos", mCameraPos );
+ }
+
+ }
+
+ /**
+ * Creates models from glTF
+ */
+ void CreateModelsFromGLTF( glTF* gltf )
+ {
+ const auto& meshes = gltf->GetMeshes();
+ for( const auto& mesh : meshes )
+ {
+ // change shader to use texture if material indicates that
+ if(mesh->material != 0xffffffff && gltf->GetMaterials()[mesh->material].pbrMetallicRoughness.enabled)
+ {
+ mModels.emplace_back( CreateModel( *gltf, mesh, VERTEX_SHADER, TEXTURED_FRAGMENT_SHADER ) );
+ }
+ else
+ {
+ mModels.emplace_back( CreateModel( *gltf, mesh, VERTEX_SHADER, FRAGMENT_SHADER ) );
+ }
+ }
+ }
+
+ void CreateTextureSetsFromGLTF( glTF* gltf, const std::string& basePath )
+ {
+ const auto& materials = gltf->GetMaterials();
+ const auto& textures = gltf->GetTextures();
+
+ std::map<std::string, Texture> textureCache{};
+
+ for(const auto& material : materials )
+ {
+ TextureSet textureSet;
+ if(material.pbrMetallicRoughness.enabled)
+ {
+ textureSet = TextureSet::New();
+ std::string filename( basePath );
+ filename += '/';
+ filename += textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
+ Dali::PixelData pixelData = Dali::Toolkit::SyncImageLoader::Load( filename );
+
+ auto cacheKey = textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
+ auto iter = textureCache.find(cacheKey);
+ Texture texture;
+ if(iter == textureCache.end())
+ {
+ texture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(),
+ pixelData.GetHeight());
+ texture.Upload(pixelData);
+ texture.GenerateMipmaps();
+ textureCache[cacheKey] = texture;
+ }
+ else
+ {
+ texture = iter->second;
+ }
+ textureSet.SetTexture( 0, texture );
+ Dali::Sampler sampler = Dali::Sampler::New();
+ sampler.SetWrapMode( Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT );
+ sampler.SetFilterMode( Dali::FilterMode::LINEAR_MIPMAP_LINEAR, Dali::FilterMode::LINEAR );
+ textureSet.SetSampler( 0, sampler );
+ }
+ mTextureSets.emplace_back( textureSet );
+ }
+ }
+
+ template<class T>
+ bool LoadFile( const std::string& filename, std::vector<T>& bytes )
+ {
+ Dali::FileStream fileStream( filename, Dali::FileStream::READ | Dali::FileStream::BINARY );
+ FILE* fin = fileStream.GetFile();
+
+ if( fin )
+ {
+ if( fseek( fin, 0, SEEK_END ) )
+ {
+ return false;
+ }
+ bytes.resize( uint32_t(ftell( fin )) );
+ std::fill( bytes.begin(), bytes.end(), 0 );
+ if( fseek( fin, 0, SEEK_SET ) )
+ {
+ return false;
+ }
+ size_t result = fread( bytes.data(), 1, bytes.size(), fin );
+ return ( result != 0 );
+ }
+
+ return false;
+ }
+
+ Shader CreateShader( const std::string& vsh, const std::string& fsh )
+ {
+ std::vector<char> vshShaderSource;
+ std::vector<char> fshShaderSource;
+
+ // VSH
+ if(vsh[0] == '/')
+ {
+ std::string vshPath( DEMO_GAME_DIR );
+ vshPath += '/';
+ vshPath += vsh;
+ LoadFile( vshPath, vshShaderSource );
+ }
+ else
+ {
+ vshShaderSource.insert(vshShaderSource.end(), vsh.begin(), vsh.end());
+ }
+
+ // FSH
+ if(fsh[0] == '/')
+ {
+ std::string fshPath( DEMO_GAME_DIR );
+ fshPath += '/';
+ fshPath += fsh;
+ LoadFile( fshPath, fshShaderSource );
+ }
+ else
+ {
+ fshShaderSource.insert(fshShaderSource.end(), fsh.begin(), fsh.end());
+ }
+
+ vshShaderSource.emplace_back(0);
+ fshShaderSource.emplace_back(0);
+ return Shader::New( std::string(vshShaderSource.data()), std::string(fshShaderSource.data()) );
+ }
+
+ std::unique_ptr<Model> CreateModel( glTF& gltf,
+ const glTF_Mesh* mesh,
+ const std::string& vertexShaderSource,
+ const std::string& fragmentShaderSource )
+ {
+ /*
+ * Obtain interleaved buffer for first mesh with position and normal attributes
+ */
+ auto positionBuffer = gltf.GetMeshAttributeBuffer( *mesh,
+ {
+ glTFAttributeType::POSITION,
+ glTFAttributeType::NORMAL,
+ glTFAttributeType::TEXCOORD_0
+ } );
+
+ auto attributeCount = gltf.GetMeshAttributeCount( mesh );
+ /**
+ * Create matching property buffer
+ */
+ auto vertexBuffer = PropertyBuffer::New( Property::Map()
+ .Add("aPosition", Property::VECTOR3 )
+ .Add("aNormal", Property::VECTOR3)
+ .Add("aTexCoord", Property::VECTOR2)
+ );
+
+ // set vertex data
+ vertexBuffer.SetData( positionBuffer.data(), attributeCount );
+
+ auto geometry = Geometry::New();
+ geometry.AddVertexBuffer( vertexBuffer );
+ auto indexBuffer = gltf.GetMeshIndexBuffer( mesh );
+ geometry.SetIndexBuffer( indexBuffer.data(), indexBuffer.size() );
+ geometry.SetType( Geometry::Type::TRIANGLES );
+ std::unique_ptr<Model> retval( new Model() );
+ retval->shader = CreateShader( vertexShaderSource, fragmentShaderSource );
+ retval->geometry = geometry;
+ return retval;
+ }
+
+ void ReplaceShader( Actor& actor, const std::string& vsh, const std::string& fsh )
+ {
+ auto renderer = actor.GetRendererAt(0);
+ auto shader = CreateShader(vsh, fsh);
+ renderer.SetShader( shader );
+ }
+
+ void OnPan( Actor actor, const PanGesture& panGesture )
+ {
+ auto displacement = panGesture.screenDisplacement;
+ mCenterActor.RotateBy( Degree( displacement.y *0.1f ), Vector3( 0.0, 0.0, 1.0) );
+ mCenterActor.RotateBy( Degree( displacement.x *0.1f ), Vector3( 0.0, 1.0, 0.0) );
+ Quaternion q;
+ mCenterActor.GetProperty( Actor::Property::ORIENTATION ).Get(q);
+ Matrix m = Matrix::IDENTITY;
+ m.SetTransformComponents( Vector3::ONE, q, Vector3::ZERO );
+ auto yAxis = m.GetYAxis() * -1.0f;
+
+ yAxis.Normalize();
+ mReflectionCamera3D.SetProperty( DevelCameraActor::Property::REFLECTION_PLANE, Vector4(yAxis.x, yAxis.y, yAxis.z, 0.0f));
+ }
+
+ void OnKeyEvent( const KeyEvent& event )
+ {
+ if( event.state == KeyEvent::Down )
+ {
+ if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
+ {
+ mApplication.Quit();
+ }
+ }
+ }
+
+ bool TickTimerSignal()
+ {
+ auto root = mLayer3D;
+ static float rotationAngle = 0.0f;
+
+ const auto ROTATION_ANGLE_STEP = 0.05f;
+ const auto FRAME_DELTA_TIME = 0.016f;
+ const auto PLASMA_K_FACTOR = 12.0f; // 'granularity' of plasma effect
+
+ rotationAngle += ROTATION_ANGLE_STEP;
+ mMockTime += FRAME_DELTA_TIME;
+ mKFactor = PLASMA_K_FACTOR;
+
+ auto sun = root.FindChildByName( "sun" );
+ sun.SetProperty( mSunTimeUniformIndex, mMockTime );
+ sun.SetProperty( mSunKFactorUniformIndex, mKFactor );
+ sun.SetOrientation( Quaternion( Radian(Degree(rotationAngle)), Vector3(0.0, 1.0, 0.0)));
+ return true;
+ }
+
+private:
+ Application& mApplication;
+
+ Layer mLayer3D;
+
+ std::vector<Actor> mActors;
+ std::vector<CameraActor> mCameras;
+ std::vector<std::unique_ptr<Model>> mModels;
+ std::vector<TextureSet> mTextureSets;
+
+ Animation mAnimation;
+ float mMockTime = 0.0f;
+ float mKFactor = 0.0f;
+ Property::Index mSunTimeUniformIndex;
+ Property::Index mSunKFactorUniformIndex;
+ PanGestureDetector mPanGestureDetector;
+
+ Vector3 mCameraPos;
+ Vector3 mLightDir;
+ Timer mTickTimer;
+
+ CameraActor mCamera3D;
+ CameraActor mReflectionCamera3D;
+ Actor mCenterActor;
+ Actor mCenterHorizActor;
+};
+
+int DALI_EXPORT_API main( int argc, char **argv )
+{
+ Application application = Application::New( &argc, &argv );
+ ReflectionExample test( application );
+ application.MainLoop();
+ return 0;
+}
--- /dev/null
+{
+ "asset" : {
+ "generator" : "Khronos glTF Blender I/O v1.1.46",
+ "version" : "2.0"
+ },
+ "scene" : 0,
+ "scenes" : [
+ {
+ "name" : "Scene",
+ "nodes" : [
+ 4,
+ 26
+ ]
+ }
+ ],
+ "nodes" : [
+ {
+ "mesh" : 0,
+ "name" : "background",
+ "rotation" : [
+ 0.2561876177787781,
+ 0,
+ 0,
+ 0.9666270613670349
+ ],
+ "scale" : [
+ 41.288753509521484,
+ 41.288753509521484,
+ 41.288753509521484
+ ],
+ "translation" : [
+ 0.6707069277763367,
+ -66.81024932861328,
+ -2.4491214752197266
+ ]
+ },
+ {
+ "camera" : 0,
+ "name" : "CameraReflection_Orientation",
+ "rotation" : [
+ -0.7071067690849304,
+ 0,
+ 0,
+ 0.7071067690849304
+ ]
+ },
+ {
+ "children" : [
+ 1
+ ],
+ "name" : "CameraReflection"
+ },
+ {
+ "camera" : 1,
+ "name" : "Camera_Orientation",
+ "rotation" : [
+ -0.7071067690849304,
+ 0,
+ 0,
+ 0.7071067690849304
+ ]
+ },
+ {
+ "children" : [
+ 0,
+ 2,
+ 3
+ ],
+ "name" : "Camera",
+ "rotation" : [
+ 0.3552197515964508,
+ 0.6114072799682617,
+ -0.3552197515964508,
+ 0.6114073395729065
+ ],
+ "translation" : [
+ 25.934219360351562,
+ 18.4041748046875,
+ 0
+ ]
+ },
+ {
+ "mesh" : 1,
+ "name" : "Cylinder",
+ "scale" : [
+ 6.3863205909729,
+ 1.160239815711975,
+ 6.3863205909729
+ ],
+ "translation" : [
+ 0,
+ -2.19092059135437,
+ 0
+ ]
+ },
+ {
+ "name" : "Empty",
+ "rotation" : [
+ 0,
+ -0.3826834261417389,
+ 0.9238795042037964,
+ -1.672762550697371e-08
+ ],
+ "scale" : [
+ 8.46078109741211,
+ 8.46078109741211,
+ 8.46078109741211
+ ],
+ "translation" : [
+ -10.59361743927002,
+ -9.98163890838623,
+ -0.23785686492919922
+ ]
+ },
+ {
+ "name" : "Empty.001",
+ "rotation" : [
+ 0,
+ 1,
+ 0,
+ -4.371138828673793e-08
+ ],
+ "scale" : [
+ 8.46078109741211,
+ 8.46078109741211,
+ 8.46078109741211
+ ],
+ "translation" : [
+ -10.59361743927002,
+ -9.98163890838623,
+ -0.23785686492919922
+ ]
+ },
+ {
+ "name" : "Light",
+ "rotation" : [
+ 0.16907575726509094,
+ 0.7558803558349609,
+ -0.27217137813568115,
+ 0.570947527885437
+ ],
+ "translation" : [
+ -1.473832130432129,
+ 4.775537014007568,
+ -8.020967483520508
+ ]
+ },
+ {
+ "mesh" : 2,
+ "name" : "Plane",
+ "scale" : [
+ 6.463212966918945,
+ 1.1742093563079834,
+ 6.463212966918945
+ ],
+ "translation" : [
+ 0,
+ -2.19092059135437,
+ 0
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.000",
+ "translation" : [
+ 4.034352779388428,
+ 0,
+ 3.406787395477295
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.001",
+ "translation" : [
+ 4.034352779388428,
+ 0,
+ -3.546769142150879
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.002",
+ "translation" : [
+ -0.7669124603271484,
+ 0,
+ -5.243768215179443
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.003",
+ "translation" : [
+ -0.7669124603271484,
+ 0,
+ 5.600468158721924
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.004",
+ "translation" : [
+ -5.40261697769165,
+ 0,
+ 1.7097878456115723
+ ]
+ },
+ {
+ "mesh" : 3,
+ "name" : "column_0.005",
+ "translation" : [
+ -5.40261697769165,
+ 0,
+ -2.0567219257354736
+ ]
+ },
+ {
+ "mesh" : 4,
+ "name" : "dome",
+ "translation" : [
+ 0,
+ 10.846502304077148,
+ 0
+ ]
+ },
+ {
+ "mesh" : 5,
+ "name" : "milkyway",
+ "scale" : [
+ 5.861281394958496,
+ -0.5747091174125671,
+ 5.861281394958496
+ ],
+ "translation" : [
+ 0,
+ 10.332517623901367,
+ 0
+ ]
+ },
+ {
+ "mesh" : 6,
+ "name" : "earth",
+ "scale" : [
+ 0.3868779242038727,
+ 0.3868779242038727,
+ 0.3868779242038727
+ ],
+ "translation" : [
+ 0.046428680419921875,
+ 4.758791923522949,
+ 1.4374182224273682
+ ]
+ },
+ {
+ "mesh" : 7,
+ "name" : "saturn",
+ "scale" : [
+ 0.8631472587585449,
+ 0.8631472587585449,
+ 0.8631472587585449
+ ],
+ "translation" : [
+ 0.7704035043716431,
+ 4.758791923522949,
+ 3.2832906246185303
+ ]
+ },
+ {
+ "mesh" : 8,
+ "name" : "saturn.001",
+ "scale" : [
+ 0.630012571811676,
+ 0.630012571811676,
+ 0.630012571811676
+ ],
+ "translation" : [
+ -2.5262279510498047,
+ 3.7848119735717773,
+ 2.0928404331207275
+ ]
+ },
+ {
+ "mesh" : 9,
+ "name" : "saturn.002",
+ "scale" : [
+ 0.5450682640075684,
+ 0.5450682640075684,
+ 0.5450682640075684
+ ],
+ "translation" : [
+ 0.22096490859985352,
+ 5.8246612548828125,
+ -2.989466428756714
+ ]
+ },
+ {
+ "mesh" : 10,
+ "name" : "saturn.003",
+ "scale" : [
+ 0.9573714733123779,
+ 0.9573714733123779,
+ 0.9573714733123779
+ ],
+ "translation" : [
+ 2.654115915298462,
+ 1.1106147766113281,
+ -0.8603012561798096
+ ]
+ },
+ {
+ "children" : [
+ 18,
+ 19,
+ 20,
+ 21,
+ 22
+ ],
+ "name" : "solar_root"
+ },
+ {
+ "mesh" : 11,
+ "name" : "sun",
+ "scale" : [
+ 1.3610559701919556,
+ 1.3610559701919556,
+ 1.3610559701919556
+ ],
+ "translation" : [
+ 0,
+ 2.0611612796783447,
+ 0
+ ]
+ },
+ {
+ "children" : [
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 23,
+ 24
+ ],
+ "name" : "RenderTaskSource"
+ },
+ {
+ "children" : [
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 25
+ ],
+ "name" : "center"
+ }
+ ],
+ "cameras" : [
+ {
+ "name" : "Camera.002",
+ "perspective" : {
+ "yfov" : 0.6911112070083618,
+ "zfar" : 1000,
+ "znear" : 0.0010000000474974513
+ },
+ "type" : "perspective"
+ },
+ {
+ "name" : "Camera.001",
+ "perspective" : {
+ "yfov" : 0.6911112070083618,
+ "zfar" : 1000,
+ "znear" : 0.0010000000474974513
+ },
+ "type" : "perspective"
+ }
+ ],
+ "materials" : [
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "background",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 0,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "sides",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 1,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "top",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 2,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0.8947368264198303,
+ "roughnessFactor" : 0.0964912474155426
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "marble2",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 3,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "marble",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 4,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "milkyway",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 5,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "mat_earth",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 6,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "mat_saturn",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 7,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0.11403506994247437,
+ "roughnessFactor" : 0.34210526943206787
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "mat_mars",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 8,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "mat_venus",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 9,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 0,
+ 0,
+ 0
+ ],
+ "name" : "mat_jupiter",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 10,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.5
+ }
+ },
+ {
+ "doubleSided" : true,
+ "emissiveFactor" : [
+ 1,
+ 1,
+ 1
+ ],
+ "name" : "mat_sun2",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 11,
+ "texCoord" : 0
+ },
+ "metallicFactor" : 0,
+ "roughnessFactor" : 0.7368420958518982
+ }
+ }
+ ],
+ "meshes" : [
+ {
+ "name" : "Plane",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 0,
+ "NORMAL" : 1,
+ "TEXCOORD_0" : 2
+ },
+ "indices" : 3,
+ "material" : 0
+ }
+ ]
+ },
+ {
+ "name" : "Cylinder",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 4,
+ "NORMAL" : 5,
+ "TEXCOORD_0" : 6
+ },
+ "indices" : 7,
+ "material" : 1
+ }
+ ]
+ },
+ {
+ "name" : "Cylinder.001",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 8,
+ "NORMAL" : 9,
+ "TEXCOORD_0" : 10
+ },
+ "indices" : 11,
+ "material" : 2
+ }
+ ]
+ },
+ {
+ "name" : "Cylinder.002",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 12,
+ "NORMAL" : 13,
+ "TEXCOORD_0" : 14
+ },
+ "indices" : 15,
+ "material" : 3
+ }
+ ]
+ },
+ {
+ "name" : "Cylinder.003",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 16,
+ "NORMAL" : 17,
+ "TEXCOORD_0" : 18
+ },
+ "indices" : 19,
+ "material" : 4
+ }
+ ]
+ },
+ {
+ "name" : "Cylinder.004",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 20,
+ "NORMAL" : 21,
+ "TEXCOORD_0" : 22
+ },
+ "indices" : 23,
+ "material" : 5
+ }
+ ]
+ },
+ {
+ "name" : "Sphere",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 24,
+ "NORMAL" : 25,
+ "TEXCOORD_0" : 26
+ },
+ "indices" : 27,
+ "material" : 6
+ }
+ ]
+ },
+ {
+ "name" : "Sphere.002",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 28,
+ "NORMAL" : 29,
+ "TEXCOORD_0" : 30
+ },
+ "indices" : 27,
+ "material" : 7
+ }
+ ]
+ },
+ {
+ "name" : "Sphere.003",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 31,
+ "NORMAL" : 32,
+ "TEXCOORD_0" : 33
+ },
+ "indices" : 27,
+ "material" : 8
+ }
+ ]
+ },
+ {
+ "name" : "Sphere.004",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 34,
+ "NORMAL" : 35,
+ "TEXCOORD_0" : 36
+ },
+ "indices" : 27,
+ "material" : 9
+ }
+ ]
+ },
+ {
+ "name" : "Sphere.005",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 37,
+ "NORMAL" : 38,
+ "TEXCOORD_0" : 39
+ },
+ "indices" : 40,
+ "material" : 10
+ }
+ ]
+ },
+ {
+ "name" : "Sphere.001",
+ "primitives" : [
+ {
+ "attributes" : {
+ "POSITION" : 41,
+ "NORMAL" : 42,
+ "TEXCOORD_0" : 43
+ },
+ "indices" : 44,
+ "material" : 11
+ }
+ ]
+ }
+ ],
+ "textures" : [
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ },
+ {
+ "source" : 0
+ }
+ ],
+ "images" : [
+ {
+ "mimeType" : "image/png",
+ "name" : "texture-atlas",
+ "uri" : "texture-atlas.jpg"
+ }
+ ],
+ "accessors" : [
+ {
+ "bufferView" : 0,
+ "componentType" : 5126,
+ "count" : 4,
+ "max" : [
+ 1,
+ 0,
+ 1
+ ],
+ "min" : [
+ -1,
+ 0,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 1,
+ "componentType" : 5126,
+ "count" : 4,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 2,
+ "componentType" : 5126,
+ "count" : 4,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 3,
+ "componentType" : 5123,
+ "count" : 6,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 4,
+ "componentType" : 5126,
+ "count" : 72,
+ "max" : [
+ 1,
+ 1,
+ 1
+ ],
+ "min" : [
+ -1,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 5,
+ "componentType" : 5126,
+ "count" : 72,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 6,
+ "componentType" : 5126,
+ "count" : 72,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 7,
+ "componentType" : 5123,
+ "count" : 192,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 8,
+ "componentType" : 5126,
+ "count" : 32,
+ "max" : [
+ 1,
+ 1,
+ 1
+ ],
+ "min" : [
+ -1,
+ 1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 9,
+ "componentType" : 5126,
+ "count" : 32,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 10,
+ "componentType" : 5126,
+ "count" : 32,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 11,
+ "componentType" : 5123,
+ "count" : 90,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 12,
+ "componentType" : 5126,
+ "count" : 800,
+ "max" : [
+ 0.9250403642654419,
+ 10.267958641052246,
+ 0.9250403642654419
+ ],
+ "min" : [
+ -0.9250403642654419,
+ -0.9530067443847656,
+ -0.9250403642654419
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 13,
+ "componentType" : 5126,
+ "count" : 800,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 14,
+ "componentType" : 5126,
+ "count" : 800,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 15,
+ "componentType" : 5123,
+ "count" : 1428,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 16,
+ "componentType" : 5126,
+ "count" : 716,
+ "max" : [
+ 6.96999979019165,
+ 1.0763102769851685,
+ 6.67748498916626
+ ],
+ "min" : [
+ -6.970000267028809,
+ -1,
+ -6.677481651306152
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 17,
+ "componentType" : 5126,
+ "count" : 716,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 18,
+ "componentType" : 5126,
+ "count" : 716,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 19,
+ "componentType" : 5123,
+ "count" : 3444,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 20,
+ "componentType" : 5126,
+ "count" : 89,
+ "max" : [
+ 1,
+ 1,
+ 1
+ ],
+ "min" : [
+ -1,
+ 1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 21,
+ "componentType" : 5126,
+ "count" : 89,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 22,
+ "componentType" : 5126,
+ "count" : 89,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 23,
+ "componentType" : 5123,
+ "count" : 90,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 24,
+ "componentType" : 5126,
+ "count" : 541,
+ "max" : [
+ 1.000000238418579,
+ 1,
+ 1.0000003576278687
+ ],
+ "min" : [
+ -0.9999998211860657,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 25,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 26,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 27,
+ "componentType" : 5123,
+ "count" : 2880,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 28,
+ "componentType" : 5126,
+ "count" : 541,
+ "max" : [
+ 1.000000238418579,
+ 1,
+ 1.0000003576278687
+ ],
+ "min" : [
+ -0.9999998211860657,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 29,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 30,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 31,
+ "componentType" : 5126,
+ "count" : 541,
+ "max" : [
+ 1.000000238418579,
+ 1,
+ 1.0000003576278687
+ ],
+ "min" : [
+ -0.9999998211860657,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 32,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 33,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 34,
+ "componentType" : 5126,
+ "count" : 541,
+ "max" : [
+ 1.000000238418579,
+ 1,
+ 1.0000003576278687
+ ],
+ "min" : [
+ -0.9999998211860657,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 35,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 36,
+ "componentType" : 5126,
+ "count" : 541,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 37,
+ "componentType" : 5126,
+ "count" : 539,
+ "max" : [
+ 1.000000238418579,
+ 1,
+ 1.0000003576278687
+ ],
+ "min" : [
+ -0.9999998211860657,
+ -1,
+ -1
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 38,
+ "componentType" : 5126,
+ "count" : 539,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 39,
+ "componentType" : 5126,
+ "count" : 539,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 40,
+ "componentType" : 5123,
+ "count" : 2880,
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 41,
+ "componentType" : 5126,
+ "count" : 559,
+ "max" : [
+ 1.0000001192092896,
+ 1,
+ 1.0000001192092896
+ ],
+ "min" : [
+ -0.9999999403953552,
+ -1,
+ -1.000000238418579
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 42,
+ "componentType" : 5126,
+ "count" : 559,
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 43,
+ "componentType" : 5126,
+ "count" : 559,
+ "type" : "VEC2"
+ },
+ {
+ "bufferView" : 44,
+ "componentType" : 5123,
+ "count" : 2880,
+ "type" : "SCALAR"
+ }
+ ],
+ "bufferViews" : [
+ {
+ "buffer" : 0,
+ "byteLength" : 48,
+ "byteOffset" : 0
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 48,
+ "byteOffset" : 48
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 32,
+ "byteOffset" : 96
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 12,
+ "byteOffset" : 128
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 864,
+ "byteOffset" : 140
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 864,
+ "byteOffset" : 1004
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 576,
+ "byteOffset" : 1868
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 384,
+ "byteOffset" : 2444
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 384,
+ "byteOffset" : 2828
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 384,
+ "byteOffset" : 3212
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 256,
+ "byteOffset" : 3596
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 180,
+ "byteOffset" : 3852
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 9600,
+ "byteOffset" : 4032
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 9600,
+ "byteOffset" : 13632
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6400,
+ "byteOffset" : 23232
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 2856,
+ "byteOffset" : 29632
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 8592,
+ "byteOffset" : 32488
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 8592,
+ "byteOffset" : 41080
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 5728,
+ "byteOffset" : 49672
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6888,
+ "byteOffset" : 55400
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 1068,
+ "byteOffset" : 62288
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 1068,
+ "byteOffset" : 63356
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 712,
+ "byteOffset" : 64424
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 180,
+ "byteOffset" : 65136
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 65316
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 71808
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4328,
+ "byteOffset" : 78300
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 5760,
+ "byteOffset" : 82628
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 88388
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 94880
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4328,
+ "byteOffset" : 101372
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 105700
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 112192
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4328,
+ "byteOffset" : 118684
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 123012
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6492,
+ "byteOffset" : 129504
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4328,
+ "byteOffset" : 135996
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6468,
+ "byteOffset" : 140324
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6468,
+ "byteOffset" : 146792
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4312,
+ "byteOffset" : 153260
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 5760,
+ "byteOffset" : 157572
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6708,
+ "byteOffset" : 163332
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 6708,
+ "byteOffset" : 170040
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 4472,
+ "byteOffset" : 176748
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 5760,
+ "byteOffset" : 181220
+ }
+ ],
+ "buffers" : [
+ {
+ "byteLength" : 186980,
+ "uri" : "reflection.bin"
+ }
+ ]
+}
--- /dev/null
+Texture Atlas contains images under Attribution 4.0 International license (CC By 4.0)
+
+https://creativecommons.org/licenses/by/4.0/
+
+https://creativecommons.org/licenses/by/4.0/legalcode
+
msgid "DALI_DEMO_STR_TITLE_REFRACTION"
msgstr "Refraction"
+msgid "DALI_DEMO_STR_TITLE_REFLECTION"
+msgstr "Reflection"
+
msgid "DALI_DEMO_STR_TITLE_RENDERER_STENCIL"
msgstr "Renderer Stencil"
msgid "DALI_DEMO_STR_TITLE_RADIAL_MENU"
msgstr "Radial Menu"
+msgid "DALI_DEMO_STR_TITLE_REFLECTION"
+msgstr "Reflection"
+
msgid "DALI_DEMO_STR_TITLE_REFRACTION"
msgstr "Refraction"
#define DALI_DEMO_STR_TITLE_PRIMITIVE_SHAPES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PRIMITIVE_SHAPES")
#define DALI_DEMO_STR_TITLE_PROGRESS_BAR dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PROGRESS_BAR")
#define DALI_DEMO_STR_TITLE_PROPERTY_NOTIFICATION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PROPERTY_NOTIFICATION")
+#define DALI_DEMO_STR_TITLE_REFLECTION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_REFLECTION")
#define DALI_DEMO_STR_TITLE_REFRACTION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_REFRACTION")
#define DALI_DEMO_STR_TITLE_REMOTE_IMAGE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_REMOTE_IMAGE")
#define DALI_DEMO_STR_TITLE_RENDERING_DRAW_LINE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_RENDERING_DRAW_LINE")
#define DALI_DEMO_STR_TITLE_PRIMITIVE_SHAPES "Primitive Shapes"
#define DALI_DEMO_STR_TITLE_PROGRESS_BAR "Progress Bar"
#define DALI_DEMO_STR_TITLE_PROPERTY_NOTIFICATION "Property Notification"
+#define DALI_DEMO_STR_TITLE_REFLECTION "Reflection"
#define DALI_DEMO_STR_TITLE_REFRACTION "Refract Effect"
#define DALI_DEMO_STR_TITLE_REMOTE_IMAGE "Remote Image"
#define DALI_DEMO_STR_TITLE_RENDERING_DRAW_LINE "Draw Line"