Skip to content

A Magnifying Glass for Cocos2D

June 3, 2012
UPDATED VERSION 12/5/2012

During development of our new iOS game, using Cocos2D, I needed a magnifying glass that you could move over the screen and enlarge the portions below it. I did something similar before with UIKit, and that wasn’t a big deal at all, however with OpenGL it is a different story. I experimented with CCLens3D effects, but wasn’t satisfied with it. Surfing around didn’t reveal much, except that there a) is a need, and b) no real complete solution around. At the end of this blog, you can download everything you need for a great magnifying glass Cocos2D solution!

Based on how to grab a screenshot to get the data that is currently shown (discussed e.g. here in the Cocos2D forum), I came up with a solution to simply take the UIKit technique I knew already: grab the data (in this case from the OpenGL buffer, but just the piece that I need), redraw it enlarged into an UIView (depending on a variable magnification scale) and then let that view hover on top of the OpenGL view. This solves at the same time the issue that any loupe graphics you use in Cocos2D would be part of the contents of the current OpenGL buffer and be enlarged as well, ending up with a funny mirror-in-mirror effect.

The UIView will be wrapped by a CCNode-derived class, so you can use it like other nodes within your scene. The solution is surprisingly lean and easy to use, does not eat much of your precious memory and is fast. In contrast to the well-known textedit loupe, I chose to not enlarge the area below your finger, but that below the center of the loupe. This turned out to be much more intuitive for my use-case, but of course you can do it differently by simply changing the grabbed rectangle coordinates.

The loupe will hover quite a bit above your finger, which is determined by setting the anchor position in the initialization. You can choose a different setting here, or make it even dynamic by adapting the anchor in setPosition (so the loupe will move around your finger when approaching the lower screen border — pretty nice effect).
For the loupe frame itself you can create whatever graphics you like. My example provides a very thin and simple rounded frame with a little 3D effect and shadow, but you can design whatever you like. For simplicity I chose a centered inner area, which makes rendering the magnified area very easy. If you need it, however, you can also go for a masked approach and mask out the inner part by providing an according masking image (and the required coding for it, of course. Ray Wenderlich provides some great samples for masking in his blog!).

Update 5/12/2012: For Cocos2D V2.0 it is no longer required to explicitly rotate the contents according to device orientation. The coding to download below  now checks the Cocos-Version and omits the rotation now automatically.

If you create your own loupe image with different proportions, you need to change the percentage of the inner part. You can compute that simply by dividing the diameter of the inner part by the total side-length of your image. Included you’ll find all required graphics for iPhone & iPad, ready & tested for standard and retina resolutions. I chose to have a relatively larger loupe for the iPhone/iPod, since magnification was even more required here than on the iPad, but it’s up to you what size of graphics you provide.

Once you imported the Magnifier class and the images into your project, you set the loupe up like that somewhere in your scene:

  Magnifier *magnifier = [[[Magnifier alloc] initWithMagnification: 2.0] autorelease];
  magnifier.position = <some position, e.g. touchLocation in ccTouchesBegan/Moved>;
  [self addChild:magnifier];

and there you go. Whenever you change the position, the magnified area will be updated as well automatically. If you want the magnified content to change dynamically also while you don’t move the loupe, you need to call the magnify method either periodically from a timer method, or at points in time where you know that content has changed. From my experience, though, having it updated on position changes is completely sufficient.

Update: Fix for iOS6 and above

There is nothing else to do for all iOS versions up to iOS 5.1. For newer versions of iOS in the future, however, you will need to tweak the way OpenGL handles graphics buffering, otherwise you will see a unicolor area only in the loupe. Fortunately, this is pretty easy to do: just replace this standard EAGLView initialization in your app delegate:

EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
	                       pixelFormat:kEAGLColorFormatRGBA8 // or whatever you use...
			       depthFormat:0];

with this one to make sure that OpenGL will retain it’s backbuffers:

EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
                               pixelFormat:kEAGLColorFormatRGBA8 // or whatever you use...
                               depthFormat:0
                        preserveBackbuffer:YES
                                sharegroup:nil
                             multiSampling:NO
                           numberOfSamples:0];

The Beef

The loupe graphics and Magnifier class ready for consumption can be downloaded here.

Advertisements

From → Development

