Example of First Person 3D game with DALI 56/95556/28
authoradam.b <adam.b@samsung.com>
Thu, 3 Nov 2016 20:18:03 +0000 (20:18 +0000)
committeradam.b <adam.b@samsung.com>
Tue, 22 Nov 2016 16:04:05 +0000 (16:04 +0000)
- Features 3D environment with simple lightmapping
- Multi-touch first person camera control scheme
- Uses free textures on the GPL license ( blendernation )
- Models are custom made
- Tutorial screen made using DALi toolkit controls ( text labels ).
- Uses PicoJSON parser ( https://github.com/kazuho/picojson )

Change-Id: I6e3503608cd22dc63f371132376d475c890a0474

58 files changed:
build/tizen/CMakeLists.txt
com.samsung.dali-demo.xml
demo/dali-demo.cpp
examples/fpp-game/fpp-game-example.cpp [new file with mode: 0644]
examples/fpp-game/fpp-game-tutorial-controller.cpp [new file with mode: 0644]
examples/fpp-game/fpp-game-tutorial-controller.h [new file with mode: 0644]
examples/fpp-game/game-camera.cpp [new file with mode: 0644]
examples/fpp-game/game-camera.h [new file with mode: 0644]
examples/fpp-game/game-container.h [new file with mode: 0644]
examples/fpp-game/game-entity.cpp [new file with mode: 0644]
examples/fpp-game/game-entity.h [new file with mode: 0644]
examples/fpp-game/game-model.cpp [new file with mode: 0644]
examples/fpp-game/game-model.h [new file with mode: 0644]
examples/fpp-game/game-renderer.cpp [new file with mode: 0644]
examples/fpp-game/game-renderer.h [new file with mode: 0644]
examples/fpp-game/game-scene.cpp [new file with mode: 0644]
examples/fpp-game/game-scene.h [new file with mode: 0644]
examples/fpp-game/game-texture.cpp [new file with mode: 0644]
examples/fpp-game/game-texture.h [new file with mode: 0644]
examples/fpp-game/game-utils.cpp [new file with mode: 0644]
examples/fpp-game/game-utils.h [new file with mode: 0644]
examples/fpp-game/third-party/picojson.h [new file with mode: 0644]
packaging/com.samsung.dali-demo.spec
resources/game/Cube.mod [new file with mode: 0644]
resources/game/lm_back_wall.png [new file with mode: 0644]
resources/game/lm_corridor_0.png [new file with mode: 0644]
resources/game/lm_corridor_1.png [new file with mode: 0644]
resources/game/lm_crate.001.png [new file with mode: 0644]
resources/game/lm_crate.002.png [new file with mode: 0644]
resources/game/lm_crate.003.png [new file with mode: 0644]
resources/game/lm_crate.004.png [new file with mode: 0644]
resources/game/lm_crate.005.png [new file with mode: 0644]
resources/game/lm_crate.006.png [new file with mode: 0644]
resources/game/lm_crate.007.png [new file with mode: 0644]
resources/game/lm_crate.008.png [new file with mode: 0644]
resources/game/lm_crate.009.png [new file with mode: 0644]
resources/game/lm_crate.010.png [new file with mode: 0644]
resources/game/lm_crate.011.png [new file with mode: 0644]
resources/game/lm_left_corridor.png [new file with mode: 0644]
resources/game/lm_right_corridor.png [new file with mode: 0644]
resources/game/lm_side_wall_floor.png [new file with mode: 0644]
resources/game/lm_slope.png [new file with mode: 0644]
resources/game/scene.json [new file with mode: 0644]
resources/game/tile_1.005.mod [new file with mode: 0644]
resources/game/tile_1.009.mod [new file with mode: 0644]
resources/game/tile_1.010.mod [new file with mode: 0644]
resources/game/tile_1.011.mod [new file with mode: 0644]
resources/po/as.po
resources/po/de.po
resources/po/en_GB.po
resources/po/en_US.po
resources/po/es.po
resources/po/fi.po
resources/po/ko.po
resources/po/ml.po
resources/po/ur.po
resources/po/zn_CH.po
shared/dali-demo-strings.h

index 1f119ad..168d55e 100644 (file)
@@ -29,6 +29,7 @@ ENDIF()
 
 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)
