include/cinder/app/App.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2012, The Cinder Project, All rights reserved.
00003 
00004  This code is intended for use with the Cinder C++ library: http://libcinder.org
00005 
00006  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00007  the following conditions are met:
00008 
00009     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00010     the following disclaimer.
00011     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00012     the following disclaimer in the documentation and/or other materials provided with the distribution.
00013 
00014  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00015  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00016  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00017  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00018  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00019  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00020  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00021  POSSIBILITY OF SUCH DAMAGE.
00022 */
00023 
00024 #pragma once
00025 
00026 #include "cinder/Cinder.h"
00027 #include "cinder/app/Renderer.h"
00028 #include "cinder/app/Window.h"
00029 #include "cinder/Vector.h"
00030 #include "cinder/app/MouseEvent.h"
00031 #include "cinder/app/KeyEvent.h"
00032 #include "cinder/app/FileDropEvent.h"
00033 #include "cinder/Display.h"
00034 #include "cinder/DataSource.h"
00035 #include "cinder/Timer.h"
00036 #include "cinder/Function.h"
00037 #include "cinder/Thread.h"
00038 #if defined( CINDER_COCOA )
00039     #if defined( CINDER_COCOA_TOUCH )
00040         #if defined( __OBJC__ )
00041             #import <UIKit/UIKit.h>
00042             #import <CoreFoundation/CoreFoundation.h>
00043         #endif
00044     #else
00045         #include <ApplicationServices/ApplicationServices.h>
00046     #endif
00047     #if defined __OBJC__
00048         @class CinderView;
00049         @class NSBundle;
00050     #else
00051         class NSBundle;
00052     #endif
00053 //  class CinderView;
00054 #elif defined( CINDER_MSW )
00055     #include "cinder/msw/OutputDebugStringStream.h"
00056 #endif
00057 
00058 #include <vector>
00059 #include <algorithm>
00060 
00061 namespace cinder {
00062 class Timeline;
00063 } // namespace cinder
00064 
00065 namespace boost { namespace asio {
00066 class io_service;
00067 } } // namespace boost::asio
00068 
00069 namespace cinder { namespace app { 
00070 
00071 
00073 struct BooleanOrEventCombiner {
00074     typedef bool    result_type;
00075 
00076     template<typename InputIterator>
00077     bool    operator()( InputIterator first, InputIterator last ) const
00078     {
00079         bool handled = ( first == last ) ? true : false;
00080         while( first != last )
00081             handled = *first++ || handled;
00082         
00083         return handled;
00084     }
00085 };
00086 
00088 struct BooleanAndEventCombiner {
00089     typedef bool    result_type;
00090 
00091     template<typename InputIterator>
00092     bool    operator()( InputIterator first, InputIterator last ) const
00093     {
00094         bool result = true;
00095         while( first != last )
00096             result = *first++ && result;
00097         
00098         return result;
00099     }
00100 };
00101 
00103 template<typename T>
00104 struct BitwiseAndEventCombiner {
00105     typedef T   result_type;
00106 
00107     template<typename InputIterator>
00108     T   operator()( InputIterator first, InputIterator last ) const
00109     {
00110         if( first == last )
00111             return 0;
00112         T mask = *first++;
00113         while( first != last )
00114             mask &= *first++;
00115 
00116         return mask;
00117     }
00118 };
00119 
00120 class App {
00121  public:
00122     class Settings {
00123       public:
00124         // whether or not the app should terminate prior to launching
00125         bool    isPrepared() const { return ! mShouldQuit; };
00126 
00128         void    setWindowSize( int windowSizeX, int windowSizeY ) { mDefaultWindowFormat.setSize( Vec2i( windowSizeX, windowSizeY ) ); }
00130         void    setWindowSize( const Vec2i &size ) { mDefaultWindowFormat.setSize( size ); }
00132         Vec2i   getWindowSize() const { return mDefaultWindowFormat.getSize(); }
00133         
00135         Vec2i   getWindowPos() const { return mDefaultWindowFormat.getPos(); }
00137         void    setWindowPos( int windowPosX, int windowPosY ) { mDefaultWindowFormat.setPos( Vec2i( windowPosX, windowPosY ) ); }
00139         void    setWindowPos( const Vec2i &windowPos ) { mDefaultWindowFormat.setPos( windowPos ); }
00141         bool    isWindowPosSpecified() const { return mDefaultWindowFormat.isPosSpecified(); }
00143         void    unspecifyWindowPos() { mDefaultWindowFormat.unspecifyPos(); }
00144 
00146         bool    isFullScreen() { return mDefaultWindowFormat.isFullScreen(); }
00148         void    setFullScreen( bool fullScreen = true, const FullScreenOptions &options = FullScreenOptions() ) { mDefaultWindowFormat.setFullScreen( fullScreen, options ); }
00149 
00151         bool    isResizable() const { return mDefaultWindowFormat.isResizable(); }
00153         void    setResizable( bool resizable = true ) { mDefaultWindowFormat.setResizable( resizable ); }
00155         bool    isBorderless() const { return mDefaultWindowFormat.isBorderless(); }
00157         void    setBorderless( bool borderless = true ) { mDefaultWindowFormat.setBorderless( borderless ); }
00159         bool    isAlwaysOnTop() const { return mDefaultWindowFormat.isAlwaysOnTop(); }
00161         void    setAlwaysOnTop( bool alwaysOnTop = true ) { mDefaultWindowFormat.setAlwaysOnTop( alwaysOnTop ); }
00162 
00164         DisplayRef  getDisplay() const { return mDefaultWindowFormat.getDisplay(); }
00166         void        setDisplay( DisplayRef display ) { mDefaultWindowFormat.setDisplay( display ); }
00167 
00168         void        prepareWindow( const Window::Format &format );
00169         std::vector<Window::Format>&        getWindowFormats() { return mWindowFormats; }
00170         const std::vector<Window::Format>&  getWindowFormats() const { return mWindowFormats; }\
00171 
00173         void        enableHighDensityDisplay( bool enable = true ) { mEnableHighDensityDisplay = enable; }
00175         bool        isHighDensityDisplayEnabled() const { return mEnableHighDensityDisplay; }
00176 
00178         Window::Format      getDefaultWindowFormat() const { return mDefaultWindowFormat; }
00180         void                setDefaultWindowFormat( const Window::Format &format ) { mDefaultWindowFormat = format; }
00181 
00183         void        enableMultiTouch( bool enable = true ) { mEnableMultiTouch = enable; }
00185         bool        isMultiTouchEnabled() const { return mEnableMultiTouch; }
00186 
00188         void    enablePowerManagement( bool aPowerManagement = true );
00190         bool    isPowerManagementEnabled() const { return mPowerManagement; }
00191 
00193         const std::string&  getTitle() const { return mTitle; }
00195         void                setTitle( const std::string &title ) { mTitle = title; }
00196 
00198         void    setFrameRate( float frameRate );
00200         void    disableFrameRate();
00202         bool    isFrameRateEnabled() const { return mFrameRateEnabled; }
00204         float   getFrameRate() const { return mFrameRate; }
00205         
00206         Settings();
00207         virtual ~Settings() {}    
00208 
00209       protected:
00210         bool            mShouldQuit; // defaults to false, facilitates early termination
00211 
00212         // A vector of Windows which have been requested using prepareWindow. An empty vector implies defaults.
00213         std::vector<Window::Format>     mWindowFormats;
00214         // The Window format which will be used if prepareWindow is not called
00215         Window::Format                  mDefaultWindowFormat;
00216             
00217         bool            mFrameRateEnabled;
00218         float           mFrameRate;
00219         bool            mPowerManagement; // allow screensavers or power management to hide app. default: false
00220         bool            mEnableHighDensityDisplay;
00221         bool            mEnableMultiTouch;
00222         std::string     mTitle;
00223         
00224         friend class App;
00225     };
00226 
00227 
00228  public:
00229     // interface
00230     App();
00231     virtual ~App();
00232 
00234     virtual void    setup() {}
00236     virtual void    shutdown() {}
00237 
00239     virtual void    update() {}
00241     virtual void    draw() {}
00242     
00244     virtual void    mouseDown( MouseEvent event ) {}
00246     virtual void    mouseUp( MouseEvent event ) {}  
00248     virtual void    mouseWheel( MouseEvent event ) {}
00250     virtual void    mouseMove( MouseEvent event ) {}
00252     virtual void    mouseDrag( MouseEvent event ) {}    
00253 
00255     virtual void    touchesBegan( TouchEvent event ) {}
00257     virtual void    touchesMoved( TouchEvent event ) {}
00259     virtual void    touchesEnded( TouchEvent event ) {}
00260     
00262     virtual void    keyDown( KeyEvent event ) {}
00264     virtual void    keyUp( KeyEvent event ) {}
00266     virtual void    resize() {}
00268     virtual void    fileDrop( FileDropEvent event ) {}
00269     
00271     virtual void    quit() = 0;
00272 
00274     signals::signal<void()>&    getSignalUpdate() { return mSignalUpdate; }
00275 
00277     signals::signal<void()>&    getSignalShutdown() { return mSignalShutdown; }
00278     void                        emitShutdown();
00279 
00280     const std::vector<TouchEvent::Touch>&   getActiveTouches() const { return getWindow()->getActiveTouches(); }
00281 
00282     // Accessors
00283     virtual const Settings& getSettings() const = 0;
00285     RendererRef         getRenderer() const { return getWindow()->getRenderer(); }
00287     DisplayRef          getDisplay() const { return getWindow()->getDisplay(); }
00288 
00290     virtual WindowRef   getWindow() const = 0;
00292     virtual size_t      getNumWindows() const = 0;
00294     virtual WindowRef   getWindowIndex( size_t index ) const = 0;
00295 
00297     virtual void    enablePowerManagement( bool powerManagement = true ) { mPowerManagement = powerManagement; }
00299     virtual bool    isPowerManagementEnabled() const { return mPowerManagement; }
00300     
00302     int                 getWindowWidth() const { return getWindow()->getWidth(); }
00304     int                 getWindowHeight() const { return getWindow()->getHeight(); }
00306     void                setWindowSize( int windowWidth, int windowHeight ) { setWindowSize( Vec2i( windowWidth, windowHeight ) ); }
00308     void                setWindowSize( const Vec2i &size ) { getWindow()->setSize( size ); }
00310 
00311     Vec2f               getWindowCenter() const { return Vec2f( (float)getWindowWidth(), (float)getWindowHeight() ) * 0.5f; }
00313     Vec2i               getWindowSize() const { return Vec2i( getWindowWidth(), getWindowHeight() ); }
00315     float               getWindowAspectRatio() const { return getWindowWidth() / (float)getWindowHeight(); }
00317 
00318     Area                getWindowBounds() const { return Area( 0, 0, getWindowWidth(), getWindowHeight() ); }
00320     float               getWindowContentScale() const { return getWindow()->getContentScale(); }
00321     
00323     Vec2i               getWindowPos() const { return getWindow()->getPos(); }
00325     int                 getWindowPosX() const { return getWindow()->getPos().x; }
00327     int                 getWindowPosY() const { return getWindow()->getPos().y; }
00329     void                setWindowPos( int x, int y ) { setWindowPos( Vec2i( x, y ) ); }
00331     virtual void        setWindowPos( const Vec2i &windowPos ) { getWindow()->setPos( windowPos ); }
00332     
00334     virtual float       getFrameRate() const = 0;
00336     virtual void        setFrameRate( float frameRate ) = 0;
00338     float               getAverageFps() const { return mAverageFps; }
00340     double              getFpsSampleInterval() const { return mFpsSampleInterval; }
00342     void                setFpsSampleInterval( double sampleInterval ) { mFpsSampleInterval = sampleInterval; }  
00343 
00345     bool                isFullScreen() const { return getWindow()->isFullScreen(); }
00347     void                setFullScreen( bool aFullScreen, const FullScreenOptions &options = FullScreenOptions() ) { getWindow()->setFullScreen( aFullScreen, options ); }
00348 
00350     double              getElapsedSeconds() const { return mTimer.getSeconds(); }
00352     uint32_t            getElapsedFrames() const { return mFrameCount; }
00353 
00355     static Vec2i        getMousePos();
00356     
00357     // utilities
00359     static DataSourceRef        loadResource( const std::string &macPath, int mswID, const std::string &mswType );
00360 #if defined( CINDER_COCOA )
00361 
00362     static DataSourceRef        loadResource( const std::string &macPath );
00364     static fs::path             getResourcePath( const fs::path &rsrcRelativePath );
00366     static fs::path             getResourcePath();
00367 #else
00368 
00369     static DataSourceRef        loadResource( int mswID, const std::string &mswType );
00370 #endif
00371     
00373     DataSourceRef           loadAsset( const fs::path &relativePath );
00375     fs::path                getAssetPath( const fs::path &relativePath );
00377     void                    addAssetDirectory( const fs::path &dirPath );
00378     
00380     virtual fs::path            getAppPath() const = 0;
00381 #if defined( CINDER_COCOA )
00382 
00383     virtual NSBundle*           getBundle() const;
00384 #endif
00385 
00386 
00389     fs::path        getOpenFilePath( const fs::path &initialPath = "", std::vector<std::string> extensions = std::vector<std::string>() );
00391     fs::path        getFolderPath(const fs::path &initialPath="");
00393 
00396     fs::path        getSaveFilePath( const fs::path &initialPath = "", std::vector<std::string> extensions = std::vector<std::string>() );
00397 
00399     std::ostream&   console();
00400     
00402     Timeline&       timeline() { return *mTimeline; }
00403 
00405     static bool     isPrimaryThread();
00406 
00408     boost::asio::io_service&    io_service() { return *mIo; }
00409     
00410     
00411     
00413     void    dispatchAsync( const std::function<void()> &fn );
00414     
00415     template<typename T>
00416     typename std::result_of<T()>::type dispatchSync( T fn )
00417     {
00418         if( isPrimaryThread() )
00419             return fn();
00420         else {
00421             typedef typename std::result_of<T()>::type result_type;
00422 #if defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) // slightly different signature with Boost.Thread
00423             std::packaged_task<result_type> task( std::move(fn) );
00424 #else
00425             std::packaged_task<result_type()> task( std::move(fn) );
00426 #endif
00427             auto fute = task.get_future();
00428             dispatchAsync( [&task]() { task(); } );
00429             return fute.get();
00430         }
00431     }
00432 
00434     RendererRef getDefaultRenderer() const { return mDefaultRenderer; }
00436     Surface copyWindowSurface();
00438     Surface copyWindowSurface( const Area &area );
00440     void    restoreWindowContext();
00441 
00443     RendererRef     findSharedRenderer( RendererRef searchRenderer ) const;
00444     
00445     // DO NOT CALL - should be private but aren't for esoteric reasons
00447     // Internal handlers - these are called into by AppImpl's. If you are calling one of these, you have likely strayed far off the path.
00448     virtual void    privateSetup__();
00449     virtual void    privateUpdate__();
00451 
00452 #if defined( CINDER_MSW )
00453     // Not all Windows target types receive paint events, and the AppImplMswRenderer* needs to know that.
00454     virtual bool        getsWindowsPaintEvents() = 0;
00455 #endif
00456 
00457     virtual bool        receivesEvents() const { return true; }
00458 
00460     static App*         get() { return sInstance; }
00461 
00462   protected:
00464     // These are called by application instantation macros and are only used in the launch process
00465     static void     prepareLaunch();
00466     static void     executeLaunch( App *app, RendererRef defaultRenderer, const char *title, int argc, char * const argv[] );
00467     static void     cleanupLaunch();
00468     
00469     virtual void    launch( const char *title, int argc, char * const argv[] ) = 0;
00470     
00472 
00473 #if defined( CINDER_MSW )
00474     friend class AppImplMsw;
00475     std::shared_ptr<std::ostream>   mOutputStream;
00476 #endif
00477 
00478   private:
00479       void      prepareAssetLoading();
00480       fs::path  findAssetPath( const fs::path &relativePath );
00481   
00482 #if defined( CINDER_COCOA )
00483     static void             *sAutoReleasePool;
00484 #endif
00485 
00486     Timer                   mTimer;
00487     uint32_t                mFrameCount;
00488     float                   mAverageFps;
00489     uint32_t                mFpsLastSampleFrame;
00490     double                  mFpsLastSampleTime;
00491     double                  mFpsSampleInterval;
00492 
00493     std::shared_ptr<Timeline>   mTimeline;
00494 
00495     signals::signal<void()>     mSignalUpdate, mSignalShutdown;
00496     
00497     std::shared_ptr<boost::asio::io_service>    mIo;
00498     std::shared_ptr<void>                       mIoWork; // boost::asio::io_service::work, but can't fwd declare member class
00499     
00500     // have we already setup the default path to assets?
00501     bool                        mAssetDirectoriesInitialized;
00502     // Path to directories which contain assets
00503     std::vector<fs::path>       mAssetDirectories;
00504     
00505   protected:
00506     static App*                 sInstance;
00507     RendererRef                 mDefaultRenderer;
00508     bool                        mPowerManagement;
00509 };
00510 
00515 inline WindowRef    getWindow() { return App::get()->getWindow(); }
00517 inline size_t       getNumWindows() { return App::get()->getNumWindows(); }
00519 inline WindowRef    getWindowIndex( size_t index ) { return App::get()->getWindowIndex( index ); }
00520 
00522 inline int  getWindowWidth() { return App::get()->getWindowWidth(); }
00524 inline void     setWindowPos( const Vec2i &windowPos ) { App::get()->setWindowPos( windowPos);  }
00526 inline void     setWindowPos( int x, int y ) { setWindowPos( Vec2i( x, y ) );  }
00528 inline int  getWindowHeight() { return App::get()->getWindowHeight(); }
00530 inline void     setWindowSize( int windowWidth, int windowHeight ) { App::get()->setWindowSize( windowWidth, windowHeight ); }
00532 
00533 inline Vec2f    getWindowCenter() { return App::get()->getWindowCenter(); }
00535 inline Vec2i    getWindowSize() { return App::get()->getWindowSize(); }
00537 inline Vec2i    getWindowPos() { return App::get()->getWindowPos(); }
00539 inline float    getWindowAspectRatio() { return App::get()->getWindowAspectRatio(); }
00541 
00542 inline Area     getWindowBounds() { return App::get()->getWindowBounds(); }
00544 inline float    getWindowContentScale() { return App::get()->getWindowContentScale(); }
00546 inline float    getFrameRate() { return App::get()->getFrameRate(); }
00548 inline void     setFrameRate( float frameRate ) { App::get()->setFrameRate( frameRate ); }
00550 inline bool     isFullScreen() { return App::get()->isFullScreen(); }
00552 inline void     setFullScreen( bool fullScreen = true ) { App::get()->setFullScreen( fullScreen ); }
00553 
00555 inline float    toPixels( float s ) { return getWindow()->toPixels( s ); }
00557 inline Vec2f    toPixels( Vec2f s ) { return getWindow()->toPixels( s ); }
00559 inline  Vec2i   toPixels( Vec2i s ) { return app::getWindow()->toPixels( s ); }
00561 inline  Area    toPixels( const Area &a ) { return getWindow()->toPixels( a ); }
00563 inline  Rectf   toPixels( const Rectf &a ) { return getWindow()->toPixels( a ); }
00565 inline  float   toPoints( float s ) { return getWindow()->toPoints( s ); }
00567 inline  Vec2f   toPoints( Vec2f s ) { return getWindow()->toPoints( s ); }
00569 inline  Vec2i   toPoints( Vec2i s ) { return getWindow()->toPoints( s ); }
00571 inline  Area    toPoints( const Area &a ) { return getWindow()->toPoints( a ); }
00573 inline  Rectf   toPoints( const Rectf &a ) { return getWindow()->toPoints( a ); }
00574 
00576 inline double   getElapsedSeconds() { return App::get()->getElapsedSeconds(); }
00578 inline uint32_t getElapsedFrames() { return App::get()->getElapsedFrames(); }
00579 
00581 inline DataSourceRef        loadResource( const std::string &macPath, int mswID, const std::string &mswType ) { return App::loadResource( macPath, mswID, mswType ); }
00582 #if defined( CINDER_COCOA )
00583 
00584     inline DataSourceRef    loadResource( const std::string &macPath ) { return App::loadResource( macPath ); }
00585 #else
00586 
00587     inline DataSourceRef    loadResource( int mswID, const std::string &mswType ) { return App::loadResource( mswID, mswType ); }
00588 #endif
00589 
00591 inline DataSourceRef        loadAsset( const fs::path &relativePath ) { return App::get()->loadAsset( relativePath ); }
00593 inline fs::path             getAssetPath( const fs::path &relativePath ) { return App::get()->getAssetPath( relativePath ); }
00595 inline void                 addAssetDirectory( const fs::path &dirPath ) { App::get()->addAssetDirectory( dirPath ); }
00596 
00598 inline fs::path     getAppPath() { return App::get()->getAppPath(); }
00600 
00603 inline fs::path     getOpenFilePath( const fs::path &initialPath = "", std::vector<std::string> extensions = std::vector<std::string>() ) { return App::get()->getOpenFilePath( initialPath, extensions ); }
00605 
00608 inline fs::path     getSaveFilePath( const fs::path &initialPath = "", std::vector<std::string> extensions = std::vector<std::string>() ) { return App::get()->getSaveFilePath( initialPath, extensions ); }
00609 
00611 
00614 inline std::ostream&    console() { return App::get()->console(); }
00615 
00617 inline Timeline&    timeline() { return App::get()->timeline(); }
00618 
00620 inline Surface  copyWindowSurface() { return App::get()->copyWindowSurface(); }
00622 inline Surface  copyWindowSurface( const Area &area ) { return App::get()->copyWindowSurface( area ); }
00624 inline void     restoreWindowContext() { return App::get()->restoreWindowContext(); }
00625 
00626 #if defined( CINDER_COCOA )
00627 
00628 inline ::CGContextRef   createWindowCgContext() { return (std::dynamic_pointer_cast<Renderer2d>(App::get()->getRenderer()))->getCgContext(); }
00629 #endif
00630 
00632 
00634 class ResourceLoadExc : public Exception {
00635   public:
00636 #if defined( CINDER_COCOA )
00637     ResourceLoadExc( const std::string &macPath );
00638 #elif defined( CINDER_MSW )
00639     ResourceLoadExc( int mswID, const std::string &mswType );
00640     ResourceLoadExc( const std::string &macPath, int mswID, const std::string &mswType );
00641 #endif
00642 
00643     virtual const char * what() const throw() { return mMessage; }
00644 
00645     char mMessage[4096];
00646 };
00647 
00649 class AssetLoadExc : public Exception {
00650   public:
00651     AssetLoadExc( const fs::path &relativePath );
00652 
00653     virtual const char * what() const throw() { return mMessage; }
00654 
00655     char mMessage[4096];
00656 };
00657 
00658 } } // namespace cinder::app