From: adam.b Date: Thu, 3 Nov 2016 20:18:03 +0000 (+0000) Subject: Example of First Person 3D game with DALI X-Git-Tag: dali_1.2.16~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;ds=sidebyside;h=d9253e5ef3a09dd18b4e0c59eabc8379d0c8138a;p=platform%2Fcore%2Fuifw%2Fdali-demo.git Example of First Person 3D game with DALI - 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 --- diff --git a/build/tizen/CMakeLists.txt b/build/tizen/CMakeLists.txt index 1f119ad..168d55e 100644 --- a/build/tizen/CMakeLists.txt +++ b/build/tizen/CMakeLists.txt @@ -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 diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index 14e92da..2a03e2a 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -172,4 +172,7 @@ + + + diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp index 8c8142a..c879617 100644 --- a/demo/dali-demo.cpp +++ b/demo/dali-demo.cpp @@ -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 index 0000000..19f3a48 --- /dev/null +++ b/examples/fpp-game/fpp-game-example.cpp @@ -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 + +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 index 0000000..ec97bb8 --- /dev/null +++ b/examples/fpp-game/fpp-game-tutorial-controller.cpp @@ -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 +#include +#include +#include + +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 index 0000000..897a922 --- /dev/null +++ b/examples/fpp-game/fpp-game-tutorial-controller.h @@ -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 +#include +#include +#include +#include + +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 index 0000000..7215c5a --- /dev/null +++ b/examples/fpp-game/game-camera.cpp @@ -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 +#include +#include +#include +#include + +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 index 0000000..f1d6306 --- /dev/null +++ b/examples/fpp-game/game-camera.h @@ -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 +#include +#include + +/** + * @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 index 0000000..d7cc40b --- /dev/null +++ b/examples/fpp-game/game-container.h @@ -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 + + +/** + * 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 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 index 0000000..fed76a1 --- /dev/null +++ b/examples/fpp-game/game-entity.cpp @@ -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 index 0000000..3601bdf --- /dev/null +++ b/examples/fpp-game/game-entity.h @@ -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 + +/** + * @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 index 0000000..3e6a585 --- /dev/null +++ b/examples/fpp-game/game-model.cpp @@ -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( bytes.data() )); + + // expect big-endian + if( MODV_TAG != mHeader.tag ) + { + // jump to little-endian variant + mHeader = *(reinterpret_cast( 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 index 0000000..0c38e0a --- /dev/null +++ b/examples/fpp-game/game-model.h @@ -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 +#include + +#include + +/** + * @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 index 0000000..b578539 --- /dev/null +++ b/examples/fpp-game/game-renderer.cpp @@ -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 + +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 index 0000000..de1222b --- /dev/null +++ b/examples/fpp-game/game-renderer.h @@ -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 + +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 index 0000000..03b8e05 --- /dev/null +++ b/examples/fpp-game/game-scene.cpp @@ -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 +#include + +#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 + +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 rootObject = root.get(); + 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() ) + { + array& location = vLocation.get(); + entity->SetLocation( Vector3( + location.at(0).get(), + location.at(1).get(), + location.at(2).get() + )); + } + + if( !vRotation.is() ) + { + array& rotation = vRotation.get(); + entity->SetRotation( Quaternion( Vector4( + -rotation.at(0).get(), + rotation.at(1).get(), + -rotation.at(2).get(), + rotation.at(3).get() + )) ); + } + + if( !vScale.is() ) + { + array& scale = vScale.get(); + entity->SetScale( Vector3( + scale.at(0).get(), + scale.at(1).get(), + scale.at(2).get() + )); + } + + if( !vSize.is() ) + { + array& size = vSize.get(); + entity->SetSize( Vector3( + size.at(0).get(), + size.at(1).get(), + size.at(2).get() + )); + } + + GameModel* model( NULL ); + GameTexture* texture( NULL ); + + if( !vModel.is() ) + { + std::string& strModel = vModel.get(); + model = GetResource( strModel.c_str(), mModelCache ); + } + + if( !vTexture.is() ) + { + std::string& strTexture = vTexture.get(); + 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 index 0000000..0b0c689 --- /dev/null +++ b/examples/fpp-game/game-scene.h @@ -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 +#include +#include + +#include "game-container.h" +#include "game-utils.h" +#include "game-camera.h" + +#include + +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 + T* GetResource( const char* filename, GameContainer& 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 +T* GameScene::GetResource( const char* filename, GameContainer& cache ) +{ + std::string path( DEMO_GAME_DIR ); + path += "/"; + path += filename; + + uint32_t hash( GameUtils::HashString( path.c_str() ) ); + + for( typename GameContainer::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 index 0000000..ee31c68 --- /dev/null +++ b/examples/fpp-game/game-texture.cpp @@ -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 + +#include "game-texture.h" +#include "game-utils.h" + +#include + +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 index 0000000..78de926 --- /dev/null +++ b/examples/fpp-game/game-texture.h @@ -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 +#include +#include + +#include + +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 index 0000000..12828dd --- /dev/null +++ b/examples/fpp-game/game-utils.cpp @@ -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 +#include + +#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 index 0000000..6d70ff1 --- /dev/null +++ b/examples/fpp-game/game-utils.h @@ -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 +#include +#include + +namespace GameUtils +{ +typedef std::vector 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 index 0000000..c0081e7 --- /dev/null +++ b/examples/fpp-game/third-party/picojson.h @@ -0,0 +1,1086 @@ +/* + * Copyright 2009-2010 Cybozu Labs, Inc. + * Copyright 2011-2014 Kazuho Oku + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef picojson_h +#define picojson_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// for isnan/isinf +#if __cplusplus>=201103L +# include +#else +extern "C" { +# ifdef _MSC_VER +# include +# elif defined(__INTEL_COMPILER) +# include +# else +# include +# endif +} +#endif + +#ifndef PICOJSON_USE_RVALUE_REFERENCE +# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) +# define PICOJSON_USE_RVALUE_REFERENCE 1 +# else +# define PICOJSON_USE_RVALUE_REFERENCE 0 +# endif +#endif//PICOJSON_USE_RVALUE_REFERENCE + + +// experimental support for int64_t (see README.mkdn for detail) +#ifdef PICOJSON_USE_INT64 +# define __STDC_FORMAT_MACROS +# include +# include +#endif + +// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 +#ifndef PICOJSON_USE_LOCALE +# define PICOJSON_USE_LOCALE 1 +#endif +#if PICOJSON_USE_LOCALE +extern "C" { +# include +} +#endif + +#ifndef PICOJSON_ASSERT +# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0) +#endif + +#ifdef _MSC_VER + #define SNPRINTF _snprintf_s + #pragma warning(push) + #pragma warning(disable : 4244) // conversion from int to char + #pragma warning(disable : 4127) // conditional expression is constant + #pragma warning(disable : 4702) // unreachable code +#else + #define SNPRINTF snprintf +#endif + +namespace picojson { + + enum { + null_type, + boolean_type, + number_type, + string_type, + array_type, + object_type +#ifdef PICOJSON_USE_INT64 + , int64_type +#endif + }; + + enum { + INDENT_WIDTH = 2 + }; + + struct null {}; + + class value { + public: + typedef std::vector array; + typedef std::map object; + union _storage { + bool boolean_; + double number_; +#ifdef PICOJSON_USE_INT64 + int64_t int64_; +#endif + std::string* string_; + array* array_; + object* object_; + }; + protected: + int type_; + _storage u_; + public: + value(); + value(int type, bool); + explicit value(bool b); +#ifdef PICOJSON_USE_INT64 + explicit value(int64_t i); +#endif + explicit value(double n); + explicit value(const std::string& s); + explicit value(const array& a); + explicit value(const object& o); + explicit value(const char* s); + value(const char* s, size_t len); + ~value(); + value(const value& x); + value& operator=(const value& x); +#if PICOJSON_USE_RVALUE_REFERENCE + value(value&& x)throw(); + value& operator=(value&& x)throw(); +#endif + void swap(value& x)throw(); + template bool is() const; + template const T& get() const; + template T& get(); + template void set(const T &); +#if PICOJSON_USE_RVALUE_REFERENCE + template void set(T &&); +#endif + bool evaluate_as_boolean() const; + const value& get(size_t idx) const; + const value& get(const std::string& key) const; + value& get(size_t idx); + value& get(const std::string& key); + + bool contains(size_t idx) const; + bool contains(const std::string& key) const; + std::string to_str() const; + template void serialize(Iter os, bool prettify = false) const; + std::string serialize(bool prettify = false) const; + private: + template value(const T*); // intentionally defined to block implicit conversion of pointer to bool + template static void _indent(Iter os, int indent); + template void _serialize(Iter os, int indent) const; + std::string _serialize(int indent) const; + void clear(); + }; + + typedef value::array array; + typedef value::object object; + + inline value::value() : type_(null_type) {} + + inline value::value(int type, bool) : type_(type) { + switch (type) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(boolean_, false); + INIT(number_, 0.0); +#ifdef PICOJSON_USE_INT64 + INIT(int64_, 0); +#endif + INIT(string_, new std::string()); + INIT(array_, new array()); + INIT(object_, new object()); +#undef INIT + default: break; + } + } + + inline value::value(bool b) : type_(boolean_type) { + u_.boolean_ = b; + } + +#ifdef PICOJSON_USE_INT64 + inline value::value(int64_t i) : type_(int64_type) { + u_.int64_ = i; + } +#endif + + inline value::value(double n) : type_(number_type) { + if ( +#ifdef _MSC_VER + ! _finite(n) +#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) + std::isnan(n) || std::isinf(n) +#else + isnan(n) || isinf(n) +#endif + ) { + throw std::overflow_error(""); + } + u_.number_ = n; + } + + inline value::value(const std::string& s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const array& a) : type_(array_type) { + u_.array_ = new array(a); + } + + inline value::value(const object& o) : type_(object_type) { + u_.object_ = new object(o); + } + + inline value::value(const char* s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const char* s, size_t len) : type_(string_type) { + u_.string_ = new std::string(s, len); + } + + inline void value::clear() { + switch (type_) { +#define DEINIT(p) case p##type: delete u_.p; break + DEINIT(string_); + DEINIT(array_); + DEINIT(object_); +#undef DEINIT + default: break; + } + } + + inline value::~value() { + clear(); + } + + inline value::value(const value& x) : type_(x.type_) { + switch (type_) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(string_, new std::string(*x.u_.string_)); + INIT(array_, new array(*x.u_.array_)); + INIT(object_, new object(*x.u_.object_)); +#undef INIT + default: + u_ = x.u_; + break; + } + } + + inline value& value::operator=(const value& x) { + if (this != &x) { + value t(x); + swap(t); + } + return *this; + } + +#if PICOJSON_USE_RVALUE_REFERENCE + inline value::value(value&& x)throw() : type_(null_type) { + swap(x); + } + inline value& value::operator=(value&& x)throw() { + swap(x); + return *this; + } +#endif + inline void value::swap(value& x)throw() { + std::swap(type_, x.type_); + std::swap(u_, x.u_); + } + +#define IS(ctype, jtype) \ + template <> inline bool value::is() const { \ + return type_ == jtype##_type; \ + } + IS(null, null) + IS(bool, boolean) +#ifdef PICOJSON_USE_INT64 + IS(int64_t, int64) +#endif + IS(std::string, string) + IS(array, array) + IS(object, object) +#undef IS + template <> inline bool value::is() const { + return type_ == number_type +#ifdef PICOJSON_USE_INT64 + || type_ == int64_type +#endif + ; + } + +#define GET(ctype, var) \ + template <> inline const ctype& value::get() const { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ + } \ + template <> inline ctype& value::get() { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ + } + GET(bool, u_.boolean_) + GET(std::string, *u_.string_) + GET(array, *u_.array_) + GET(object, *u_.object_) +#ifdef PICOJSON_USE_INT64 + GET(double, (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), u_.number_)) + GET(int64_t, u_.int64_) +#else + GET(double, u_.number_) +#endif +#undef GET + +#define SET(ctype, jtype, setter) \ + template <> inline void value::set(const ctype &_val) { \ + clear(); \ + type_ = jtype##_type; \ + setter \ + } + SET(bool, boolean, u_.boolean_ = _val;) + SET(std::string, string, u_.string_ = new std::string(_val);) + SET(array, array, u_.array_ = new array(_val);) + SET(object, object, u_.object_ = new object(_val);) + SET(double, number, u_.number_ = _val;) +#ifdef PICOJSON_USE_INT64 + SET(int64_t, int64, u_.int64_ = _val;) +#endif +#undef SET + +#if PICOJSON_USE_RVALUE_REFERENCE +#define MOVESET(ctype, jtype, setter) \ + template <> inline void value::set(ctype &&_val) { \ + clear(); \ + type_ = jtype##_type; \ + setter \ + } + MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));) + MOVESET(array, array, u_.array_ = new array(std::move(_val));) + MOVESET(object, object, u_.object_ = new object(std::move(_val));) +#undef MOVESET +#endif + + inline bool value::evaluate_as_boolean() const { + switch (type_) { + case null_type: + return false; + case boolean_type: + return u_.boolean_; + case number_type: + return u_.number_ != 0; +#ifdef PICOJSON_USE_INT64 + case int64_type: + return u_.int64_ != 0; +#endif + case string_type: + return ! u_.string_->empty(); + default: + return true; + } + } + + inline const value& value::get(size_t idx) const { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; + } + + inline value& value::get(size_t idx) { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; + } + + inline const value& value::get(const std::string& key) const { + static value s_null; + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; + } + + inline value& value::get(const std::string& key) { + static value s_null; + PICOJSON_ASSERT(is()); + object::iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; + } + + inline bool value::contains(size_t idx) const { + PICOJSON_ASSERT(is()); + return idx < u_.array_->size(); + } + + inline bool value::contains(const std::string& key) const { + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end(); + } + + inline std::string value::to_str() const { + switch (type_) { + case null_type: return "null"; + case boolean_type: return u_.boolean_ ? "true" : "false"; +#ifdef PICOJSON_USE_INT64 + case int64_type: { + char buf[sizeof("-9223372036854775808")]; + SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); + return buf; + } +#endif + case number_type: { + char buf[256]; + double tmp; + SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); +#if PICOJSON_USE_LOCALE + char *decimal_point = localeconv()->decimal_point; + if (strcmp(decimal_point, ".") != 0) { + size_t decimal_point_len = strlen(decimal_point); + for (char *p = buf; *p != '\0'; ++p) { + if (strncmp(p, decimal_point, decimal_point_len) == 0) { + return std::string(buf, p) + "." + (p + decimal_point_len); + } + } + } +#endif + return buf; + } + case string_type: return *u_.string_; + case array_type: return "array"; + case object_type: return "object"; + default: PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif + } + return std::string(); + } + + template void copy(const std::string& s, Iter oi) { + std::copy(s.begin(), s.end(), oi); + } + + template + struct serialize_str_char { + Iter oi; + void operator()(char c) { + switch (c) { +#define MAP(val, sym) case val: copy(sym, oi); break + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); +#undef MAP + default: + if (static_cast(c) < 0x20 || c == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = c; + } + break; + } + } + }; + + template void serialize_str(const std::string& s, Iter oi) { + *oi++ = '"'; + serialize_str_char process_char = { oi }; + std::for_each(s.begin(), s.end(), process_char); + *oi++ = '"'; + } + + template void value::serialize(Iter oi, bool prettify) const { + return _serialize(oi, prettify ? 0 : -1); + } + + inline std::string value::serialize(bool prettify) const { + return _serialize(prettify ? 0 : -1); + } + + template void value::_indent(Iter oi, int indent) { + *oi++ = '\n'; + for (int i = 0; i < indent * INDENT_WIDTH; ++i) { + *oi++ = ' '; + } + } + + template void value::_serialize(Iter oi, int indent) const { + switch (type_) { + case string_type: + serialize_str(*u_.string_, oi); + break; + case array_type: { + *oi++ = '['; + if (indent != -1) { + ++indent; + } + for (array::const_iterator i = u_.array_->begin(); + i != u_.array_->end(); + ++i) { + if (i != u_.array_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + i->_serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.array_->empty()) { + _indent(oi, indent); + } + } + *oi++ = ']'; + break; + } + case object_type: { + *oi++ = '{'; + if (indent != -1) { + ++indent; + } + for (object::const_iterator i = u_.object_->begin(); + i != u_.object_->end(); + ++i) { + if (i != u_.object_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + serialize_str(i->first, oi); + *oi++ = ':'; + if (indent != -1) { + *oi++ = ' '; + } + i->second._serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.object_->empty()) { + _indent(oi, indent); + } + } + *oi++ = '}'; + break; + } + default: + copy(to_str(), oi); + break; + } + if (indent == 0) { + *oi++ = '\n'; + } + } + + inline std::string value::_serialize(int indent) const { + std::string s; + _serialize(std::back_inserter(s), indent); + return s; + } + + template class input { + protected: + Iter cur_, end_; + bool consumed_; + int line_; + public: + input(const Iter& first, const Iter& last) : cur_(first), end_(last), consumed_(false), line_(1) {} + int getc() { + if (consumed_) { + if (*cur_ == '\n') { + ++line_; + } + ++cur_; + } + if (cur_ == end_) { + consumed_ = false; + return -1; + } + consumed_ = true; + return *cur_ & 0xff; + } + void ungetc() { + consumed_ = false; + } + Iter cur() const { + if (consumed_) { + input *self = const_cast*>(this); + self->consumed_ = false; + ++self->cur_; + } + return cur_; + } + int line() const { return line_; } + void skip_ws() { + while (1) { + int ch = getc(); + if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } + } + } + bool expect(int expect) { + skip_ws(); + if (getc() != expect) { + ungetc(); + return false; + } + return true; + } + bool match(const std::string& pattern) { + for (std::string::const_iterator pi(pattern.begin()); + pi != pattern.end(); + ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } + } + return true; + } + }; + + template inline int _parse_quadhex(input &in) { + int uni_ch = 0, hex; + for (int i = 0; i < 4; i++) { + if ((hex = in.getc()) == -1) { + return -1; + } + if ('0' <= hex && hex <= '9') { + hex -= '0'; + } else if ('A' <= hex && hex <= 'F') { + hex -= 'A' - 0xa; + } else if ('a' <= hex && hex <= 'f') { + hex -= 'a' - 0xa; + } else { + in.ungetc(); + return -1; + } + uni_ch = uni_ch * 16 + hex; + } + return uni_ch; + } + + template inline bool _parse_codepoint(String& out, input& in) { + int uni_ch; + if ((uni_ch = _parse_quadhex(in)) == -1) { + return false; + } + if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { + if (0xdc00 <= uni_ch) { + // a second 16-bit of a surrogate pair appeared + return false; + } + // first 16-bit of surrogate pair, get the next one + if (in.getc() != '\\' || in.getc() != 'u') { + in.ungetc(); + return false; + } + int second = _parse_quadhex(in); + if (! (0xdc00 <= second && second <= 0xdfff)) { + return false; + } + uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); + uni_ch += 0x10000; + } + if (uni_ch < 0x80) { + out.push_back(uni_ch); + } else { + if (uni_ch < 0x800) { + out.push_back(0xc0 | (uni_ch >> 6)); + } else { + if (uni_ch < 0x10000) { + out.push_back(0xe0 | (uni_ch >> 12)); + } else { + out.push_back(0xf0 | (uni_ch >> 18)); + out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); + } + out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); + } + out.push_back(0x80 | (uni_ch & 0x3f)); + } + return true; + } + + template inline bool _parse_string(String& out, input& in) { + while (1) { + int ch = in.getc(); + if (ch < ' ') { + in.ungetc(); + return false; + } else if (ch == '"') { + return true; + } else if (ch == '\\') { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { +#define MAP(sym, val) case sym: out.push_back(val); break + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); +#undef MAP + case 'u': + if (! _parse_codepoint(out, in)) { + return false; + } + break; + default: + return false; + } + } else { + out.push_back(ch); + } + } + return false; + } + + template inline bool _parse_array(Context& ctx, input& in) { + if (! ctx.parse_array_start()) { + return false; + } + size_t idx = 0; + if (in.expect(']')) { + return ctx.parse_array_stop(idx); + } + do { + if (! ctx.parse_array_item(in, idx)) { + return false; + } + idx++; + } while (in.expect(',')); + return in.expect(']') && ctx.parse_array_stop(idx); + } + + template inline bool _parse_object(Context& ctx, input& in) { + if (! ctx.parse_object_start()) { + return false; + } + if (in.expect('}')) { + return true; + } + do { + std::string key; + if (! in.expect('"') + || ! _parse_string(key, in) + || ! in.expect(':')) { + return false; + } + if (! ctx.parse_object_item(in, key)) { + return false; + } + } while (in.expect(',')); + return in.expect('}'); + } + + template inline std::string _parse_number(input& in) { + std::string num_str; + while (1) { + int ch = in.getc(); + if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' + || ch == 'e' || ch == 'E') { + num_str.push_back(ch); + } else if (ch == '.') { +#if PICOJSON_USE_LOCALE + num_str += localeconv()->decimal_point; +#else + num_str.push_back('.'); +#endif + } else { + in.ungetc(); + break; + } + } + return num_str; + } + + template inline bool _parse(Context& ctx, input& in) { + in.skip_ws(); + int ch = in.getc(); + switch (ch) { +#define IS(ch, text, op) case ch: \ + if (in.match(text) && op) { \ + return true; \ + } else { \ + return false; \ + } + IS('n', "ull", ctx.set_null()); + IS('f', "alse", ctx.set_bool(false)); + IS('t', "rue", ctx.set_bool(true)); +#undef IS + case '"': + return ctx.parse_string(in); + case '[': + return _parse_array(ctx, in); + case '{': + return _parse_object(ctx, in); + default: + if (('0' <= ch && ch <= '9') || ch == '-') { + double f; + char *endp; + in.ungetc(); + std::string num_str = _parse_number(in); + if (num_str.empty()) { + return false; + } +#ifdef PICOJSON_USE_INT64 + { + errno = 0; + intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); + if (errno == 0 + && std::numeric_limits::min() <= ival + && ival <= std::numeric_limits::max() + && endp == num_str.c_str() + num_str.size()) { + ctx.set_int64(ival); + return true; + } + } +#endif + f = strtod(num_str.c_str(), &endp); + if (endp == num_str.c_str() + num_str.size()) { + ctx.set_number(f); + return true; + } + return false; + } + break; + } + in.ungetc(); + return false; + } + + class deny_parse_context { + public: + bool set_null() { return false; } + bool set_bool(bool) { return false; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return false; } +#endif + bool set_number(double) { return false; } + template bool parse_string(input&) { return false; } + bool parse_array_start() { return false; } + template bool parse_array_item(input&, size_t) { + return false; + } + bool parse_array_stop(size_t) { return false; } + bool parse_object_start() { return false; } + template bool parse_object_item(input&, const std::string&) { + return false; + } + }; + + class default_parse_context { + protected: + value* out_; + public: + default_parse_context(value* out) : out_(out) {} + bool set_null() { + *out_ = value(); + return true; + } + bool set_bool(bool b) { + *out_ = value(b); + return true; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t i) { + *out_ = value(i); + return true; + } +#endif + bool set_number(double f) { + *out_ = value(f); + return true; + } + template bool parse_string(input& in) { + *out_ = value(string_type, false); + return _parse_string(out_->get(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template bool parse_array_item(input& in, size_t) { + array& a = out_->get(); + a.push_back(value()); + default_parse_context ctx(&a.back()); + return _parse(ctx, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { + *out_ = value(object_type, false); + return true; + } + template bool parse_object_item(input& in, const std::string& key) { + object& o = out_->get(); + default_parse_context ctx(&o[key]); + return _parse(ctx, in); + } + private: + default_parse_context(const default_parse_context&); + default_parse_context& operator=(const default_parse_context&); + }; + + class null_parse_context { + public: + struct dummy_str { + void push_back(int) {} + }; + public: + null_parse_context() {} + bool set_null() { return true; } + bool set_bool(bool) { return true; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return true; } +#endif + bool set_number(double) { return true; } + template bool parse_string(input& in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { return true; } + template bool parse_array_item(input& in, size_t) { + return _parse(*this, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { return true; } + template bool parse_object_item(input& in, const std::string&) { + return _parse(*this, in); + } + private: + null_parse_context(const null_parse_context&); + null_parse_context& operator=(const null_parse_context&); + }; + + // obsolete, use the version below + template inline std::string parse(value& out, Iter& pos, const Iter& last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; + } + + template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { + input in(first, last); + if (! _parse(ctx, in) && err != NULL) { + char buf[64]; + SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); + *err = buf; + while (1) { + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(ch); + } + } + } + return in.cur(); + } + + template inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { + default_parse_context ctx(&out); + return _parse(ctx, first, last, err); + } + + inline std::string parse(value& out, const std::string& s) { + std::string err; + parse(out, s.begin(), s.end(), &err); + return err; + } + + inline std::string parse(value& out, std::istream& is) { + std::string err; + parse(out, std::istreambuf_iterator(is.rdbuf()), + std::istreambuf_iterator(), &err); + return err; + } + + template struct last_error_t { + static std::string s; + }; + template std::string last_error_t::s; + + inline void set_last_error(const std::string& s) { + last_error_t::s = s; + } + + inline const std::string& get_last_error() { + return last_error_t::s; + } + + inline bool operator==(const value& x, const value& y) { + if (x.is()) + return y.is(); +#define PICOJSON_CMP(type) \ + if (x.is()) \ + return y.is() && x.get() == y.get() + PICOJSON_CMP(bool); + PICOJSON_CMP(double); + PICOJSON_CMP(std::string); + PICOJSON_CMP(array); + PICOJSON_CMP(object); +#undef PICOJSON_CMP + PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif + return false; + } + + inline bool operator!=(const value& x, const value& y) { + return ! (x == y); + } +} + +#if !PICOJSON_USE_RVALUE_REFERENCE +namespace std { + template<> inline void swap(picojson::value& x, picojson::value& y) + { + x.swap(y); + } +} +#endif + +inline std::istream& operator>>(std::istream& is, picojson::value& x) +{ + picojson::set_last_error(std::string()); + std::string err = picojson::parse(x, is); + if (! err.empty()) { + picojson::set_last_error(err); + is.setstate(std::ios::failbit); + } + return is; +} + +inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) +{ + x.serialize(std::ostream_iterator(os)); + return os; +} +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/packaging/com.samsung.dali-demo.spec b/packaging/com.samsung.dali-demo.spec index 39a3bf5..f81dea0 100755 --- a/packaging/com.samsung.dali-demo.spec +++ b/packaging/com.samsung.dali-demo.spec @@ -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 index 0000000..2f0b2d5 --- /dev/null +++ b/resources/game/scene.json @@ -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 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 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 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 index 0000000..55efc44 Binary files /dev/null and b/resources/game/tile_1.011.mod differ diff --git a/resources/po/as.po b/resources/po/as.po index fc7c204..d431697 100755 --- a/resources/po/as.po +++ b/resources/po/as.po @@ -144,3 +144,6 @@ msgstr "অকনিষ্ঠ অৰ্জুন বঁটা" msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR" msgstr "টিল্ট অনুভূতি" + +msgid "DALI_DEMO_STR_TITLE_FPP_GAME" +msgstr "FPP খেলা" diff --git a/resources/po/de.po b/resources/po/de.po index 7d3e41c..9ddb8f0 100755 --- a/resources/po/de.po +++ b/resources/po/de.po @@ -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" diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po index e90637b..18f1489 100755 --- a/resources/po/en_GB.po +++ b/resources/po/en_GB.po @@ -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" diff --git a/resources/po/en_US.po b/resources/po/en_US.po index 1d6c984..848950e 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -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" diff --git a/resources/po/es.po b/resources/po/es.po index 1454c50..1f79c61 100755 --- a/resources/po/es.po +++ b/resources/po/es.po @@ -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" diff --git a/resources/po/fi.po b/resources/po/fi.po index dcbfb24..49cf19c 100755 --- a/resources/po/fi.po +++ b/resources/po/fi.po @@ -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" diff --git a/resources/po/ko.po b/resources/po/ko.po index 69775e4..79d388b 100755 --- a/resources/po/ko.po +++ b/resources/po/ko.po @@ -144,3 +144,6 @@ msgstr "텍스트 스크롤" msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR" msgstr "기울기 센서" + +msgid "DALI_DEMO_STR_TITLE_FPP_GAME" +msgstr "FPP Game" diff --git a/resources/po/ml.po b/resources/po/ml.po index 10fd9e3..571fea7 100755 --- a/resources/po/ml.po +++ b/resources/po/ml.po @@ -144,3 +144,6 @@ msgstr "ടെക്സ്റ്റ് സ്ക്രോളിംഗ്" msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR" msgstr "ചെരിവ് സെൻസർ" + +msgid "DALI_DEMO_STR_TITLE_FPP_GAME" +msgstr "FPP Game" diff --git a/resources/po/ur.po b/resources/po/ur.po index 49d552f..61492ce 100755 --- a/resources/po/ur.po +++ b/resources/po/ur.po @@ -144,3 +144,6 @@ msgstr "حروف کاسکرال " msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR" msgstr "ٹلٹ سینسر" + +msgid "DALI_DEMO_STR_TITLE_FPP_GAME" +msgstr "FPP گیم" diff --git a/resources/po/zn_CH.po b/resources/po/zn_CH.po index b268411..edc52ca 100755 --- a/resources/po/zn_CH.po +++ b/resources/po/zn_CH.po @@ -144,3 +144,6 @@ msgstr "滚动文字" msgid "DALI_DEMO_STR_TITLE_TILT_SENSOR" msgstr "倾斜传感器" + +msgid "DALI_DEMO_STR_TITLE_FPP_GAME" +msgstr "FPP遊戲" diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index 750fd84..e782b17 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -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