@@ -37,6 +38,7 @@ IF(NOT DEFINED LOCAL_STYLE_DIR)
 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/)
@@ -46,6 +48,7 @@ IF(NOT DEFINED LOCALE_DIR)
         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}\\")
@@ -88,6 +91,11 @@ FOREACH(flag ${LOCAL_SCRIPTS_LIST})
         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 )
 
@@ -122,7 +130,7 @@ FOREACH(flag ${REQUIRED_PKGS_CFLAGS})
         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
index 14e92da..2a03e2a 100644 (file)
        <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>
index 8c8142a..c879617 100644 (file)
@@ -84,6 +84,7 @@ int DALI_EXPORT_API main(int argc, char **argv)
   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 );
 
diff --git a/examples/fpp-game/fpp-game-example.cpp b/examples/fpp-game/fpp-game-example.cpp
new file mode 100644 (file)
index 0000000..19f3a48
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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;
+}
diff --git a/examples/fpp-game/fpp-game-tutorial-controller.cpp b/examples/fpp-game/fpp-game-tutorial-controller.cpp
new file mode 100644 (file)
index 0000000..ec97bb8
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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 );
+}
+
diff --git a/examples/fpp-game/fpp-game-tutorial-controller.h b/examples/fpp-game/fpp-game-tutorial-controller.h
new file mode 100644 (file)
index 0000000..897a922
--- /dev/null
@@ -0,0 +1,75 @@
+#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
diff --git a/examples/fpp-game/game-camera.cpp b/examples/fpp-game/game-camera.cpp
new file mode 100644 (file)
index 0000000..7215c5a
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * 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;
+}
diff --git a/examples/fpp-game/game-camera.h b/examples/fpp-game/game-camera.h
new file mode 100644 (file)
index 0000000..f1d6306
--- /dev/null
@@ -0,0 +1,122 @@
+#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
diff --git a/examples/fpp-game/game-container.h b/examples/fpp-game/game-container.h
new file mode 100644 (file)
index 0000000..d7cc40b
--- /dev/null
@@ -0,0 +1,82 @@
+#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
diff --git a/examples/fpp-game/game-entity.cpp b/examples/fpp-game/game-entity.cpp
new file mode 100644 (file)
index 0000000..fed76a1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 );
+}
diff --git a/examples/fpp-game/game-entity.h b/examples/fpp-game/game-entity.h
new file mode 100644 (file)
index 0000000..3601bdf
--- /dev/null
@@ -0,0 +1,92 @@
+#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
diff --git a/examples/fpp-game/game-model.cpp b/examples/fpp-game/game-model.cpp
new file mode 100644 (file)
index 0000000..3e6a585
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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;
+}
diff --git a/examples/fpp-game/game-model.h b/examples/fpp-game/game-model.h
new file mode 100644 (file)
index 0000000..0c38e0a
--- /dev/null
@@ -0,0 +1,96 @@
+#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
diff --git a/examples/fpp-game/game-renderer.cpp b/examples/fpp-game/game-renderer.cpp
new file mode 100644 (file)
index 0000000..b578539
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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;
+}
+
+
+
diff --git a/examples/fpp-game/game-renderer.h b/examples/fpp-game/game-renderer.h
new file mode 100644 (file)
index 0000000..de1222b
--- /dev/null
@@ -0,0 +1,78 @@
+#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
diff --git a/examples/fpp-game/game-scene.cpp b/examples/fpp-game/game-scene.cpp
new file mode 100644 (file)
index 0000000..03b8e05
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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;
+}
diff --git a/examples/fpp-game/game-scene.h b/examples/fpp-game/game-scene.h
new file mode 100644 (file)
index 0000000..0b0c689
--- /dev/null
@@ -0,0 +1,123 @@
+#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
diff --git a/examples/fpp-game/game-texture.cpp b/examples/fpp-game/game-texture.cpp
new file mode 100644 (file)
index 0000000..ee31c68
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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;
+}
diff --git a/examples/fpp-game/game-texture.h b/examples/fpp-game/game-texture.h
new file mode 100644 (file)
index 0000000..78de926
--- /dev/null
@@ -0,0 +1,81 @@
+#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
diff --git a/examples/fpp-game/game-utils.cpp b/examples/fpp-game/game-utils.cpp
new file mode 100644 (file)
index 0000000..12828dd
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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;
+}
+
+}
diff --git a/examples/fpp-game/game-utils.h b/examples/fpp-game/game-utils.h
new file mode 100644 (file)
index 0000000..6d70ff1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
+
diff --git a/examples/fpp-game/third-party/picojson.h b/examples/fpp-game/third-party/picojson.h
new file mode 100644 (file)
index 0000000..c0081e7
--- /dev/null
@@ -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 <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
index 39a3bf5..f81dea0 100755 (executable)
@@ -137,6 +137,7 @@ exit 0
 %{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/*
diff --git a/resources/game/Cube.mod b/resources/game/Cube.mod
new file mode 100644 (file)
index 0000000..ccba5e7
Binary files /dev/null and b/resources/game/Cube.mod differ
diff --git a/resources/game/lm_back_wall.png b/resources/game/lm_back_wall.png
new file mode 100644 (file)
index 0000000..7342ba6
Binary files /dev/null and b/resources/game/lm_back_wall.png differ
diff --git a/resources/game/lm_corridor_0.png b/resources/game/lm_corridor_0.png
new file mode 100644 (file)
index 0000000..98f37f0
Binary files /dev/null and b/resources/game/lm_corridor_0.png differ
diff --git a/resources/game/lm_corridor_1.png b/resources/game/lm_corridor_1.png
new file mode 100644 (file)
index 0000000..f3e89f7
Binary files /dev/null and b/resources/game/lm_corridor_1.png differ
diff --git a/resources/game/lm_crate.001.png b/resources/game/lm_crate.001.png
new file mode 100644 (file)
index 0000000..146dfe2
Binary files /dev/null and b/resources/game/lm_crate.001.png differ
diff --git a/resources/game/lm_crate.002.png b/resources/game/lm_crate.002.png
new file mode 100644 (file)
index 0000000..3f80497
Binary files /dev/null and b/resources/game/lm_crate.002.png differ
diff --git a/resources/game/lm_crate.003.png b/resources/game/lm_crate.003.png
new file mode 100644 (file)
index 0000000..6c7fb29
Binary files /dev/null and b/resources/game/lm_crate.003.png differ
diff --git a/resources/game/lm_crate.004.png b/resources/game/lm_crate.004.png
new file mode 100644 (file)
index 0000000..cfd845f
Binary files /dev/null and b/resources/game/lm_crate.004.png differ
diff --git a/resources/game/lm_crate.005.png b/resources/game/lm_crate.005.png
new file mode 100644 (file)
index 0000000..69dd2a0
Binary files /dev/null and b/resources/game/lm_crate.005.png differ
diff --git a/resources/game/lm_crate.006.png b/resources/game/lm_crate.006.png
new file mode 100644 (file)
index 0000000..c5e42de
Binary files /dev/null and b/resources/game/lm_crate.006.png differ
diff --git a/resources/game/lm_crate.007.png b/resources/game/lm_crate.007.png
new file mode 100644 (file)
index 0000000..e87d584
Binary files /dev/null and b/resources/game/lm_crate.007.png differ
diff --git a/resources/game/lm_crate.008.png b/resources/game/lm_crate.008.png
new file mode 100644 (file)
index 0000000..bf66627
Binary files /dev/null and b/resources/game/lm_crate.008.png differ
diff --git a/resources/game/lm_crate.009.png b/resources/game/lm_crate.009.png
new file mode 100644 (file)
index 0000000..f1c6131
Binary files /dev/null and b/resources/game/lm_crate.009.png differ
diff --git a/resources/game/lm_crate.010.png b/resources/game/lm_crate.010.png
new file mode 100644 (file)
index 0000000..d185de4
Binary files /dev/null and b/resources/game/lm_crate.010.png differ
diff --git a/resources/game/lm_crate.011.png b/resources/game/lm_crate.011.png
new file mode 100644 (file)
index 0000000..708590a
Binary files /dev/null and b/resources/game/lm_crate.011.png differ
diff --git a/resources/game/lm_left_corridor.png b/resources/game/lm_left_corridor.png
new file mode 100644 (file)
index 0000000..e83ac9c
Binary files /dev/null and b/resources/game/lm_left_corridor.png differ
diff --git a/resources/game/lm_right_corridor.png b/resources/game/lm_right_corridor.png
new file mode 100644 (file)
index 0000000..2d4d175
Binary files /dev/null and b/resources/game/lm_right_corridor.png differ
diff --git a/resources/game/lm_side_wall_floor.png b/resources/game/lm_side_wall_floor.png
new file mode 100644 (file)
index 0000000..ed7901d
Binary files /dev/null and b/resources/game/lm_side_wall_floor.png differ
diff --git a/resources/game/lm_slope.png b/resources/game/lm_slope.png
new file mode 100644 (file)
index 0000000..3e0c679
Binary files /dev/null and b/resources/game/lm_slope.png differ
diff --git a/resources/game/scene.json b/resources/game/scene.json
new file mode 100644 (file)
index 0000000..2f0b2d5
--- /dev/null
@@ -0,0 +1,164 @@
+{
+  "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"
+  }
+}
diff --git a/resources/game/tile_1.005.mod b/resources/game/tile_1.005.mod
new file mode 100644 (file)
index 0000000..c7e5f8e
Binary files /dev/null and b/resources/game/tile_1.005.mod differ
diff --git a/resources/game/tile_1.009.mod b/resources/game/tile_1.009.mod
new file mode 100644 (file)
index 0000000..2144893
Binary files /dev/null and b/resources/game/tile_1.009.mod differ
diff --git a/resources/game/tile_1.010.mod b/resources/game/tile_1.010.mod
new file mode 100644 (file)
index 0000000..d1c6d72
Binary files /dev/null and b/resources/game/tile_1.010.mod differ
diff --git a/resources/game/tile_1.011.mod b/resources/game/tile_1.011.mod
new file mode 100644 (file)
index 0000000..55efc44
Binary files /dev/null and b/resources/game/tile_1.011.mod differ
index fc7c204..d431697 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "অকনিষ্ঠ অৰ্জুন বঁটা"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "টিল্ট অনুভূতি"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP খেলা"
index 7d3e41c..9ddb8f0 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "Text Scrollen"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "Neigungssensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Spiel"
index e90637b..18f1489 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "Text Scrolling"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "Tilt Sensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
index 1d6c984..848950e 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "Text Scrolling"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "Tilt Sensor"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
index 1454c50..1f79c61 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "Texto con desplazamiento"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "Sensor de inclinacion"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "Juego FPP"
index dcbfb24..49cf19c 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "Tekstin Vieritys"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "Kallistustunnistin"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP peli"
index 69775e4..79d388b 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "텍스트 스크롤"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "기울기 센서"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
index 10fd9e3..571fea7 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "ടെക്സ്റ്റ് സ്ക്രോളിംഗ്"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "ചെരിവ് സെൻസർ"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP Game"
index 49d552f..61492ce 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "حروف کاسکرال "
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "ٹلٹ سینسر"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP گیم"
index b268411..edc52ca 100755 (executable)
@@ -144,3 +144,6 @@ msgstr "滚动文字"
 
 msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR"
 msgstr "倾斜传感器"
+
+msgid "DALI_DEMO_STR_TITLE_FPP_GAME"
+msgstr "FPP遊戲"
index 750fd84..e782b17 100644 (file)
@@ -80,6 +80,7 @@ extern "C"
 #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
 
@@ -131,6 +132,7 @@ extern "C"
 #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