27 Comments
  1. Brent permalink

    Dude killer. Thank you for sharing. You are the man.

  2. Ziya Bal permalink

    Hi,

    Nice for sharing this great stuff. Can you provide me for more support on how to import the magnifier in my project. I’ve downloaded the classes, implemented them in my project, tryed to with some code to get use of it. But I can’t get a result.

    Can you give some more support on how to call the magnifier.

    Great work, thanks!

    • There is not much magic involved. Add the code files and graphics to your project, and then just import “Magnifier.h” and put the few lines code from the blog into some layer coding (e.g. the init method) from your Cocos2D project. Once you added the Magnifier-node to a layer (or any visible subnode), it will show up there (you need to set some meaningful position, of course).
      If you want to move the loupe (and I am sure you will want to), then you need to set the position to the touch location in ccTouchMoved.

      • I tried the description of yours to add the magnifier in my project. I’m getting stuck with implementing it in my own code. I’ve added the images en the …h and …m to my project.

        Is there maybe a sample project to just show on how it use on a main view (in viewcontroller) to get more control for users that just new with these methods. Like ccTouchMoved. Can you provide a simple one view sample project, just to show how to implement?

        Friendly regards,

        Greets from Holland

      • I might try to come up with a sample project later on, but as you can see in my latest blog I am right now doing the final touches on my new game, Café International. So I am pretty busy right now.
        Once you know the basics of Cocos2D, it will be totally easy for you to do it. Don’t mess around with the view controller, this is definitely the wrong place to do it. Cocos2D is all about “scenes”, and once your scene is in place and up and running, you can just add the magnifier with the few lines of code as explained in the blog.
        Implementing touch handling is a standard thing to do (just enable touches and register your layer as touch handler), and there are plenty of tutorials around for this.
        Once I have some more air to breathe again, I’ll look into a more comprehensive complete sample.
        Best, rombos

  3. I’m very happy to get a fast/quick reply!

    I know what you’re working on, I read your blog and it’s interesting. I’m looking for more 🙂
    I’m new to cocos2d, and I’m learning day by day. I look forward to implement the magnifier to one of my projects.

    Thanks again!

  4. riz permalink

    Thank you! It’s the one I’m looking for!

  5. riz permalink

    Oh, and there is some bug:
    if you touched in your loupe image(like loupe.png), ‘ccTouchedBegan’ method gets magnifierView’s touch location. (not based on device location, based on magnifierView).
    magnifierView’s order of priority is higher than UIView.
    (I use this codes in cocos2d project.)
    So, you need to insert one line in ‘initWithLoupeImage: (UIImage *) loupeImg’ method.

    [self setUserInteractionEnabled:NO];

    Thank you! 🙂

    • Great observation!
      It doesn’t occur the way I use it, though. I fire the loupe on ccTouchBegan and return YES. Then I get all ccTouchMoved until you lift the finger again, in which case I put the loupe away. So no touch will ever be distributed elsewhere while the magnifier is open.

  6. Hi Rombos,

    Did you manage looping for a sample project with the magnifier included?

    I want to get in touch with the magnifier in my project, but i don’t know how to implement with just 2 lines of code.

    Thank you!

  7. Matt permalink

    Hello,
    I am having a small problem.. I followed the instructions and I am able to get the magnifying glass on the layer.. However, it’s completely white.. There is nothing inside.. What do u think is my mistake?
    Thanks..

    • Matt permalink

      Btw I am using Cocos2d 2.0

      • I updated the code in the ZIP to correctly consider V2.0, since here you must not rotate the grabbed content according to device orientation. I inserted a macro to check the Cocos version and omit the rotation for Cocos2D V2.0+ now.

      • helena permalink

        hey, i have high-res images that are rescaled to .1 and they seem like low-res in the mgnifying glass.. Can I fix this problem??

      • The magnification is done on the actual pixel resolution of the underlying screen, not on the graphics that are presented there. So you don’t gain additional pixels through this way of magnification. In theory you could modify the grabImage routine to get the information from the corresponding area of the underlying higher resolution source graphics, but this works of course only in special cases where the area to be magnified is not a composition of many (maybe even moving) sprites.

    • Probably you are using it under iOS 6. Please read the part of the blog referring to iOS 6 and above: you need to switch on double buffering for iOS6.

  8. Matt permalink

    I have sprites that move around.. if i move the magnifying glass on the sprites, then I will be able to see them moving.. however if I stop moving the magnifying glass, even though the sprites move out of the magniying glass’ scene, on the magnifying glass, sprites remain without moving.. how can I fix this?

    • This is mentioned in the blog, please re-read it how to solve this.

      • geoff permalink

        hey, this is awesome.. i have a small problem.. on my device, when repositioning it, my game runs too slow.. in fact fps label stops updating, other sprites stop moving etc.. it works fine in simulator though.. any ideas?

      • The way the magnification works is inherently slow (but this is unfortunately the only generic way to do it at all). You are actually making a screenshot, then enlarge the desired area and copy it back to the screen. It will not work well in a real-time environment loaded with ongoing animations.

  9. Steven permalink

    I am trying to use this magnifier with physics in place (moving blocks). I’ve noticed that whenever I set the magnifiers position it freezes the physics simulation. Is it possible that it is interrupting the animation thread? I’m not 100% sure on what is causing this and I know you advise against this use case, but I was curious to see how it would perform. Do you have any insight or advice on how to address this issue? Thanks for the tool.

    • Hi,

      I don’t see how this technique would actually freeze any physics simulation. If you don’t update the magnification regularly, the view of it through the loupe seems to be frozen, of course, but the underlying animations should actually proceed.
      Regularly updating the magnification view, however, is pretty expensive, so it will definitely slow down what you’re doing…

      Regards, Rombos

Trackbacks & Pingbacks

  1. List of Open Source Cocos2d Projects, Extensions and Code Snippets | iUridium
  2. Example: Creating A Magnifying Glass Effect In Cocos2D | WebScriptPlus.com
  3. Last weeks iOS resources (Jul 15 2012) | E.V.I.C.T. B.V.
  4. Last weeks iOS resources (Jul 29 2012) | E.V.I.C.T. B.V.
  5. A Magnifying Glass for Cocos2D « Programming Cocos2D with iPhones and iPads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: