Synchronize COCOS2D Layer on top of a MKMapView - ios

I'm tring to synchronize cocos2D layer objects with the map, I managed to get it working by adjusting the glView to the visibleMapRect of the MKMapView. I can zoom, move, my objects are following the map. But, there is a small and annoying lag between the MKMapView and the cocos2D Layer.
I'm synchronizing it at each display loop.
Method:
1) Retrieve the MKMapView.visibleMapRect
2) Set the glViewPort
3) Do an orthographic projection to adjust my layer to the MapView.
I already tried others methods, like moving the cocos2D layer with touch and then move the coordinates of my map according to the touch, still laggy.
Even disabling acceleration and deceleration of the MapView doesn't remove the lag.
Thanks.

Shot in the dark: we know that iOS devices use optimizations to speed up rendering while scaling. This is true for Safari browser, when you zoom in you actually only zoom in on the image that is currently being displayed as the browser window's contents. Only after you stop the pinch motion does the device update the view.
You'll see this specifically with text on older devices. When the device re-renders the contents with the new scale factor, the text suddenly becomes sharp and crisp again. I believe the same optimization is done in MKMapView.
You might want to check if the visibleMapRect values are actually updated during the zoom, and whether they accurately reflect the current zoom level or not.
The other issue I can imagine is that the framerate with MKMapView + Cocos2D is simply low. And specifically zooming might consume a lot of CPU power. You might want to enable the cocos2d FPS display to see what the framerate is.
Another trick that's necessary to allow smooth scrolling of views in cocos2d (particularly complex views like UITableView) is to reduce cocos2d's max framerate (animationInterval) and/or to run the rendering of the gl view on a separate thread. Your issue may simply be a variation of this issue: UIScrollView pauses NSTimer until scrolling finishes
Note that this also occurs with DisplayLink director. The info in this question did the trick for me.

Related

Synchronizing CATiledLayer drawing to screen?

We have an application that uses CATiledLayer to render a large and complex vector drawing to the display. The scrolling and zooming peformance is quite good. We are having an issue when the image is zoomed in and the user is editing the vector items. They are able to select an item and modify it by moving the item or adjusting the item control points. We only update the visible area of the screen. Using Instruments. I can tell that our rendering code is properly clipping and in only called when the backing layers are updated. Memory overhead is low and our drawing routine is fast. The issue is in the screen update; we can see tearing as the CATiledLayer updates the tiles.
Does anyone know of a way to synchronize the drawing of all the tiles that are onscreen so they are blitted at the same time? If not, has anyone come up with any techniques to deal with type of issue?
Thanks in advance for any advice or input!

How to fix various MKTileOverlay rendering problems?

I'm currently in the process of converting a custom map from using a CATiledLayer scroll view to using custom map tiles in an MKMapView with an MKTileOverlay. Whilst the CATiledLayer-approach generally works well and looks nicer, you get a lot of things for free by using an MKMapView such as rotations which are otherwise very difficult to achieve.
So, I've redrawn my tiles for use with the recommended format of zoom level, column and row numbers, and have them displaying in the map view correctly. Note that my map tiles only cover a small region somewhere; I don't have them for the entire globe.
The first problem I noticed is that there seems to be an issue when you zoom in past the largest zoom level my tiles support. I have tiles all the way to zoom level 20 so I set my MKTileOverlay's maximumZ property to 20. If you zoom in to level 21, the map view no longer requests tiles at all. Any tiles loaded on the way to level 21 still show (albeit pixelated), but if you scroll away it won't load any more tiles, so eventually the map just becomes blank. Ideally, it would fall back to my level 20 tiles and display those instead, or prevent the user from zooming in too far. When I use the CATiledLayer, you could zoom in as much as you want and it would always show the most zoomed in tiles (even if you were zoomed in further than the tiles were 'comfortable' at). Example
I have other minor niggles too:
If you set canReplaceMapContent to true, you can zoom in a lot further (which is fine), but the camera clips the ground if you get too close and I get all sorts of rendering artefacts. Any way to prevent that from happening? Example
Sometimes there are small pixel-sized rendering artefacts between tiles which indicate the tiles aren't quite positioned or sized correctly my the MKMapView. These artefacts don't seem to affect the native maps app; any way to get rid of these? Example
As you pan around when zoomed in, there are a lot of white flashes as tiles are loaded and it's quite obvious. When I used the CATiledLayer, they were loaded in quite smoothly (by animating the opacity) and the lower-zoom levels were already present in the background so it was overall difficult to tell it was even using tiles. Is there any way to load in my tiles more seamlessly? Example
I'm guessing the answer to most of these questions is that it's not possible to fix using MKMapView, which is a shame because I really want to allow the user to change the heading of the map and it seems pretty difficult to do using a standard CATiledLayer!

