diff --git a/iphone/Maps/Classes/EAGLView.h b/iphone/Maps/Classes/EAGLView.h index af17102255..873874a650 100644 --- a/iphone/Maps/Classes/EAGLView.h +++ b/iphone/Maps/Classes/EAGLView.h @@ -34,12 +34,11 @@ namespace yg shared_ptr renderContext; shared_ptr renderBuffer; shared_ptr frameBuffer; - shared_ptr drawer; @public shared_ptr windowHandle; - shared_ptr textureManager; + shared_ptr drawer; MapViewController * controller; } @@ -50,6 +49,7 @@ namespace yg @property (nonatomic, assign) CADisplayLink * displayLink; @property (nonatomic, assign) MapViewController * controller; @property (nonatomic, assign) shared_ptr windowHandle; +@property (nonatomic, assign) shared_ptr drawer; @property (nonatomic, assign) shared_ptr renderContext; @property (nonatomic, assign) shared_ptr resourceManager; diff --git a/iphone/Maps/Classes/EAGLView.mm b/iphone/Maps/Classes/EAGLView.mm index b1f711bd1d..6136a3a379 100644 --- a/iphone/Maps/Classes/EAGLView.mm +++ b/iphone/Maps/Classes/EAGLView.mm @@ -20,6 +20,7 @@ bool _inRepaint = false; @synthesize controller; @synthesize windowHandle; +@synthesize drawer; @synthesize renderContext; @synthesize resourceManager; @synthesize displayLink; @@ -143,7 +144,6 @@ bool _inRepaint = false; windowHandle = shared_ptr(new iphone::WindowHandle(_doRepaint)); - windowHandle->setDrawer(drawer); windowHandle->setRenderContext(renderContext); displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)]; @@ -174,19 +174,13 @@ bool _inRepaint = false; - (void)drawView { - if (!_inRepaint) + if (windowHandle->needRedraw()) { - _inRepaint = true; - - if (_doRepaint) - { - _doRepaint = false; - [controller beginPaint]; - [controller doPaint]; - renderBuffer->present(); - [controller endPaint]; - } - _inRepaint = false; + windowHandle->setNeedRedraw(false); + [controller beginPaint]; + [controller doPaint]; + renderBuffer->present(); + [controller endPaint]; } } diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index 5a549f14ec..3162c5015c 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -289,8 +289,8 @@ NSInteger compareAddress(id l, id r, void * context) - (void)doPaint { - shared_ptr windowHandle = [(EAGLView*)self.view windowHandle]; - shared_ptr paintEvent(new PaintEvent(windowHandle->drawer().get())); + shared_ptr drawer = [(EAGLView*)self.view drawer]; + shared_ptr paintEvent(new PaintEvent(drawer.get())); m_framework->DoPaint(paintEvent); } diff --git a/map/framework.cpp b/map/framework.cpp index a2172f3f9a..568de21cc0 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -234,6 +234,18 @@ void Framework::SetMaxWorldRect() m_navigator.SetFromRect(m_model.GetWorldRect()); } +template +bool Framework::NeedRedraw() const +{ + return m_windowHandle->needRedraw(); +} + +template +void Framework::SetNeedRedraw(bool flag) +{ + m_windowHandle->setNeedRedraw(false); +} + template void Framework::Invalidate() { diff --git a/map/framework.hpp b/map/framework.hpp index 0331dd9327..ec58117589 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -208,6 +208,9 @@ public: double GetCurrentScale() const; + bool NeedRedraw() const; + void SetNeedRedraw(bool flag); + virtual void BeginPaint(); /// Function for calling from platform dependent-paint function. virtual void DoPaint(shared_ptr e); diff --git a/map/window_handle.hpp b/map/window_handle.hpp index 7b606697c0..f1062ba57c 100644 --- a/map/window_handle.hpp +++ b/map/window_handle.hpp @@ -15,22 +15,28 @@ namespace yg class WindowHandle { - // iOS implementation needs this parameter. - // Desktop realization holds DrawerYG in draw_widget.hpp. - shared_ptr m_drawer; - shared_ptr m_renderContext; bool m_hasPendingUpdates; bool m_isUpdatesEnabled; + bool m_needRedraw; public: - WindowHandle() : m_hasPendingUpdates(false), m_isUpdatesEnabled(true) {} + WindowHandle() : + m_hasPendingUpdates(false), + m_isUpdatesEnabled(true), + m_needRedraw(true) + {} virtual ~WindowHandle() {} - shared_ptr const & drawer() + bool needRedraw() const { - return m_drawer; + return m_isUpdatesEnabled && m_needRedraw; + } + + void setNeedRedraw(bool flag) + { + m_needRedraw = flag; } shared_ptr const & renderContext() @@ -43,17 +49,12 @@ public: m_renderContext = renderContext; } - void setDrawer(shared_ptr const & drawer) - { - m_drawer = drawer; - } - bool setUpdatesEnabled(bool doEnable) { bool res = false; if ((!m_isUpdatesEnabled) && (doEnable) && (m_hasPendingUpdates)) { - invalidateImpl(); + setNeedRedraw(true); m_hasPendingUpdates = false; res = true; } @@ -64,10 +65,8 @@ public: void invalidate() { if (m_isUpdatesEnabled) - invalidateImpl(); + setNeedRedraw(true); else m_hasPendingUpdates = true; } - - virtual void invalidateImpl() = 0; }; diff --git a/platform/apple_video_timer.mm b/platform/apple_video_timer.mm new file mode 100644 index 0000000000..6092d33901 --- /dev/null +++ b/platform/apple_video_timer.mm @@ -0,0 +1,67 @@ +#include "video_timer.hpp" + +#include "../std/target_os.hpp" + +#include + +class AppleVideoTimer : public VideoTimer +{ + + CVDisplayLinkRef m_displayLink; + +public: + + AppleVideoTimer(VideoTimer::TFrameFn frameFn) + : VideoTimer(frameFn), m_displayLink(0) + {} + + ~AppleVideoTimer() + { + stop(); + } + + void start() + { + if (m_displayLink == 0) + { + CVDisplayLinkCreateWithActiveCGDisplays(&m_displayLink); + CVDisplayLinkSetOutputCallback(m_displayLink, &displayLinkCallback, (void*)this); + CVDisplayLinkStart(m_displayLink); + } + } + + static CVReturn displayLinkCallback( + CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext + ) + { + AppleVideoTimer * t = reinterpret_cast(displayLinkContext); + t->perform(); + + return kCVReturnSuccess; + } + + void stop() + { + if (m_displayLink) + { + CVDisplayLinkStop(m_displayLink); + CVDisplayLinkRelease(m_displayLink); + m_displayLink = 0; + } + } + + void perform() + { + m_frameFn(); + } +}; + +VideoTimer * CreateAppleVideoTimer(VideoTimer::TFrameFn frameFn) +{ + return new AppleVideoTimer(frameFn); +} diff --git a/platform/ios_video_timer.mm b/platform/ios_video_timer.mm new file mode 100644 index 0000000000..4a80809ac5 --- /dev/null +++ b/platform/ios_video_timer.mm @@ -0,0 +1,89 @@ +#include "video_timer.hpp" + +#include "../std/target_os.hpp" + +#import +#import + +class IOSVideoTimer; + +@interface VideoTimerWrapper : NSObject { +@private + IOSVideoTimer * m_timer; +} +- (id)initWithTimer:(IOSVideoTimer *) timer; +- (void)perform; +@end + +class IOSVideoTimer : public VideoTimer +{ + + VideoTimerWrapper * m_objCppWrapper; + CADisplayLink * m_displayLink; + +public: + + IOSVideoTimer(VideoTimer::TFrameFn frameFn) : VideoTimer(frameFn), m_objCppWrapper(0), m_displayLink(0) + {} + + ~IOSVideoTimer() + { + stop(); + } + + void start() + { + if (m_displayLink == 0) + { + m_objCppWrapper = [[VideoTimerWrapper alloc] initWithTimer:this]; + m_displayLink = [CADisplayLink displayLinkWithTarget:m_objCppWrapper selector:@selector(perform)]; + m_displayLink.frameInterval = 1; + [m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + } + } + + void stop() + { + if (m_displayLink) + { + [m_displayLink invalidate]; + [m_objCppWrapper release]; + m_displayLink = 0; + } + } + + void perform() + { + m_frameFn(); + } +}; + +@implementation VideoTimerWrapper + +- (id)initWithTimer:(IOSVideoTimer*) timer +{ + self = [super init]; + if (self) { + m_timer = timer; + } + return self; +} + +- (void)dealloc +{ + [super dealloc]; +} + +- (void)perform +{ + m_timer->perform(); +} + +@end + +VideoTimer * CreateIOSVideoTimer(VideoTimer::TFrameFn frameFn) +{ + return new IOSVideoTimer(frameFn); +} + + diff --git a/platform/platform.pro b/platform/platform.pro index 2889e7ab9f..bcf2fcf510 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -35,8 +35,15 @@ macx|iphone* { } macx:!iphone* { - OBJECTIVE_SOURCES += wifi_info_mac.mm - LIBS += -framework CoreWLAN + OBJECTIVE_SOURCES += wifi_info_mac.mm \ + apple_video_timer.mm + + LIBS += -framework CoreWLAN -framework QuartzCore +} + +iphone* { + OBJECTIVE_SOURCES += ios_video_timer.mm + LIBS += -framework QuartzCore } win32 { @@ -52,9 +59,11 @@ HEADERS += \ concurrent_runner.hpp \ preferred_languages.hpp \ settings.hpp \ + video_timer.hpp SOURCES += \ location_manager.cpp \ preferred_languages.cpp \ settings.cpp \ platform.cpp \ + video_timer.cpp diff --git a/platform/video_timer.cpp b/platform/video_timer.cpp new file mode 100644 index 0000000000..288534d04a --- /dev/null +++ b/platform/video_timer.cpp @@ -0,0 +1,4 @@ +#include "video_timer.hpp" + +VideoTimer::VideoTimer(TFrameFn fn) : m_frameFn(fn) +{} diff --git a/platform/video_timer.hpp b/platform/video_timer.hpp new file mode 100644 index 0000000000..a93bfee31a --- /dev/null +++ b/platform/video_timer.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../std/function.hpp" + +/// Timer, synchronized to Vertical Sync +class VideoTimer +{ +public: + + typedef function TFrameFn; + +protected: + + TFrameFn m_frameFn; + +public: + + VideoTimer(TFrameFn fn); + + virtual void start() = 0; + virtual void stop() = 0; +}; + +extern "C" VideoTimer * CreateIOSVideoTimer(VideoTimer::TFrameFn frameFn); +extern "C" VideoTimer * CreateAppleVideoTimer(VideoTimer::TFrameFn frameFn); +extern "C" VideoTimer * CreateWin32VideoTimer(VideoTimer::TFrameFn frameFn); diff --git a/qt/draw_widget.cpp b/qt/draw_widget.cpp index 169486f1e1..aa6a2aeaca 100644 --- a/qt/draw_widget.cpp +++ b/qt/draw_widget.cpp @@ -17,19 +17,32 @@ namespace qt { DrawWidget::DrawWidget(QWidget * pParent, Storage & storage) : base_type(pParent), - m_handle(new qt::WindowHandle(this)), + m_handle(new WindowHandle()), m_framework(FrameworkFactory::CreateFramework(m_handle, 0)), m_isDrag(false), m_redrawInterval(100), - m_pScale(0) + m_pScale(0), + m_isInitialized(false), + m_isTimerStarted(false) { m_framework->InitStorage(storage); m_timer = new QTimer(this); +//#ifdef OMIM_OS_MAC +// m_videoTimer.reset(CreateAppleVideoTimer(bind(&DrawWidget::DrawFrame, this))); +//#else + m_animTimer = new QTimer(this); + connect(m_animTimer, SIGNAL(timeout()), this, SLOT(AnimTimerElapsed())); +//#endif connect(m_timer, SIGNAL(timeout()), this, SLOT(ScaleTimerElapsed())); } void DrawWidget::PrepareShutdown() { +//#ifdef OMIM_OS_MAC +// m_videoTimer->stop(); +//#else + m_animTimer->stop(); +//#endif m_framework->PrepareToShutdown(); } @@ -165,26 +178,51 @@ namespace qt { widget_type::initializeGL(); m_handle->setRenderContext(renderContext()); - //m_handle->setDrawer(GetDrawer()); m_framework->InitializeGL(renderContext(), resourceManager()); + m_isInitialized = true; } - void DrawWidget::DoDraw(shared_ptr p) + void DrawWidget::DrawFrame() { - m_framework->BeginPaint(); - shared_ptr paintEvent(new PaintEvent(p.get())); - m_framework->DoPaint(paintEvent); + if (m_framework->NeedRedraw()) + { + makeCurrent(); + m_framework->SetNeedRedraw(false); + m_framework->BeginPaint(); + shared_ptr paintEvent(new PaintEvent(GetDrawer().get())); + m_framework->DoPaint(paintEvent); - /// swapping buffers before ending the frame, see issue #333 - swapBuffers(); + /// swapping buffers before ending the frame, see issue #333 + swapBuffers(); - m_framework->EndPaint(); + m_framework->EndPaint(); + doneCurrent(); + } + } + + void DrawWidget::DoDraw(shared_ptr p) + { + if ((m_isInitialized) && (!m_isTimerStarted)) + { + /// timer should be started upon the first repaint + /// request to fully initialized GLWidget. + m_isTimerStarted = true; +//#ifdef OMIM_OS_MAC +// m_videoTimer->start(); +//#else + m_animTimer->start(1000 / 60); +//#endif + } + + m_framework->Invalidate(); } void DrawWidget::DoResize(int w, int h) { m_framework->OnSize(w, h); m_framework->Invalidate(); + if (m_isInitialized && m_isTimerStarted) + DrawFrame(); UpdateScaleControl(); emit ViewportChanged(); } @@ -258,6 +296,11 @@ namespace qt m_timer->stop(); } + void DrawWidget::AnimTimerElapsed() + { + DrawFrame(); + } + void DrawWidget::wheelEvent(QWheelEvent * e) { if (!m_isDrag) diff --git a/qt/draw_widget.hpp b/qt/draw_widget.hpp index 40daa385ac..254a7235f9 100644 --- a/qt/draw_widget.hpp +++ b/qt/draw_widget.hpp @@ -1,12 +1,14 @@ #pragma once -#include "qt_window_handle.hpp" #include "widgets.hpp" +#include "../map/window_handle.hpp" #include "../map/feature_vec_model.hpp" #include "../map/framework.hpp" #include "../map/navigator.hpp" +#include "../platform/video_timer.hpp" + #include "../std/auto_ptr.hpp" #include @@ -28,15 +30,22 @@ namespace qt { typedef widget_type base_type; - shared_ptr m_handle; + shared_ptr m_handle; + + shared_ptr m_drawer; + bool m_isInitialized; + bool m_isTimerStarted; typedef model::FeaturesFetcher model_t; auto_ptr > m_framework; + auto_ptr m_videoTimer; + bool m_isDrag; QTimer * m_timer; + QTimer * m_animTimer; size_t m_redrawInterval; Q_OBJECT @@ -59,6 +68,7 @@ namespace qt void Repaint(); void ScaleChanged(int action); void ScaleTimerElapsed(); + void AnimTimerElapsed(); public: DrawWidget(QWidget * pParent, storage::Storage & storage); @@ -86,10 +96,12 @@ namespace qt /// @name Overriden from base_type. //@{ virtual void initializeGL(); - virtual void DoDraw(shared_ptr p); + virtual void DoDraw(shared_ptr p); virtual void DoResize(int w, int h); //@} + void DrawFrame(); + /// @name Overriden from QWidget. //@{ virtual void mousePressEvent(QMouseEvent * e); diff --git a/qt/qt.pro b/qt/qt.pro index 4186995953..9c21aca280 100644 --- a/qt/qt.pro +++ b/qt/qt.pro @@ -19,7 +19,7 @@ win32-msvc* { } macx { - LIBS += -framework CoreLocation -framework Foundation -framework CoreWLAN + LIBS += -framework CoreLocation -framework Foundation -framework CoreWLAN -framework QuartzCore ICON = res/mac.icns PLIST_FILE = Info.plist @@ -77,7 +77,6 @@ HEADERS += \ mainwindow.hpp \ widgets.hpp \ draw_widget.hpp \ - qt_window_handle.hpp \ proxystyle.hpp \ slider_ctrl.hpp \ about.hpp \ diff --git a/qt/widgets.cpp b/qt/widgets.cpp index ad366ac129..7e733174f4 100644 --- a/qt/widgets.cpp +++ b/qt/widgets.cpp @@ -22,6 +22,11 @@ namespace qt { } + shared_ptr const & GLDrawWidget::GetDrawer() const + { + return m_p; + } + void GLDrawWidget::initializeGL() { /// we'll perform swap by ourselves, see issue #333 diff --git a/qt/widgets.hpp b/qt/widgets.hpp index c70af3c3a9..cc8fc98aa6 100644 --- a/qt/widgets.hpp +++ b/qt/widgets.hpp @@ -33,6 +33,8 @@ namespace qt shared_ptr const & renderContext(); shared_ptr const & resourceManager(); + shared_ptr const & GetDrawer() const; + protected: virtual void initializeGL(); };