SET(RESOURCE_DIR ${ROOT_SRC_DIR}/resources)
SET(LOCAL_IMAGES_DIR ${RESOURCE_DIR}/images)
+SET(LOCAL_GAME_DIR ${RESOURCE_DIR}/game)
SET(LOCAL_VIDEOS_DIR ${RESOURCE_DIR}/videos)
SET(LOCAL_MODELS_DIR ${RESOURCE_DIR}/models)
SET(LOCAL_SCRIPTS_DIR ${RESOURCE_DIR}/scripts)
ENDIF()
SET(IMAGES_DIR ${APP_DATA_RES_DIR}/images/)
+SET(GAME_DIR ${APP_DATA_RES_DIR}/game/)
SET(VIDEOS_DIR ${APP_DATA_RES_DIR}/videos/)
SET(MODELS_DIR ${APP_DATA_RES_DIR}/models/)
SET(SCRIPTS_DIR ${APP_DATA_RES_DIR}/scripts/)
SET(LOCALE_DIR ${PREFIX}/share/locale)
ENDIF()
+SET(DEMO_GAME_DIR \\"${GAME_DIR}\\")
SET(DEMO_IMAGE_DIR \\"${IMAGES_DIR}\\")
SET(DEMO_VIDEO_DIR \\"${VIDEOS_DIR}\\")
SET(DEMO_MODEL_DIR \\"${MODELS_DIR}\\")
INSTALL(FILES ${LOCAL_SCRIPTS_DIR}/${flag} DESTINATION ${SCRIPTS_DIR})
ENDFOREACH(flag)
+FILE(GLOB LOCAL_GAME_LIST RELATIVE "${LOCAL_GAME_DIR}" "${LOCAL_GAME_DIR}/*.*")
+FOREACH(flag ${LOCAL_GAME_LIST})
+ INSTALL(FILES ${LOCAL_GAME_DIR}/${flag} DESTINATION ${GAME_DIR})
+ENDFOREACH(flag)
+
#Create resources location file
CONFIGURE_FILE( resources-location.in ${DEMO_SHARED}/resources-location.cpp )
SET(REQUIRED_CFLAGS "${REQUIRED_CFLAGS} ${flag}")
ENDFOREACH(flag)
-SET(DALI_DEMO_CFLAGS "-DDEMO_IMAGE_DIR=${DEMO_IMAGE_DIR} -DDEMO_VIDEO_DIR=${DEMO_VIDEO_DIR} -DDEMO_MODEL_DIR=${DEMO_MODEL_DIR} -DDEMO_SCRIPT_DIR=${DEMO_SCRIPT_DIR} -DDEMO_STYLE_DIR=${DEMO_STYLE_DIR} -DDEMO_THEME_PATH=${DEMO_THEME_PATH} -DDEMO_EXAMPLE_BIN=${DEMO_EXAMPLE_BIN} -DDEMO_LOCALE_DIR=${DEMO_LOCALE_DIR} -fvisibility=hidden -DHIDE_DALI_INTERNALS -DDEMO_LANG=${DEMO_LANG}")
+SET(DALI_DEMO_CFLAGS "-DDEMO_GAME_DIR=${DEMO_GAME_DIR} -DDEMO_IMAGE_DIR=${DEMO_IMAGE_DIR} -DDEMO_VIDEO_DIR=${DEMO_VIDEO_DIR} -DDEMO_MODEL_DIR=${DEMO_MODEL_DIR} -DDEMO_SCRIPT_DIR=${DEMO_SCRIPT_DIR} -DDEMO_STYLE_DIR=${DEMO_STYLE_DIR} -DDEMO_THEME_PATH=${DEMO_THEME_PATH} -DDEMO_EXAMPLE_BIN=${DEMO_EXAMPLE_BIN} -DDEMO_LOCALE_DIR=${DEMO_LOCALE_DIR} -fvisibility=hidden -DHIDE_DALI_INTERNALS -DDEMO_LANG=${DEMO_LANG}")
###########################################################################
# Internationalization
<ui-application appid="contact-cards.example" exec="/usr/apps/com.samsung.dali-demo/bin/contact-cards.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
<label>Contact Cards</label>
</ui-application>
+ <ui-application appid="fpp-game.example" exec="/usr/apps/com.samsung.dali-demo/bin/fpp-game.example" nodisplay="true" multiple="false" type="c++app" taskmanage="true">
+ <label>First Person Camera Game</label>
+ </ui-application>
</manifest>
demo.AddExample(Example("sparkle.example", DALI_DEMO_STR_TITLE_SPARKLE));
demo.AddExample(Example("progress-bar.example", DALI_DEMO_STR_TITLE_PROGRESS_BAR));
demo.AddExample(Example("contact-cards.example", DALI_DEMO_STR_TITLE_CONTACT_CARDS));
+ demo.AddExample(Example("fpp-game.example", DALI_DEMO_STR_TITLE_FPP_GAME));
demo.SortAlphabetically( true );
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-renderer.h"
+#include "game-model.h"
+#include "game-texture.h"
+#include "game-scene.h"
+
+#include "fpp-game-tutorial-controller.h"
+
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+
+namespace
+{
+
+const char* SCENE_URL =
+{
+ DEMO_GAME_DIR "/scene.json"
+};
+
+}
+/* This example creates 3D environment with first person camera control
+ It contains following modules:
+
+ GameScene - responsible for loading and managing the scene data,
+ it wraps around stage. Owns list of entities. Scene can be deserialised
+ from json file ( see scene.json )
+ GameEntity - the renderable object that has also a transformation. It wraps DALi actors.
+
+ GameModel - loads models ( '.mod' file format ) and wraps DALi Geometry object. 'mod' format
+ is binary in order
+
+ GameTexture - manages textures. Loads them, creates samplers and wraps DALi TextureSet
+
+ GameRenderer - binds texture and model. It's created per entity. While renderer is always unique
+ for entity, the texture and model may be reused
+
+ GameCamera - Wraps the CameraActor. It provides not only that but also handles user input and
+ implements first-person-perspective camera behavior.
+ GameCamera uses Dali::Timer to provide per-frame ( or rather every 16ms ) update tick.
+
+
+ .-----------.
+ .---------------| GameScene |---------------.
+ | '-----------' |
+ | | |
+ v | v
+ .------------. .------------.|.------------. .------------.
+ | GameEntity | | GameEntity |v| ... | | GameEntity |
+ '------------' '------------' '------------' '------------'
+ |
+ v
+ .--------------.
+ | GameRenderer |
+ '--------------'
+ |
+ <------'-------->
+.--------------. .--------------.
+| GameTexture | | GameModel |
+'--------------' '--------------'
+ */
+class GameController : public ConnectionTracker
+{
+public:
+
+ GameController( Application& application )
+ : mApplication( application )
+ {
+ // Connect to the Application's Init signal
+ mApplication.InitSignal().Connect( this, &GameController::Create );
+ }
+
+ ~GameController()
+ {
+ }
+
+ // The Init signal is received once (only) during the Application lifetime
+ void Create( Application& application )
+ {
+ // Get a handle to the stage
+ mStage = Stage::GetCurrent();
+
+ mStage.SetBackgroundColor( Color::BLACK );
+
+ // Use 3D layer
+ mStage.GetRootLayer().SetBehavior( Layer::LAYER_3D );
+
+ // Load game scene
+ mScene.Load( SCENE_URL );
+
+ // Display tutorial
+ mTutorialController.DisplayTutorial();
+
+ // Connect OnKeyEvent signal
+ mStage.KeyEventSignal().Connect( this, &GameController::OnKeyEvent );
+ }
+
+ // Handle a quit key event
+ 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();
+ }
+ }
+ }
+
+private:
+
+ Application& mApplication;
+ GameScene mScene;
+ Stage mStage;
+ FppGameTutorialController mTutorialController;
+};
+
+void RunTest( Application& application )
+{
+ GameController test( application );
+
+ application.MainLoop();
+}
+
+// Entry point for Linux & Tizen applications
+//
+int DALI_EXPORT_API main( int argc, char **argv )
+{
+ Application application = Application::New( &argc, &argv );
+
+ RunTest( application );
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "fpp-game-tutorial-controller.h"
+
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+FppGameTutorialController::FppGameTutorialController()
+: mLeftTutorialComplete( false ),
+ mRightTutorialComplete( false )
+{
+
+}
+
+FppGameTutorialController::~FppGameTutorialController()
+{
+
+}
+
+void FppGameTutorialController::OnTouch( const TouchData& touchEvent )
+{
+ Vector2 size( mStage.GetSize() );
+
+ bool isLandscape( size.x > size.y );
+
+ if( !isLandscape )
+ {
+ std::swap( size.x, size.y );
+ }
+
+ Vector2 sizeHalf( size * 0.5f );
+
+ for( size_t i = 0; i < touchEvent.GetPointCount(); ++i )
+ {
+ Vector2 pos = touchEvent.GetScreenPosition( i );
+ if( !isLandscape )
+ {
+ std::swap( pos.x, pos.y );
+ }
+
+ // left label touched
+ if( touchEvent.GetState( i ) == PointState::STARTED )
+ {
+ if( pos.x < sizeHalf.x && !mLeftTutorialComplete )
+ {
+ mLeftTutorialComplete = true;
+ Animation animation = Animation::New( 1.0f );
+ animation.AnimateTo( Property( mLeftLabel, Actor::Property::COLOR_ALPHA ), 0.0f );
+
+ // connect complete signal
+ if( mRightTutorialComplete )
+ {
+ animation.FinishedSignal().Connect( this, &FppGameTutorialController::OnTutorialComplete );
+ }
+ animation.Play();
+ }
+ // right label touched
+ else if( !mRightTutorialComplete )
+ {
+ mRightTutorialComplete = true;
+ Animation animation = Animation::New( 1.0f );
+ animation.AnimateTo( Property( mRightLabel, Actor::Property::COLOR_ALPHA ), 0.0f );
+ // connect complete signal
+ if( mLeftTutorialComplete )
+ {
+ animation.FinishedSignal().Connect( this, &FppGameTutorialController::OnTutorialComplete );
+ }
+ animation.Play();
+ }
+ }
+ }
+}
+
+void FppGameTutorialController::DisplayTutorial()
+{
+ mStage = Stage::GetCurrent();
+
+ Vector2 stageSize( mStage.GetSize() );
+ bool isLandscape( stageSize.x > stageSize.y );
+ if( !isLandscape )
+ {
+ std::swap( stageSize.x, stageSize.y );
+ }
+
+ mUiRoot = Actor::New();
+ mStage.Add( mUiRoot );
+
+ // left tutorial text label
+ mLeftLabel = Toolkit::TextLabel::New("Touch here to walk");
+ mLeftLabel.SetParentOrigin( ParentOrigin::CENTER );
+ mLeftLabel.SetAnchorPoint( AnchorPoint::CENTER );
+ mLeftLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+ mLeftLabel.SetSize( Vector3( stageSize.x*0.5, stageSize.y, 1.0f ) );
+ mLeftLabel.SetProperty( Toolkit::Control::Property::BACKGROUND_COLOR, Vector4( 0.0, 0.0, 0.7, 0.2 ));
+ mLeftLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); // White.
+ mLeftLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+ mLeftLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+
+ // right tutorial text label
+ mRightLabel = Toolkit::TextLabel::New("Touch here to look around");
+ mRightLabel.SetParentOrigin( ParentOrigin::CENTER );
+ mRightLabel.SetAnchorPoint( AnchorPoint::CENTER );
+ mRightLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+ mRightLabel.SetSize( Vector3( stageSize.x*0.5, stageSize.y, 1.0f ) );
+ mRightLabel.SetProperty( Toolkit::Control::Property::BACKGROUND_COLOR, Vector4( 0.5, 0.0, 0.0, 0.2 ));
+ mRightLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) ); // White.
+ mRightLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+ mRightLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+
+ // create camera dedicated to be used with UI controls
+ CameraActor uiCamera = CameraActor::New();
+ mTutorialRenderTask = mStage.GetRenderTaskList().CreateTask();
+ mTutorialRenderTask.SetCameraActor( uiCamera );
+ mTutorialRenderTask.SetClearEnabled( false );
+ mTutorialRenderTask.SetSourceActor( mUiRoot );
+ mTutorialRenderTask.SetExclusive( true );
+
+ if( !isLandscape )
+ {
+ uiCamera.RotateBy( Degree(90.0f), Vector3( 0.0f, 0.0f, 1.0f ));
+ }
+
+ mLeftLabel.SetPosition( Vector3( -stageSize.x*0.25f, 0.0, 0.0 ) );
+ mRightLabel.SetPosition( Vector3( stageSize.x*0.25f, 0.0, 0.0 ) );
+
+ mUiRoot.Add( mLeftLabel );
+ mUiRoot.Add( mRightLabel );
+ mStage.Add( uiCamera );
+
+ Animation animation = Animation::New( 1.0f );
+ animation.AnimateTo( Property( mLeftLabel, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_OUT );
+ animation.AnimateTo( Property( mRightLabel, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_OUT );
+
+ animation.FinishedSignal().Connect( this, &FppGameTutorialController::OnTutorialAnimationFinished );
+
+ animation.Play();
+}
+
+void FppGameTutorialController::OnTutorialAnimationFinished( Animation& animation )
+{
+ // touch signal will wait for a single touch on each side of screen
+ mStage.TouchSignal().Connect( this, &FppGameTutorialController::OnTouch );
+}
+
+void FppGameTutorialController::OnTutorialComplete( Animation& animation )
+{
+ mStage.Remove( mUiRoot );
+ mUiRoot.Reset();
+ mStage.GetRenderTaskList().RemoveTask( mTutorialRenderTask );
+}
+
--- /dev/null
+#ifndef FPPGAMETUTORIAL_H
+#define FPPGAMETUTORIAL_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+
+class FppGameTutorialController : public Dali::ConnectionTracker
+{
+public:
+
+ /**
+ * Creates new instance of FppGameTutorialController
+ */
+ FppGameTutorialController();
+
+ /**
+ * Destroys instance of FppGameTutorialController
+ */
+ ~FppGameTutorialController();
+
+ /**
+ * Displays UI with tutorial
+ */
+ void DisplayTutorial();
+
+ /**
+ * Handles tutorial touch input
+ * @param[in] touchEvent Incoming touch event in the UI space
+ */
+ void OnTouch( const Dali::TouchData& touchEvent );
+
+ /**
+ * Handles tutorial animation finished signal
+ * @param[in] animation Animation object
+ */
+ void OnTutorialAnimationFinished( Dali::Animation& animation );
+
+ /**
+ * Handles tutorial completion stage
+ * @param animation Animation object
+ */
+ void OnTutorialComplete( Dali::Animation& animation );
+
+private:
+
+ Dali::RenderTask mTutorialRenderTask; /// RenderTask associated with rendering tutorial
+ Dali::Actor mUiRoot; /// The parent actor for tutorial UI
+ Dali::Toolkit::TextLabel mLeftLabel; /// Text label displaying left message
+ Dali::Toolkit::TextLabel mRightLabel; /// Text label displaying right message
+ bool mLeftTutorialComplete; /// Flag indicating the walk (left) tutorial action has been performed
+ bool mRightTutorialComplete; /// Flag indicating the look (right) tutorial action has been performed
+ Dali::Stage mStage;
+};
+
+#endif // FPPGAMETUTORIAL_H
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-camera.h"
+
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/events/touch-event.h>
+
+using namespace Dali;
+
+namespace
+{
+// Input sensitivity, the larger value, the more sensitive input
+// Default value has been chosen empirically
+const float CAMERA_SENSITIVITY ( 90.0f );
+
+// Vertical angle limit of the camera
+const float CAMERA_VERTICAL_LIMIT ( 80.0f );
+
+// Position where camera is instantiated by default
+const Vector3 CAMERA_DEFAULT_POSITION ( 1.0f, -1.5f, -3.0f );
+
+// Field-of-View in degrees
+const float CAMERA_DEFAULT_FOV ( 60.0f );
+
+// Near plane
+const float CAMERA_DEFAULT_NEAR ( 0.1f );
+
+// Far plane
+const float CAMERA_DEFAULT_FAR ( 100.0f );
+
+// Default forward vector
+const Vector3 CAMERA_FORWARD ( 0.0f, 0.0f, 1.0f );
+
+// Default up vector
+const Vector3 CAMERA_UP ( Vector3::YAXIS );
+}
+
+GameCamera::GameCamera()
+: mFovY( CAMERA_DEFAULT_FOV ),
+ mNear( CAMERA_DEFAULT_NEAR ),
+ mFar( CAMERA_DEFAULT_FAR ),
+ mWalkingTouchId( -1 ),
+ mLookingTouchId( -1 ),
+ mPortraitMode( false )
+{
+}
+
+GameCamera::~GameCamera()
+{
+ mTimer.Stop();
+ mCameraActor.Remove( mInterceptorActor );
+}
+
+void GameCamera::Initialise( float fovY, float near, float far )
+{
+ mFovY = fovY;
+ mNear = near;
+ mFar = far;
+
+ Vector2 stageSize = Stage::GetCurrent().GetSize();
+ mPortraitMode = stageSize.x < stageSize.y ? true : false;
+
+ // Initialise default camera
+ InitialiseDefaultCamera();
+
+ // Create input interceptor actor
+ CreateInterceptorActor();
+
+ // Start timer
+ mTimer = Timer::New( 16 );
+ mTimer.TickSignal().Connect( this, &GameCamera::OnTick );
+ mTimer.Start();
+}
+
+bool GameCamera::OnTick()
+{
+ Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+ // ---------------------------------------------------------------------
+ // update rotation
+ Vector2 tmp( mScreenLookDelta );
+ mScreenLookDelta = Vector2::ZERO;
+
+ if( mPortraitMode )
+ {
+ float yaw = ( (tmp.y / stageSize.y ) * CAMERA_SENSITIVITY );
+ float pitch = ( (tmp.x / stageSize.x ) * CAMERA_SENSITIVITY );
+ mCameraYawPitch.y -= yaw;
+ mCameraYawPitch.x -= pitch;
+ if( abs( mCameraYawPitch.y ) > CAMERA_VERTICAL_LIMIT )
+ {
+ mCameraYawPitch.y = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.y < 0) ? -1.0f : 1.0f );
+ }
+ }
+ else
+ {
+ float yaw = ( (tmp.y / stageSize.x ) * CAMERA_SENSITIVITY );
+ float pitch = ( (tmp.x / stageSize.y ) * CAMERA_SENSITIVITY );
+ mCameraYawPitch.x -= yaw;
+ mCameraYawPitch.y -= pitch;
+ if( abs( mCameraYawPitch.x ) > CAMERA_VERTICAL_LIMIT )
+ {
+ mCameraYawPitch.x = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.x < 0) ? -1.0f : 1.0f );
+ }
+ }
+
+ Quaternion rotation;
+ Quaternion rotX( Degree( mCameraYawPitch.x), Vector3( 1.0f, 0.0f, 0.0f ) );
+ Quaternion rotY( Degree( mCameraYawPitch.y), Vector3( 0.0f, 1.0f, 0.0f ) );
+ if (mPortraitMode )
+ {
+ Quaternion rotZ( Degree( mPortraitMode ? 90.0 : 0.0f), Vector3( 0.0f, 0.0f, 1.0f ) );
+ rotation = ( rotZ * rotX * rotY );
+ }
+ else
+ {
+ rotation = ( rotY * rotX );
+ }
+ mCameraActor.SetOrientation( rotation );
+
+ // ---------------------------------------------------------------------
+ // update position
+ Vector3 position( mCameraPosition );
+
+ // Rotate CAMERA_FORWARD vector
+ Vector3 forwardVector = rotation.Rotate( CAMERA_FORWARD );
+
+ // Cancel vertical movement
+ forwardVector.y = 0.0f;
+
+ // Normalize
+ forwardVector.Normalize();
+
+ // compute sideways vector
+ Vector3 sidewaysVector = forwardVector.Cross( CAMERA_UP );
+
+ sidewaysVector.Normalize();
+
+ const float forwardSpeed( mScreenWalkDelta.y / stageSize.y );
+ const float sidewaysSpeed( mScreenWalkDelta.x / stageSize.x );
+
+ // Adjust walking speed
+ if ( mPortraitMode )
+ {
+ position += forwardVector * (forwardSpeed * 0.5f);
+ }
+ else
+ {
+ position += forwardVector * (-forwardSpeed * 0.5f);
+ }
+
+ position += sidewaysVector * (sidewaysSpeed * 0.5f);
+
+ mCameraActor.SetPosition( position );
+
+ mCameraPosition = position;
+
+ return true;
+}
+
+void GameCamera::InitialiseDefaultCamera()
+{
+ Stage stage = Stage::GetCurrent();
+ mCameraActor = stage.GetRenderTaskList().GetTask(0).GetCameraActor();
+ mCameraActor.SetName( "GameCamera" );
+ mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+ mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
+ mCameraActor.SetFieldOfView( Radian( Degree( mFovY ) ) );
+
+ // should be read from file
+ mCameraActor.SetNearClippingPlane( mNear );
+ mCameraActor.SetFarClippingPlane( mFar );
+ mCameraActor.SetPosition( CAMERA_DEFAULT_POSITION );
+
+ // Camera position is shadowed in order to avoid using GetCurrentPosition()
+ mCameraPosition = CAMERA_DEFAULT_POSITION;
+}
+
+void GameCamera::CreateInterceptorActor()
+{
+ Stage stage = Stage::GetCurrent();
+
+ mInterceptorActor = Actor::New();
+ mInterceptorActor.SetName( "GameInputInterceptor" );
+ mInterceptorActor.SetSize( Vector3( stage.GetSize().x, stage.GetSize().y, 1 ) );
+ mInterceptorActor.SetPosition( Vector3( 0.0, 0.0, 1.0 ) );
+ mInterceptorActor.SetAnchorPoint( AnchorPoint::CENTER );
+ mInterceptorActor.SetParentOrigin( ParentOrigin::CENTER );
+ mCameraActor.Add( mInterceptorActor );
+
+ // Connect TouchSignal to interceptor actor
+ mInterceptorActor.TouchSignal().Connect( this, &GameCamera::OnTouch );
+}
+
+bool GameCamera::OnTouch( Actor actor, const TouchData& touch )
+{
+ Stage stage = Stage::GetCurrent();
+
+ for( int i = 0; i < (int)touch.GetPointCount() && i < 3; ++i )
+ {
+ int id = touch.GetDeviceId( i );
+ Vector2 tmp( touch.GetScreenPosition( i ) );
+ Vector2 position;
+ float halfWindowSize;
+ if( mPortraitMode )
+ {
+ position.x = tmp.y;
+ position.y = tmp.x;
+ halfWindowSize = stage.GetSize().y / 2;
+ }
+ else
+ {
+ position.x = tmp.x;
+ position.y = tmp.y;
+ halfWindowSize = stage.GetSize().x / 2;
+ }
+
+ // touch started
+ if( touch.GetState( i ) == PointState::STARTED )
+ {
+ // start looking
+ if( position.x > halfWindowSize && mLookingTouchId < 0 )
+ {
+ mLookingTouchId = id;
+ mOldTouchLookPosition = position;
+ }
+ // start walking
+ else if( position.x < halfWindowSize && mWalkingTouchId < 0 )
+ {
+ mWalkingTouchId = id;
+ mOldTouchWalkPosition = position;
+ mScreenWalkDelta = Vector2::ZERO;
+ }
+ }
+ else if( touch.GetState( i ) == PointState::FINISHED ||
+ touch.GetState( i ) == PointState::LEAVE ||
+ touch.GetState( i ) == PointState::INTERRUPTED
+ )
+ {
+ // terminate look
+ if( mLookingTouchId == id )
+ {
+ mScreenLookDelta = Vector2::ZERO;
+ mOldTouchLookPosition = Vector2::ZERO;
+ mLookingTouchId = -1;
+ }
+ // terminate walking
+ else if( mWalkingTouchId == id )
+ {
+ mScreenWalkDelta = Vector2::ZERO;
+ mOldTouchWalkPosition = Vector2::ZERO;
+ mWalkingTouchId = -1;
+ }
+ }
+ else // on motion
+ {
+ // update looking
+ if( mLookingTouchId == id )
+ {
+ mScreenLookDelta.x += ( position.x - mOldTouchLookPosition.x );
+ mScreenLookDelta.y += ( position.y - mOldTouchLookPosition.y );
+ mOldTouchLookPosition = position;
+ }
+ // update walking
+ else if ( mWalkingTouchId == id )
+ {
+ mScreenWalkDelta.x += ( position.x - mOldTouchWalkPosition.x );
+ mScreenWalkDelta.y += ( position.y - mOldTouchWalkPosition.y );
+ mOldTouchWalkPosition = position;
+ }
+ }
+ }
+ return true;
+}
--- /dev/null
+#ifndef GAME_CAMERA_H
+#define GAME_CAMERA_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/math/vector2.h>
+
+/**
+ * @brief The GameCamera class
+ * First-person camera implementation with handling user input
+ *
+ * GameCamera uses the DALi camera for displaying 3D game view.
+ * Additionally it handles simple user input by attaching fullscreen
+ * sized 'interceptor' Actor to the front of the CameraActor ( to be always
+ * parallel to the view ). It is necessary, as with changing camera orientation
+ * the the stage cannot be used as a touch signal receiver ( it will simply
+ * go offscreen with camera rotation ).
+ *
+ * DALi camera uses left-handed coordinate system.
+ *
+ * The control scheme assumes that left half of the screen is responsible for
+ * movement, the right half of screen is a rotation.
+ */
+class GameCamera : public Dali::ConnectionTracker
+{
+public:
+
+ /**
+ * Creates an instance of GameCamera
+ */
+ GameCamera();
+
+ /**
+ * Destroys an instance of GameCamera
+ */
+ ~GameCamera();
+
+ /**
+ * Initialise with given fovY, near, far
+ * @param[in] fovY Field of view in degrees
+ * @param[in] near Near plane
+ * @param[in] far Far Plane
+ */
+ void Initialise( float fov, float near, float far );
+
+ /**
+ * Retrieves actor associated with camera object
+ * @return Returns camera actor
+ */
+ Dali::CameraActor GetCameraActor();
+
+private:
+
+ /**
+ * Sets up a perspective camera using Dali default camera
+ */
+ void InitialiseDefaultCamera();
+
+ /**
+ * Creates 'interceptor' actor. Interceptor actor is always parallel
+ * to the camera and positioned little bit in front of it in order to
+ * intercept user input.
+ */
+ void CreateInterceptorActor();
+
+ /**
+ * Handles onTouch signal on the 'interceptor' actor
+ * @param[in] actor Actor receiving signal
+ * @param[in] touch Touch data
+ */
+ bool OnTouch( Dali::Actor actor, const Dali::TouchData& touch );
+
+ /**
+ * Handles camera tick() update
+ * @return true if continue running timer, false otherwise
+ */
+ bool OnTick();
+
+private:
+
+ Dali::CameraActor mCameraActor; /// Camera actor
+ Dali::Actor mInterceptorActor; /// Actor intercepting user input
+
+ Dali::Timer mTimer; /// Per-frame timer
+
+ Dali::Vector2 mScreenLookDelta; /// Look delta vector in screen space
+ Dali::Vector2 mScreenWalkDelta; /// Walk delta vector in screen space
+ Dali::Vector2 mOldTouchLookPosition; /// Previous look vector in screen space
+ Dali::Vector2 mOldTouchWalkPosition; /// Previuus walk vector in screen space
+
+ Dali::Vector2 mCameraYawPitch; /// Camera yaw-pitch angles
+
+ float mFovY; /// Camera field-of-view
+ float mNear; /// Near plane
+ float mFar; /// Far plane
+
+ int mWalkingTouchId; /// Touch device id bound to the walking action
+ int mLookingTouchId; /// Touch device id bound to the looking action
+
+ Dali::Vector3 mCameraPosition; /// Current camera position ( shadowing the actor position )
+
+ bool mPortraitMode; /// flag if window is in portrait mode ( physically stage width < height )
+};
+
+#endif
--- /dev/null
+#ifndef GAME_CONTAINER_H
+#define GAME_CONTAINER_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/common/dali-vector.h>
+
+
+/**
+ * GameContainer is a vector which owns heap-allocated objects.
+ * Unlike vector this will call delete on the stored pointers during destruction.
+ * For example, you can define a vector of heap-allocated Node objects:
+ * @code
+ * typedef GameContainer< GameEntity* > EntityArray;
+ *
+ * EntityArray entites;
+ * entites.PushBack( new GameEntity() );
+ * // container is now responsible for calling delete on GameEntity
+ *
+ * @endcode
+ */
+template< class T > class GameContainer : public Dali::Vector< T >
+{
+public:
+
+ typedef typename Dali::Vector< T >::Iterator Iterator;
+ typedef typename Dali::Vector< T >::ConstIterator ConstIterator;
+
+ /**
+ * Create a owner container.
+ */
+ GameContainer()
+ {
+ }
+
+ /**
+ * Non-virtual destructor; GameCache<T> is not suitable as base class.
+ */
+ ~GameContainer()
+ {
+ Clear();
+ Dali::VectorBase::Release();
+ }
+
+ /**
+ * Destroy all of the elements in the container.
+ */
+ void Clear()
+ {
+ ConstIterator end = Dali::Vector< T >::End();
+ for( Iterator iter = Dali::Vector< T >::Begin(); iter != end; ++iter )
+ {
+ delete (*iter);
+ }
+ Dali::Vector< T >::Clear();
+ }
+
+private:
+
+ // Undefined copy constructor.
+ GameContainer( const GameContainer& );
+
+ // Undefined assignment operator.
+ GameContainer& operator=( const GameContainer& );
+};
+
+#endif // GAMECACHE_H
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-entity.h"
+#include "game-renderer.h"
+
+GameEntity::GameEntity( const char* name )
+{
+ mActor = Dali::Actor::New();
+ mActor.SetName( name );
+}
+
+GameEntity::~GameEntity()
+{
+}
+
+void GameEntity::UpdateRenderer()
+{
+ if( mActor.GetRendererCount() )
+ {
+ Dali::Renderer currentRenderer = mActor.GetRendererAt( 0 );
+ if( currentRenderer == mGameRenderer.GetRenderer() )
+ {
+ return;
+ }
+ mActor.RemoveRenderer( currentRenderer );
+ }
+ if( mGameRenderer.GetRenderer() )
+ {
+ mActor.AddRenderer( mGameRenderer.GetRenderer() );
+ }
+}
+
+GameRenderer& GameEntity::GetGameRenderer()
+{
+ return mGameRenderer;
+}
+
+Dali::Actor& GameEntity::GetActor()
+{
+ return mActor;
+}
+
+void GameEntity::SetLocation( const Dali::Vector3& loc )
+{
+ mActor.SetPosition( loc );
+}
+
+void GameEntity::SetRotation( const Dali::Quaternion& rot )
+{
+ mActor.SetOrientation( rot );
+}
+
+void GameEntity::SetScale( const Dali::Vector3& scale )
+{
+ mActor.SetScale( scale );
+}
+
+void GameEntity::SetSize( const Dali::Vector3& size )
+{
+ mActor.SetSize( size );
+}
--- /dev/null
+#ifndef GAME_ENTITY_H
+#define GAME_ENTITY_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-renderer.h"
+
+#include <dali/public-api/actors/actor.h>
+
+/**
+ * @brief The GameEntity class
+ * GameEntity wraps the Dali::Actor class and binds the GameRenderer with
+ * loaded entity. Entities are owned by the GameScene and populated when
+ * scene is being deserialized.
+ */
+class GameEntity
+{
+public:
+
+ /**
+ * Creates an instance of GameEntity with given name
+ * @param[in] name Name of created entity
+ */
+ GameEntity( const char* name );
+
+ /**
+ * Destroys an instance of GameEntity
+ */
+ ~GameEntity();
+
+ /**
+ * Returns the GameRenderer object
+ */
+ GameRenderer& GetGameRenderer();
+
+ /**
+ * Returns associated DALi actor
+ * @return Returns actor associated with this GameEntity
+ */
+ Dali::Actor& GetActor();
+
+ /**
+ * Sets location of entity
+ * @param[in] location Local position of entity
+ */
+ void SetLocation( const Dali::Vector3& location );
+
+ /**
+ * Sets rotation of entity
+ * @param[in] rotation Local rotation of entity
+ */
+ void SetRotation( const Dali::Quaternion& rotation );
+
+ /**
+ * Sets scale of entity
+ * @param[in] scale Local scale of entity
+ */
+ void SetScale( const Dali::Vector3& scale );
+
+ /**
+ * Sets size of entity
+ * @param[in] size Bounding box of entity
+ */
+ void SetSize( const Dali::Vector3& size );
+
+ /**
+ * Updates Dali::Renderer in case if anything changed ( geometry, texture, etc. )
+ */
+ void UpdateRenderer();
+
+private:
+
+ Dali::Actor mActor;
+ GameRenderer mGameRenderer;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-model.h"
+#include "game-utils.h"
+
+using namespace GameUtils;
+
+namespace
+{
+// 'MODV' tag stored in the big-endian (network) order
+const uint32_t MODV_TAG( 0x4D4F4456 );
+}
+
+GameModel::GameModel( const char *filename )
+ : mUniqueId( false ),
+ mIsReady( false )
+{
+ ByteArray bytes;
+ if( !LoadFile( filename, bytes ) )
+ {
+ return;
+ }
+
+ mHeader = *(reinterpret_cast<ModelHeader*>( bytes.data() ));
+
+ // expect big-endian
+ if( MODV_TAG != mHeader.tag )
+ {
+ // jump to little-endian variant
+ mHeader = *(reinterpret_cast<ModelHeader*>( bytes.data() + bytes.size()/2 ));
+ }
+
+ mVertexBuffer = Dali::PropertyBuffer::New( Dali::Property::Map().
+ Add( "aPosition", Dali::Property::VECTOR3 ).
+ Add( "aNormal", Dali::Property::VECTOR3 ).
+ Add( "aTexCoord", Dali::Property::VECTOR2 )
+ );
+
+ mVertexBuffer.SetData( bytes.data() + mHeader.dataBeginOffset, mHeader.vertexBufferSize/mHeader.vertexStride );
+
+ mGeometry = Dali::Geometry::New();
+ mGeometry.AddVertexBuffer( mVertexBuffer );
+ mGeometry.SetType( Dali::Geometry::TRIANGLES );
+
+ mUniqueId = HashString( filename );
+
+ mIsReady = true;
+}
+
+GameModel::~GameModel()
+{
+}
+
+Dali::Geometry& GameModel::GetGeometry()
+{
+ return mGeometry;
+}
+
+bool GameModel::IsReady()
+{
+ return mIsReady;
+}
+
+uint32_t GameModel::GetUniqueId()
+{
+ return mUniqueId;
+}
--- /dev/null
+#ifndef GAME_MODEL_H
+#define GAME_MODEL_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/property-buffer.h>
+
+#include <inttypes.h>
+
+/**
+ * @brief The ModelHeader struct
+ * Model file header structure
+ */
+struct ModelHeader
+{
+ uint32_t tag; /// 'MODV' tag
+ uint32_t version; /// File version
+ uint32_t vertexBufferSize; /// total size of the vertex buffer to allocate
+ uint32_t attributeCount; /// number of stored attributes
+ uint32_t attributeFormat[16]; /// format encoded as ((type << 16)|(count)); 'type' represents primitive type, 'count' represents number of components ( 1-4 )
+ uint32_t attributeOffset[16]; /// attribute offsets
+ uint32_t attributeSize[16]; /// attribute size in bytes
+ uint32_t vertexStride; /// vertex stride
+ uint32_t reserved; /// reserved, may point at additional structure
+ uint32_t dataBeginOffset; /// start of actual vertex data
+};
+
+/**
+ * @brief The GameModel class
+ * GameModel represents model geometry. It loads model data from external model file ( .mod file ).
+ * Such data is ready to be used as GL buffer so it can be copied directly into the PropertyBuffer
+ * object.
+ *
+ * Model file is multi-architecture so can be loaded on little and big endian architectures
+ */
+class GameModel
+{
+public:
+
+ /**
+ * Creates an instance of GameModel and loads the '.mod' file
+ * @param[in] filename Name of file to load
+ */
+ GameModel( const char* filename );
+
+ /**
+ * Destroys an instance of GameModel
+ */
+ ~GameModel();
+
+ /**
+ * Returns DALi geometry object
+ * @return Returns DALi geometry object
+ */
+ Dali::Geometry& GetGeometry();
+
+ /**
+ * Checks status of model, returns false if failed to load
+ * @return true if model has been loaded, false otherwise
+ */
+ bool IsReady();
+
+ /**
+ * Returns unique Id of the texture
+ * @return Unique Id
+ */
+ uint32_t GetUniqueId();
+
+private:
+
+ Dali::Geometry mGeometry;
+ Dali::PropertyBuffer mVertexBuffer;
+
+ ModelHeader mHeader;
+
+ uint32_t mUniqueId;
+ bool mIsReady;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "game-model.h"
+#include "game-texture.h"
+#include "game-renderer.h"
+
+#include <dali/dali.h>
+
+namespace
+{
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+ attribute highp vec3 aPosition;\n
+ attribute highp vec3 aNormal;\n
+ attribute highp vec2 aTexCoord;\n
+ uniform highp mat4 uMvpMatrix;\n
+ varying highp vec2 vTexCoord;\n
+ void main()\n
+ {\n
+ gl_Position = uMvpMatrix * vec4(aPosition, 1.0 );\n
+ vTexCoord = aTexCoord;\n
+ vTexCoord.y = 1.0 - vTexCoord.y;\n
+ }\n
+)
+ ;
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ uniform sampler2D sTexture;\n
+ varying highp vec2 vTexCoord;\n
+ void main()\n
+ {\n
+ gl_FragColor = texture2D( sTexture, vTexCoord ) * vec4(1.2, 1.2, 1.2, 1.0);\n
+ }\n
+);
+
+}
+
+GameRenderer::GameRenderer()
+ : mModel( NULL ),
+ mTexture( NULL )
+{
+}
+
+GameRenderer::~GameRenderer()
+{
+}
+
+void GameRenderer::SetModel( GameModel* model )
+{
+ mModel = model;
+ Setup();
+}
+
+void GameRenderer::SetMainTexture( GameTexture* texture )
+{
+ mTexture = texture;
+ Setup();
+}
+
+void GameRenderer::Setup()
+{
+ if( !mRenderer && mModel )
+ {
+ Dali::Shader shader = Dali::Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mRenderer = Dali::Renderer::New( mModel->GetGeometry(), shader );
+ mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_WRITE_MODE, Dali::DepthWriteMode::ON );
+ mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_FUNCTION, Dali::DepthFunction::LESS_EQUAL );
+ mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_TEST_MODE, Dali::DepthTestMode::ON );
+ }
+
+ Dali::TextureSet textureSet;
+ Dali::Geometry geometry;
+
+ if( mModel )
+ {
+ geometry = mModel->GetGeometry();
+ }
+
+ if( mTexture && mTexture->GetTextureSet() )
+ {
+ textureSet = mTexture->GetTextureSet();
+ }
+
+ if( textureSet && geometry )
+ {
+ mRenderer.SetGeometry( geometry );
+ mRenderer.SetTextures( textureSet );
+ }
+}
+
+Dali::Renderer& GameRenderer::GetRenderer()
+{
+ return mRenderer;
+}
+
+
+
--- /dev/null
+#ifndef GAME_RENDERER_H
+#define GAME_RENDERER_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/rendering/renderer.h>
+
+class GameModel;
+class GameTexture;
+
+/**
+ * @brief The GameRenderer class
+ * GameRenderer binds the main texture with model. Can be used by multiple entities. It wraps
+ * Dali::Renderer.
+ */
+class GameRenderer
+{
+public:
+
+ /**
+ * Creates an instance of the GameRenderer
+ */
+ GameRenderer();
+
+ /**
+ * Destroys an instance of the GameRenderer
+ */
+ ~GameRenderer();
+
+ /**
+ * Sets current model on the renderer
+ * Resets the Dali::Renderer or creates new one on first time setup
+ * @param[in] model Pointer to the GameModel object
+ */
+ void SetModel( GameModel* model );
+
+ /**
+ * Sets main texture on the renderer
+ * Resets the Dali::Renderer or creates new one on first time setup
+ * @param[in] texture Pointer to the GameTexture object
+ */
+ void SetMainTexture( GameTexture* texture );
+
+ /**
+ * Retrieves DALi renderer object
+ */
+ Dali::Renderer& GetRenderer();
+
+private:
+
+ /**
+ * Initialises rendering data
+ */
+ void Setup();
+
+private:
+
+ Dali::Renderer mRenderer;
+ GameModel* mModel;
+ GameTexture* mTexture;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "game-scene.h"
+#include "game-model.h"
+#include "game-texture.h"
+#include "game-entity.h"
+#include "game-renderer.h"
+#include "game-camera.h"
+
+#include "third-party/picojson.h"
+
+#include <dali/dali.h>
+
+using namespace Dali;
+using namespace picojson;
+
+using std::vector;
+
+using namespace GameUtils;
+
+GameScene::GameScene()
+{
+}
+
+GameScene::~GameScene()
+{
+}
+
+bool GameScene::Load(const char *filename)
+{
+ ByteArray bytes;
+ if( !LoadFile( filename, bytes ) )
+ {
+ return false;
+ }
+
+ // add EOL
+ bytes.push_back( '\0');
+
+ picojson::value root;
+ picojson::parse( root, bytes.data() );
+
+ bool failed( false );
+
+ if( root.is<object>() )
+ {
+ object rootObject = root.get<object>();
+ for( object::iterator it = rootObject.begin(); it != rootObject.end(); ++it )
+ {
+ std::string entityName( (*it).first );
+
+ GameEntity* entity = new GameEntity( entityName.c_str() );
+ mEntities.PushBack( entity );
+
+ value& val( (*it).second );
+ value& vLocation = val.get( "location" );
+ value& vRotation = val.get( "rotation" );
+ value& vScale = val.get( "scale" );
+ value& vSize = val.get( "size" );
+ value& vModel = val.get( "model" );
+ value& vTexture = val.get( "texture" );
+
+ if( !vLocation.is<null>() )
+ {
+ array& location = vLocation.get<array>();
+ entity->SetLocation( Vector3(
+ location.at(0).get<double>(),
+ location.at(1).get<double>(),
+ location.at(2).get<double>()
+ ));
+ }
+
+ if( !vRotation.is<null>() )
+ {
+ array& rotation = vRotation.get<array>();
+ entity->SetRotation( Quaternion( Vector4(
+ -rotation.at(0).get<double>(),
+ rotation.at(1).get<double>(),
+ -rotation.at(2).get<double>(),
+ rotation.at(3).get<double>()
+ )) );
+ }
+
+ if( !vScale.is<null>() )
+ {
+ array& scale = vScale.get<array>();
+ entity->SetScale( Vector3(
+ scale.at(0).get<double>(),
+ scale.at(1).get<double>(),
+ scale.at(2).get<double>()
+ ));
+ }
+
+ if( !vSize.is<null>() )
+ {
+ array& size = vSize.get<array>();
+ entity->SetSize( Vector3(
+ size.at(0).get<double>(),
+ size.at(1).get<double>(),
+ size.at(2).get<double>()
+ ));
+ }
+
+ GameModel* model( NULL );
+ GameTexture* texture( NULL );
+
+ if( !vModel.is<null>() )
+ {
+ std::string& strModel = vModel.get<std::string>();
+ model = GetResource( strModel.c_str(), mModelCache );
+ }
+
+ if( !vTexture.is<null>() )
+ {
+ std::string& strTexture = vTexture.get<std::string>();
+ texture = GetResource( strTexture.c_str(), mTextureCache );
+ }
+
+ if( !model || !texture )
+ {
+ failed = true;
+ break;
+ }
+
+ entity->GetGameRenderer().SetModel( model );
+ entity->GetGameRenderer().SetMainTexture( texture );
+ }
+ }
+
+ if( failed )
+ {
+ return false;
+ }
+
+ // add all to the stage
+ Stage stage = Stage::GetCurrent();
+ mRootActor = Actor::New();
+ mRootActor.SetAnchorPoint( AnchorPoint::CENTER );
+ mRootActor.SetParentOrigin( ParentOrigin::CENTER );
+ stage.GetRootLayer().Add( mRootActor );
+ mRootActor.SetScale( -1.0, 1.0, 1.0 );
+ mRootActor.SetPosition( 0.0, 0.0, 0.0 );
+ mRootActor.SetOrientation( Degree( 90 ), Vector3( 1.0, 0.0, 0.0 ));
+ for( size_t i = 0; i < mEntities.Size(); ++i )
+ {
+ Actor actor( mEntities[i]->GetActor() );
+ actor.SetAnchorPoint( AnchorPoint::CENTER );
+ actor.SetParentOrigin( ParentOrigin::CENTER );
+ mRootActor.Add( actor );
+ mEntities[i]->UpdateRenderer();
+ }
+
+ // update camera
+ mCamera.Initialise( 60.0f, 0.1f, 100.0f );
+
+ return true;
+}
+
+Dali::Actor& GameScene::GetRootActor()
+{
+ return mRootActor;
+}
--- /dev/null
+#ifndef GAME_SCENE_H
+#define GAME_SCENE_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <vector>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "game-container.h"
+#include "game-utils.h"
+#include "game-camera.h"
+
+#include <dali/public-api/actors/actor.h>
+
+class GameCamera;
+class GameEntity;
+class GameTexture;
+class GameModel;
+
+/**
+ * Container based types owning heap allocated data of specifed types
+ */
+typedef GameContainer< GameEntity* > EntityArray;
+typedef GameContainer< GameTexture* > TextureArray;
+typedef GameContainer< GameModel* > ModelArray;
+
+class GameScene
+{
+public:
+
+ /**
+ * Creates an instance of the GameScene
+ */
+ GameScene();
+
+ /**
+ * Destroys an instance of the GameScene
+ */
+ ~GameScene();
+
+ /**
+ * Loads scene from formatted JSON file, returns true on success
+ *
+ * @param[in] filename Path to the scene file
+ * @return true if suceess
+ */
+ bool Load( const char* filename );
+
+ /**
+ * Loads resource ( model or texture ) or gets if from cache if already loaded
+ * @param[in] filename Path to the resource file
+ * @param[in] cache Reference to the cache array to be used
+ * @return Pointer to the resource or NULL otherwise
+ */
+ template <typename T>
+ T* GetResource( const char* filename, GameContainer<T*>& cache );
+
+ /**
+ * Returns scene root actor
+ * @return Parent actor of the whole game scene
+ */
+ Dali::Actor& GetRootActor();
+
+private:
+
+ EntityArray mEntities;
+ GameCamera mCamera;
+
+ // internal scene cache
+ ModelArray mModelCache;
+ TextureArray mTextureCache;
+
+ Dali::Actor mRootActor;
+};
+
+
+template<typename T>
+T* GameScene::GetResource( const char* filename, GameContainer<T*>& cache )
+{
+ std::string path( DEMO_GAME_DIR );
+ path += "/";
+ path += filename;
+
+ uint32_t hash( GameUtils::HashString( path.c_str() ) );
+
+ for( typename GameContainer<T*>::Iterator iter = cache.Begin(); iter != cache.End(); ++iter )
+ {
+ if( (*iter)->GetUniqueId() == hash )
+ {
+ return (*iter);
+ }
+ }
+
+ // load resource
+ T* resource = new T( path.c_str() );
+ if( !resource->IsReady() )
+ {
+ return NULL;
+ }
+
+ cache.PushBack( resource );
+
+ return resource;
+}
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+
+#include "game-texture.h"
+#include "game-utils.h"
+
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+
+GameTexture::GameTexture()
+{
+}
+
+GameTexture::~GameTexture()
+{
+}
+
+GameTexture::GameTexture( const char* filename ) :
+ mUniqueId( 0 )
+{
+ Load( filename );
+}
+
+bool GameTexture::Load( const char* filename )
+{
+ Dali::PixelData pixelData = Dali::Toolkit::SyncImageLoader::Load( filename );
+
+ if( !pixelData )
+ {
+ return false;
+ }
+
+ Dali::Texture texture = Dali::Texture::New( Dali::TextureType::TEXTURE_2D,
+ pixelData.GetPixelFormat(),
+ pixelData.GetWidth(),
+ pixelData.GetHeight() );
+ texture.Upload( pixelData );
+ texture.GenerateMipmaps();
+ Dali::TextureSet textureSet = Dali::TextureSet::New();
+ 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 );
+
+ mTexture = texture;
+ mSampler = sampler;
+ mTextureSet = textureSet;
+
+ mUniqueId = GameUtils::HashString( filename );
+
+ mIsReady = true;
+
+ return true;
+}
+
+Dali::TextureSet& GameTexture::GetTextureSet()
+{
+ return mTextureSet;
+}
+
+uint32_t GameTexture::GetUniqueId()
+{
+ return mUniqueId;
+}
+
+bool GameTexture::IsReady()
+{
+ return mIsReady;
+}
--- /dev/null
+#ifndef GAME_TEXTURE_H
+#define GAME_TEXTURE_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/sampler.h>
+
+#include <inttypes.h>
+
+class GameTexture
+{
+public:
+
+ /**
+ * Creates an instance of the GameTexture
+ */
+ GameTexture();
+
+ /**
+ * Creates an instance of the GameTexture with given filename
+ */
+ GameTexture( const char* filename );
+
+ /**
+ * Destroys an instance of the GameTexture
+ */
+ ~GameTexture();
+
+ /**
+ * @brief Loads texture from file
+ * @return Returns true if success
+ */
+ bool Load( const char* filename );
+
+ /**
+ * Checks status of texture, returns false if failed to load
+ * @return true if texture has been loaded, false otherwise
+ */
+ bool IsReady();
+
+ /**
+ * @brief Returns DALi texture set associated with the GameTexture
+ * @return Initialised TextureSet
+ */
+ Dali::TextureSet& GetTextureSet();
+
+ /**
+ * Returns unique Id of the texture
+ * @return Value of unique Id
+ */
+ uint32_t GetUniqueId();
+
+private:
+
+ Dali::Texture mTexture;
+ Dali::Sampler mSampler;
+ Dali::TextureSet mTextureSet;
+
+ uint32_t mUniqueId;
+
+ bool mIsReady;
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include "game-utils.h"
+
+namespace GameUtils
+{
+bool LoadFile( const char* filename, ByteArray& bytes )
+{
+ FILE* fin = fopen( filename, "rb" );
+ fseek( fin, 0, SEEK_END );
+ bytes.resize( ftell( fin ) );
+ std::fill( bytes.begin(), bytes.end(), 0 );
+ fseek( fin, 0, SEEK_SET );
+ size_t result = fread( bytes.data(), 1, bytes.size(), fin );
+ fclose( fin );
+ return (result != 0);
+}
+
+size_t HashString( const char* str )
+{
+ size_t hash = 5381;
+ int c;
+ while( ( c = *str++ ) )
+ {
+ hash = ((hash << 5) + hash) + c;
+ }
+ return hash;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GAME_UTILS_H
+#define GAME_UTILS_H
+
+#include <vector>
+#include <inttypes.h>
+#include <stdlib.h>
+
+namespace GameUtils
+{
+typedef std::vector<char> ByteArray;
+
+/**
+ * Loads file from the storage and returns byte array
+ */
+bool LoadFile( const char* filename, ByteArray& out );
+
+/**
+ * Computes hash value from string using djb2 algorithm
+ * @return hash value
+ */
+size_t HashString( const char* str );
+}
+
+#endif
+
--- /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
%{dali_app_exe_dir}/*.example
%{dali_app_exe_dir}/dali-builder
%{dali_app_res_dir}/images/*
+%{dali_app_res_dir}/game/*
%{dali_app_res_dir}/videos/*
%{dali_app_res_dir}/models/*
%{dali_app_res_dir}/scripts/*
--- /dev/null
+{
+ "crate.011" : {
+ "uid" : 140636849641992,
+ "location" : [ 2.929080, 32.407696, -0.438286 ],
+ "rotation" : [ -0.000000, -0.000000, 0.210321, 0.977632 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.011.png"
+ },
+ "crate.010" : {
+ "uid" : 140636849640456,
+ "location" : [ 1.141492, 31.771614, -0.438286 ],
+ "rotation" : [ -0.000000, 0.000000, -0.275506, 0.961299 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.010.png"
+ },
+ "crate.009" : {
+ "uid" : 140636847323656,
+ "location" : [ -0.631420, 31.771614, -0.438286 ],
+ "rotation" : [ -0.000000, -0.000000, 0.101605, 0.994825 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.009.png"
+ },
+ "crate.008" : {
+ "uid" : 140636847322120,
+ "location" : [ -3.485219, 30.717421, -0.438286 ],
+ "rotation" : [ -0.000000, -0.000000, 0.651881, 0.758321 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.008.png"
+ },
+ "crate.007" : {
+ "uid" : 140636847320584,
+ "location" : [ -2.265040, 31.771614, -0.438286 ],
+ "rotation" : [ -0.000000, -0.000000, 0.466266, 0.884644 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.007.png"
+ },
+ "crate.006" : {
+ "uid" : 140636847319048,
+ "location" : [ -2.962721, 31.168840, 0.717751 ],
+ "rotation" : [ -0.000000, -0.000000, 0.466266, 0.884644 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.006.png"
+ },
+ "back_wall" : {
+ "uid" : 140636847303688,
+ "location" : [ -0.927336, 23.381512, 4.328736 ],
+ "rotation" : [ -0.000000, 0.000000, -0.000000, 1.000000 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 16.032043, 23.978968, 11.872409 ],
+ "model" : "tile_1.011.mod",
+ "texture" : "lm_back_wall.png"
+ },
+ "side_wall_floor" : {
+ "uid" : 140636849654280,
+ "location" : [ -0.911298, 25.371010, 4.919888 ],
+ "rotation" : [ -0.000000, 0.000000, -0.000000, 1.000000 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 20.064106, 20.000000, 11.872391 ],
+ "model" : "tile_1.010.mod",
+ "texture" : "lm_side_wall_floor.png"
+ },
+ "slope" : {
+ "uid" : 140636849655816,
+ "location" : [ -0.879243, 13.510683, -0.510011 ],
+ "rotation" : [ -0.000000, 0.000000, -0.000000, 1.000000 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 19.999998, 3.720652, 1.012590 ],
+ "model" : "tile_1.009.mod",
+ "texture" : "lm_slope.png"
+ },
+ "left_corridor" : {
+ "uid" : 140636849645064,
+ "location" : [ -12.219622, 24.306738, 2.417727 ],
+ "rotation" : [ -0.061628, 0.061629, -0.704416, 0.704416 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 6.548267, 8.015736, 5.146265 ],
+ "model" : "tile_1.005.mod",
+ "texture" : "lm_left_corridor.png"
+ },
+ "right_corridor" : {
+ "uid" : 140636849652744,
+ "location" : [ 11.361787, 24.607277, 2.269830 ],
+ "rotation" : [ -0.061628, -0.061629, 0.704416, 0.704416 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 6.548267, 8.015736, 5.146265 ],
+ "model" : "tile_1.005.mod",
+ "texture" : "lm_right_corridor.png"
+ },
+ "crate.005" : {
+ "uid" : 140636847317512,
+ "location" : [ 0.990019, 8.702949, 1.887937 ],
+ "rotation" : [ -0.020922, 0.250372, -0.080603, 0.964562 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.005.png"
+ },
+ "crate.004" : {
+ "uid" : 140636847315976,
+ "location" : [ 0.269215, 8.675555, 0.574302 ],
+ "rotation" : [ -0.000000, 0.000000, -0.295460, 0.955355 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.004.png"
+ },
+ "crate.003" : {
+ "uid" : 140636847314440,
+ "location" : [ -1.762900, 0.681778, 1.730339 ],
+ "rotation" : [ -0.000000, -0.000000, 0.055911, 0.998436 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.003.png"
+ },
+ "crate.002" : {
+ "uid" : 140636847312904,
+ "location" : [ -1.762900, 1.603783, 0.574302 ],
+ "rotation" : [ -0.000000, -0.000000, 0.055911, 0.998436 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.002.png"
+ },
+ "crate.001" : {
+ "uid" : 140636847311368,
+ "location" : [ -1.762900, -0.008718, 0.574302 ],
+ "rotation" : [ -0.000000, -0.000000, 0.277257, 0.960796 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 1.156036, 1.156036, 1.156036 ],
+ "model" : "Cube.mod",
+ "texture" : "lm_crate.001.png"
+ },
+ "corridor_1" : {
+ "uid" : 140636847308296,
+ "location" : [ -0.732166, 6.650357, 2.804132 ],
+ "rotation" : [ -0.000000, 0.000000, -0.000000, 1.000000 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 6.548267, 8.015736, 5.146265 ],
+ "model" : "tile_1.005.mod",
+ "texture" : "lm_corridor_1.png"
+ },
+ "corridor_0" : {
+ "uid" : 140636847306760,
+ "location" : [ -0.728281, -1.365378, 2.804132 ],
+ "rotation" : [ -0.000000, 0.000000, -0.000000, 1.000000 ],
+ "scale" : [ 1.000000, 1.000000, 1.000000 ],
+ "size" : [ 6.548267, 8.015736, 5.146265 ],
+ "model" : "tile_1.005.mod",
+ "texture" : "lm_corridor_0.png"
+ }
+}
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "টিল্ট অনুভূতি"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP খেলা"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "Neigungssensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Spiel"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "Tilt Sensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "Tilt Sensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "Sensor de inclinacion"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "Juego FPP"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "Kallistustunnistin"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP peli"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "기울기 센서"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "ചെരിവ് സെൻസർ"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "ٹلٹ سینسر"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP گیم"
msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
msgstr "倾斜传感器"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP遊戲"
#define DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE")
#define DALI_DEMO_STR_TITLE_TEXT_SCROLLING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_TEXT_SCROLLING")
#define DALI_DEMO_STR_TITLE_TILT_SENSOR dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_TILT_SENSOR")
+#define DALI_DEMO_STR_TITLE_FPP_GAME dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_FPP_GAME")
#else // !INTERNATIONALIZATION_ENABLED
#define DALI_DEMO_STR_TITLE_TEXT_SCROLLING "Text Scrolling"
#define DALI_DEMO_STR_TITLE_TILT_SENSOR "Tilt Sensor"
#define DALI_DEMO_STR_TITLE_PROGRESS_BAR "Progress Bar"
+#define DALI_DEMO_STR_TITLE_FPP_GAME "First Person Game"
#endif