Drawing World Map - Performance & Interaction - iOS

I’d like to use a Shapefile to generate an interactive world map. I was able to import the data and use CG Paths to draw the map into one large view.
The map needs to support panning, zooming and touch interaction. For that, I've created a UIScrollView and placed the MapView (large view with all of the countries drawn) into it.
I need to improve two aspects of it:
Performance / rendering
I have drawn the map much larger than the screen size, in order to make it look reasonable when I zoom in. There are a few problems with this. First, when I'm zoomed out, I need the border stroke/line to be wider so they are visible. When I zoom in, I'd like the stroke to be a thinner. Also, when I zoom in, I can still see that the map is a blurry. I don't want to increase the view size too much.
How can I make the map look crisp when I'm zoomed in? I attempted to redraw the map on zoom in, but it takes far too long. Can I somehow only re render onscreen stuff?
Touch Interaction
I need to be able to have a touch event for every different country.
Possible approach?
I was thinking of trying to separate every country onto it’s own view. That should make touches easy to handle. Then I’m thinking I can possibly redraw the appropriate views that are on screen/zoomed to.
I've played with an app that does something similar ("World Maps"), and I can see that when you pan or zoom, the map is blurry for a second but then becomes clear. What is going on there?
use mapkit and provide custom tiles. dont reinvent the wheel and try to write yet another map framework
I think that you have to create different scaled area image from the big map image. how to say... imagine the google map, how it works... I think that provide many different zoom factor image for every area of the world... then merged display on the screen while user need show it ...
use code implemented the map effect is impossible on current iPhone device, out of the ability of the iOS device

Synchronize UIView layout to OpenGL frames

We are developing a game that has 2d elements displayed with UIViews over an OpenGL ES view (specifically, we're using GLKit's GLKView) and are having problems keeping the positions perfectly in sync.
In the parent view's layoutSubviews, we're projecting 3d positions in the world onto the screen, and using those as locations for several UIView "markers" in the game. The whole game only updates in response to the user moving the camera, and the camera tells the view setNeedsLayout each time it moves.
Everthing's working fine, except that the markers seem to be roughly 1 frame out of sync with the 3d rendering. I say roughly because (1) it's an estimate! and (2) I'm wondering whether there's potentially a multithreading issue: doesn't GLKView sync to a special screen refresh callback or something?
Is there some way of hooking a view's layoutSubviews so that it sync's to the 3d view update?
Update: Weirdly, calling layoutIfNeeded immediately after setNeedsLayout makes the problem worse! Possibly 2 or more frames out. Really don't understand that!
What's triggering your call to LayoutSubviews?
It all depends where in the RunLoop your call is triggered vs. where your GLK update call is triggered.
In general, for what you're doing, I'd aim to do your layout as a side-effect of the GLK update - i.e. don't wait for layoutSubviews to change your position.
(if you're using OpenGL, then the whole "layout" system isn't much use to you: GLK is running in its own little world of variable frame rate, and you want to make that your reference point)
This is impossible to do correctly without drawing the frames of the video using OpenGL (drawing in the same context so that you are always sure that one frame contains the same time of video and animation). Everyting else you do, framerate compensation, lag prediction, only depends on chance, and will always be a little bit unsynchronized.
I'm not familiar with UIView but if there is any way to let it play audio and copy the frames to a texture, do that. The lag in the audio is much easier to compensate and much less noticeable by the humans than in the video.

Custom UIview free rotation too slow

Programming for iOS, I have a composite custom view consisting of many UIViews. Some UIViews in this composites are responsible for drawing shadow and others for some custom shading. The shadow and shading need to be redrawn upon rotation recognized by UIRotationGestureRecognizer. However the speed of the rotation is far from satisfactory. When I commented out setNeedDisplay, the rotational speed is fine. However, if I do call setNeedDisplay, even when I commented out everything in all drawRects for the shadow and shading views, the rotation still lags significantly.
Are there any recommendations to speed things up?
I can think of one possible solution: make sure the system calls drawRect less often while in rotation. But I do not know how to do this, nor do I know if this is the best solution. Any suggestion appreciated. Thanks.
Calling setNeedsDisplay: too often, especially every frame will always be slow. setNeedsDisplay runs on the CPU, not the GPU. Don't redraw views during rotation and zooming. Wait until the end of the animation, then call setNeedsDisplay: to "render" the final position.
Take a look at how various UIKit views handle large animations:
While MapKit zooms in, the map image scales and looks blurry. Once the zoom gesture stops it renders a new image at that scale. (In this case the image is downloaded from the internet, but it still illustrates the concept.)
ZoomingPDF Sample code (see apple developer docs) shows how zooming on PDFs doesn't render in realtime, but after the zooming finishes.
Hope this helps.

Resources