From: adam.b Date: Wed, 19 Feb 2020 16:28:27 +0000 (+0000) Subject: Reflection demo X-Git-Tag: dali_1.9.5~2^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-demo.git;a=commitdiff_plain;h=58c85134a26e3a8d565861f55d24f78ba21c90ad Reflection demo Packed resources are under Attribution 4.0 International license. The user may use, adapt and share the textures for any purpose, even commercially. Change-Id: If9092a8fde225c39daa599367d13e9d0924bd657 --- diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index 4bdee68..55c7471 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -187,6 +187,9 @@ + + + diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp index 2884a32..a6bee7a 100644 --- a/demo/dali-demo.cpp +++ b/demo/dali-demo.cpp @@ -50,6 +50,7 @@ int DALI_EXPORT_API main(int argc, char **argv) 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)); diff --git a/examples/reflection-demo/gltf-scene.cpp b/examples/reflection-demo/gltf-scene.cpp new file mode 100644 index 0000000..424ffa2 --- /dev/null +++ b/examples/reflection-demo/gltf-scene.cpp @@ -0,0 +1,588 @@ +/* + * 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 + +#include "gltf-scene.h" + +#include "pico-json.h" + +namespace +{ +// string contains enum type index encoded matching glTFAttributeType +const std::vector GLTF_STR_ATTRIBUTE_TYPE = { + "POSITION", + "NORMAL", + "TEXCOORD_0" +}; + +const std::vector> 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(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& val ) + { + return val.first == name; + }); + if( iter == GLTF_STR_COMPONENT_TYPE.end() ) + { + return 0; + } + + return iter->second; +} + +template +struct JsonResult +{ + bool success; + T result; + operator T() const + { + return static_cast(result); + } +}; + +template<> +struct JsonResult +{ + bool success; + bool result; + + operator bool() const + { + return result; + } +}; + +template +JsonResult 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 +JsonResult JsonGetValue( const picojson::value& val, const std::string& name, const Converted& onFail ) +{ + if( val.contains(name) ) + { + return {true, static_cast(val.get(name).get())}; + } + return {false, onFail}; +} + +template +bool JsonGetValueOut( const picojson::value& val, const std::string& name, Converted& writeOut ) +{ + if( val.contains(name) ) + { + writeOut = static_cast(val.get(name).get()); + return true; + } + return false; +} + + +/** + * Safe json value accessor + */ +template +JsonResult> JsonGetArray( const picojson::value& val, const std::string& name, std::vector valueOnFail = {} ) +{ + if(val.contains(name) ) + { + const auto& array = val.get(name).get(); + std::vector result{}; + for( const auto& item : array ) + { + result.emplace_back( static_cast(item.get()) ); + } + 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(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()) + { + return false; + } + + // Add dummy first node to nodes (scene node) + mNodes.emplace_back(); + + // Sources for textures to be resolved later + std::vector textureSources{}; + std::vector images{}; + + for( auto& val : jsonNode.get() ) + { + GLTF_LOG( "node: %s", val.first.c_str()); + + // Parse bufferviews + if( val.first == "bufferViews" ) + { + auto bufferViews = val.second; + for( auto& view : bufferViews.get() ) + { + auto bufferIndex = uint32_t(view.get("buffer").get()); + auto byteLength = uint32_t(view.get("byteLength").get()); + auto byteOffset = uint32_t(view.get("byteOffset").get()); + + 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() ) + { + auto gltfAccessor = glTF_Accessor{}; + gltfAccessor.bufferView = uint32_t(accessor.get( "bufferView" ).get()); + gltfAccessor.componentType = uint32_t(accessor.get( "componentType" ).get()); + gltfAccessor.count = uint32_t(accessor.get( "count" ).get()); + gltfAccessor.type = accessor.get( "type" ).get(); + gltfAccessor.componentSize = glTFComponentTypeStrToNum( gltfAccessor.type ); + mAccessors.emplace_back( gltfAccessor ); + } + } + + // parse meshes + else if( val.first == "meshes" ) + { + for( const auto& mesh : val.second.get() ) + { + glTF_Mesh gltfMesh{}; + gltfMesh.name = mesh.get( "name" ).get(); + + // get primitives (in this implementation assuming single mesh consists of + // one and only one primitive) + const auto& primitive = mesh.get("primitives").get()[0]; + const auto& attrs = primitive.get("attributes").get(); + for( const auto& attr : attrs ) + { + auto type = glTFAttributeTypeStrToEnum( attr.first ); + auto bvIndex = uint32_t(attr.second.get()); + 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()); + gltfMesh.material = uint32_t(primitive.get("material").get()); + mMeshes.emplace_back( gltfMesh ); + } + } + // parse cameras + else if( val.first == "cameras" ) + { + glTF_Camera tgifCamera{}; + for( const auto& camera : val.second.get() ) + { + 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(perspective.get( "yfov" ).get()); + tgifCamera.zfar = static_cast(perspective.get( "zfar" ).get()); + tgifCamera.znear = static_cast(perspective.get( "znear" ).get()); + } + + mCameras.emplace_back( tgifCamera ); + } + } + // parse nodes + else if( val.first == "nodes" ) + { + auto nodeIndex = 1u; + for( const auto& node : val.second.get() ) + { + glTF_Node gltfNode{}; + gltfNode.name = node.get( "name" ).to_str(); + auto rotation = JsonGetArray( node, "rotation", {0.0f, 0.0f, 0.0f, 1.0f} ); + auto translation = JsonGetArray( node, "translation", {0.0f, 0.0f, 0.0f} ); + auto scale = JsonGetArray( 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( node, "children" ); + if(children.success) + { + gltfNode.children = std::move(children.result); + } + gltfNode.index = nodeIndex; + gltfNode.cameraId = 0xffffffff; + gltfNode.meshId = 0xffffffff; + + auto cameraId = JsonGetValue( node, "camera", 0xffffffff ); + if( cameraId.success ) + { + gltfNode.cameraId = cameraId.result; + } + auto meshId = JsonGetValue( 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()[0]; + sceneNode.name = JsonGetValue( scene, "name", std::string() ); + auto result = JsonGetArray( scene, "nodes" ); + sceneNode.children = result.result; + sceneNode.index = 0; + } + else if( val.first == "materials" ) + { + for( const auto& node : val.second.get() ) + { + // Get pbr material, base color texture + glTF_Material material{}; + material.doubleSided = JsonGetValue( node, "doubleSided", false ).result; + material.name = JsonGetValue( 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()); + auto texCoord = uint32_t(node1.get("texCoord").get()); + 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() ) + { + auto source = JsonGetValue( item, "source", 0xffffffff ); + textureSources.emplace_back( source.result ); + } + } + else if( val.first == "images" ) + { + for(const auto& item : val.second.get() ) + { + glTF_Texture tex{}; + JsonGetValueOut( item, "name", tex.name ); + JsonGetValueOut( 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 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 glTF::GetMeshes() const +{ + std::vector retval; + for( auto& mesh : mMeshes ) + { + retval.emplace_back( &mesh ); + } + return retval; +} + +std::vector glTF::GetCameras() +{ + std::vector cameras; + for( const auto& cam : mCameras ) + { + cameras.emplace_back( &cam ); + } + return cameras; +} + +std::vector glTF::GetMeshAttributeBuffer( const glTF_Mesh& mesh, const std::vector& attrTypes ) +{ + // find buffer views + struct Data + { + uint32_t accessorIndex{0u}; + uint32_t byteStride{0u}; + char* srcPtr{ nullptr }; + }; + std::vector data{}; + for( const auto& attrType : attrTypes ) + { + std::find_if( mesh.attributes.begin(), mesh.attributes.end(), [&data, &attrType]( const std::pair& 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(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(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 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 retval{}; + retval.resize( accessor.count ); + const auto& bufferView = mBufferViews[accessor.bufferView]; + const auto* srcPtr = reinterpret_cast + (reinterpret_cast(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::GetMaterials() const +{ + return mMaterials; +} + +const std::vector& glTF::GetTextures() const +{ + return mTextures; +} diff --git a/examples/reflection-demo/gltf-scene.h b/examples/reflection-demo/gltf-scene.h new file mode 100644 index 0000000..faecea8 --- /dev/null +++ b/examples/reflection-demo/gltf-scene.h @@ -0,0 +1,178 @@ +/* + * 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 + +#include + +#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> 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 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; + +/** + * 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 GetMeshes() const; + + std::vector GetCameras(); + + const std::vector& GetMaterials() const; + + const std::vector& GetTextures() const; + + const std::vector& GetNodes() const + { + return mNodes; + } + + /** + * MESH interface + */ + /** + * Returns a copy of attribute buffer + * @return + */ + std::vector GetMeshAttributeBuffer( const glTF_Mesh& mesh, const std::vector& 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 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 mMeshes; + std::vector mCameras; + std::vector mBufferViews; + std::vector mAccessors; + std::vector mNodes; + std::vector mMaterials; + std::vector mTextures; + glTF_Buffer mBuffer; + glTF_Buffer jsonBuffer; + + // json nodes + picojson::value jsonNode; +}; + + +#endif //DALI_CMAKE_GLTF_SCENE_H diff --git a/examples/reflection-demo/pico-json.h b/examples/reflection-demo/pico-json.h new file mode 100644 index 0000000..c1cde44 --- /dev/null +++ b/examples/reflection-demo/pico-json.h @@ -0,0 +1,1086 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// for isnan/isinf +#if __cplusplus>=201103L +# include +#else +extern "C" { +# ifdef _MSC_VER +# include +# elif defined(__INTEL_COMPILER) +# include +# else +# include +# 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 +# include +#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 +} +#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 array; + typedef std::map 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 bool is() const; + template const T& get() const; + template T& get(); + template void set(const T &); +#if PICOJSON_USE_RVALUE_REFERENCE + template 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 void serialize(Iter os, bool prettify = false) const; + std::string serialize(bool prettify = false) const; +private: + template value(const T*); // intentionally defined to block implicit conversion of pointer to bool + template static void _indent(Iter os, int indent); + template 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() 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() const { + return type_ == number_type +#ifdef PICOJSON_USE_INT64 + || type_ == int64_type +#endif + ; +} + +#define GET(ctype, var) \ + template <> inline const ctype& value::get() const { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ + } \ + template <> inline ctype& value::get() { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + 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(this)->type_ = number_type, const_cast(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(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 &&_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()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; +} + +inline value& value::get(size_t idx) { + static value s_null; + PICOJSON_ASSERT(is()); + 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::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::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()); + return idx < u_.array_->size(); +} + +inline bool value::contains(const std::string& key) const { + PICOJSON_ASSERT(is()); + 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 void copy(const std::string& s, Iter oi) { + std::copy(s.begin(), s.end(), oi); +} + +template +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(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 void serialize_str(const std::string& s, Iter oi) { + *oi++ = '"'; + serialize_str_char process_char = { oi }; + std::for_each(s.begin(), s.end(), process_char); + *oi++ = '"'; +} + +template 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 void value::_indent(Iter oi, int indent) { + *oi++ = '\n'; + for (int i = 0; i < indent * INDENT_WIDTH; ++i) { + *oi++ = ' '; + } +} + +template 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 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 *self = const_cast*>(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 inline int _parse_quadhex(input &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 inline bool _parse_codepoint(String& out, input& 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 inline bool _parse_string(String& out, input& 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 inline bool _parse_array(Context& ctx, input& 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 inline bool _parse_object(Context& ctx, input& 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 inline std::string _parse_number(input& 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 inline bool _parse(Context& ctx, input& 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::min() <= ival + && ival <= std::numeric_limits::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 bool parse_string(input&) { return false; } + bool parse_array_start() { return false; } + template bool parse_array_item(input&, size_t) { + return false; + } + bool parse_array_stop(size_t) { return false; } + bool parse_object_start() { return false; } + template bool parse_object_item(input&, 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 bool parse_string(input& in) { + *out_ = value(string_type, false); + return _parse_string(out_->get(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template bool parse_array_item(input& in, size_t) { + array& a = out_->get(); + 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 bool parse_object_item(input& in, const std::string& key) { + object& o = out_->get(); + 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 bool parse_string(input& in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { return true; } + template bool parse_array_item(input& in, size_t) { + return _parse(*this, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { return true; } + template bool parse_object_item(input& 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 inline std::string parse(value& out, Iter& pos, const Iter& last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; +} + +template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { + input 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 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(is.rdbuf()), + std::istreambuf_iterator(), &err); + return err; +} + +template struct last_error_t { + static std::string s; +}; +template std::string last_error_t::s; + +inline void set_last_error(const std::string& s) { + last_error_t::s = s; +} + +inline const std::string& get_last_error() { + return last_error_t::s; +} + +inline bool operator==(const value& x, const value& y) { + if (x.is()) + return y.is(); +#define PICOJSON_CMP(type) \ + if (x.is()) \ + return y.is() && x.get() == y.get() + 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(os)); + return os; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/examples/reflection-demo/reflection-example.cpp b/examples/reflection-demo/reflection-example.cpp new file mode 100644 index 0000000..c0eb880 --- /dev/null +++ b/examples/reflection-demo/reflection-example.cpp @@ -0,0 +1,674 @@ +/* + * 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 +#include +#include + +#include + +#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(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(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 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 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 + bool LoadFile( const std::string& filename, std::vector& 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 vshShaderSource; + std::vector 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 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 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 mActors; + std::vector mCameras; + std::vector> mModels; + std::vector 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; +} diff --git a/resources/game/reflection.bin b/resources/game/reflection.bin new file mode 100644 index 0000000..510c7af Binary files /dev/null and b/resources/game/reflection.bin differ diff --git a/resources/game/reflection.gltf b/resources/game/reflection.gltf new file mode 100644 index 0000000..713f818 --- /dev/null +++ b/resources/game/reflection.gltf @@ -0,0 +1,1426 @@ +{ + "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" + } + ] +} diff --git a/resources/game/texture-atlas-license.txt b/resources/game/texture-atlas-license.txt new file mode 100644 index 0000000..9603efa --- /dev/null +++ b/resources/game/texture-atlas-license.txt @@ -0,0 +1,6 @@ +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 + diff --git a/resources/game/texture-atlas.jpg b/resources/game/texture-atlas.jpg new file mode 100644 index 0000000..21b46a7 Binary files /dev/null and b/resources/game/texture-atlas.jpg differ diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po index d5c26e5..d36222d 100755 --- a/resources/po/en_GB.po +++ b/resources/po/en_GB.po @@ -175,6 +175,9 @@ msgstr "Radial Menu" 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" diff --git a/resources/po/en_US.po b/resources/po/en_US.po index c8f0c68..6058031 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -175,6 +175,9 @@ msgstr "Primitive Shapes" 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" diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index fbb8155..8d62660 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -96,6 +96,7 @@ extern "C" #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") @@ -195,6 +196,7 @@ extern "C" #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"