Detecting HD displays

Unless I’m missing something, it seems like there’s a pretty big hole in the way HD resolutions are being handled in Cocos 2DX. In Cocos2D, the use of a retina flag is also, “wrong” but it works for the iPhone. Cocos2DX needs a more general solution, but the current method:

http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Multi_resolution_support

Doesn’t work very well IMO. The issue is that it has no concept of pixel density so a 4" display that is 960x640 would use the same assets as an 8" display that is 960x640, which is not what you want under most circumstances.

What you want to do is use high density assets for the 4" display, and low density assets for the 8" display. The 8" display has more usable real estate, but less quality - and will likely use a very different layout.

I’m fine doing the math on all of this myself, but right now there’s no way that I can find to detect that the difference between the two displays.

CCDirector::sharedDirector()->getWinSize();
CCDirector::sharedDirector()->getWinSizeInPixels();
CCDirector::sharedDirector()->getVisibleSize();

All return the exact same values.

CCDirector::sharedDirector()->getContentScaleFactor();

always returns 1.

I get that the idea is we’re supposed to set the content scale factor, but without knowing the pixel density I can’t set it correctly.

What should be happening (IMO) is that when you have a high density display the content scale factor should be initialized to the value that normalizes the pixels per inch (for retina, it would be 2 or 0.5 depending on which way you go) and suitable values would need to be used for Android devices (there are methods for getting the pixel density there as well). With that in place, we can always work in Points instead of Pixels, determine what density assets to load based on the scale factor, and determine what layouts to use based on Points.

getWinSize() would return the points, and getWinSizeInPixels() would return pixels. This would also match the behavior of Cocos2D (Obj-C version).

Does that sound right, or am I missing a call somewhere that would get me the info I need?

Tom

1 Like
  • About return values: CCDirector::sharedDirector()->getContentScaleFactor() returns 2 on Apple retina devices, and 1 anywhere else. But you can set it manually using setContentScaleFactor method.
  • Use CCDirector::getWinSize() to get screen size in pixels, CCDevice::getDPI() to get pixels-per-inch factor, and CCEGLView::setDesignResolutionSize(...) to change size of logical coordinate system in cocos2dx.
  • There are only two sizes: size of screen in pixels that is equal to image quality and physical size that is equal to touches quality.

Some math:

The getDPI() function could work depending on how it’s implemented. For example, I wouldn’t want it to give me a different value for the iPad Mini and the non-retina iPads. For now I’ll have to create assets the function within a range of DPIs - a bit fiddly, but should do the trick.

That said, I just triple checked a bunch of things and it definitely looks like there are some bugs with this stuff:

  1. In the iPhone simulator getContentScaleFactor() returns 1 on all different device types (retina or otherwise).
  2. Using setContentScaleFactor to set the scale factor to 2 doubles the results of getWinSizeInPixels which should never change
  3. getWinSize returns the same results regardless of what the scale is set to.

This behavior is all completely different from Obj-C version of Cocos2D and breaks the whole points vs pixels methodology.

Tom

Thanks Tom for starting a discussion on this, I have been struggling with the methodology behind this as well.

I am only starting out, so I don’t have experience with either cocos2d or cocos2d-x, but correct me if I am wrong, the difference in the methodologies is that cocos2d doesn’t have a parallel to pEGLView->setDesignResolutionSize(), and where cocos2d bases the content scale factor off of the pixel ratio, cocos2d-x bases it off the frame pixel size relative to the design resolution size.

I am starting to think I need to base my resource loading off more than the logic that is supplied in the sample apps and take into account DPI

The best way I’ve found to work with multiple resolutions and pixel densities is to go with a points system like what is being done with the Obj-C version of Cocos2D. I’ve been doing some digging into the Cocos2D-X source code and the content scale factor implementation is completely broken. As in … I don’t think it even works as intended for Cocos2D-X, let alone not matching the Obj-C version.

Right now it modifies values being sent to a number of different places in the code, but to work correctly it should be modifying the modelview matrix (for OpenGL ES 1.1) to do the proper scaling. All of the draw calls then function in points, and the scaling happens uniformly and makes for substantially simpler code.

You can still use the design resolution methodology, but you have it work in points instead of pixels. Then you extend that to support different pixel density assets. The end result is that all of your layout code is based on the physical size of the device, and the level of detail (pixel resolution) is based on the pixel density of the device.

I have other priorities at the moment, but I plan on modifying Cocos2D-X to work this way for me as soon as I get a chance. Hopefully those changes will be seen as useful and brought into the main branch.

Tom

Continuing to peal the onion that is content scale handling, and I have a better understanding of what is happening, it’s just very different than what I’m used to or would expect.

You need to use to both the design resolution system and set the content scale factor to get the results I would expect. Which is of course what the documentation says, just not in a way I understood until I looked at the code :wink:

The system is usable - it’s just a bit more work than necessary and unfortunately the content scale factor is global so you can’t pick and choose which assets are high density, etc. I think it would be possible to extend the system to be a bit more flexible like the Obj-C version, but will file that away for another day.

Tom

Thanks Tom, I have the same questions as you, coming from a (iOS) Cocos2D-Spritebuilder background. The game I’ve created in cocos2d-x for iOS devices is truly screen size agnostic, and it handles scales perfectly. The reason is there are just a few iOS devices and it’s not too hard to hard code those in yet, so it selects the “correct” resolutions of artwork for each screen. And all the screen POINT sizes are nicely available to us, for instance I always look at http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions if I ever forget those. So the game I’ve made (and published) uses the exact native point sizes for each screen size. 320x480 up till iPhone 4s, then 320x568 for iPhone 5 line, 375x667 for iPhone 6 and 414x736 for iPhone 6 Plus. I fully support iPads too, both retina and non retina, the point size is 768x1024. Of course you know this. :slight_smile:
Then in the game I position menus and buttons and what not relatively to each other. If I want to position a button 5 points to the right of another button, it will be the exact same amount of distance on screen for all devices if we get a ruler and count the centimeters. That’s what point sizes are for.

So, the way I calculate screen design size is:

screendesignsize = screenpixels / screenscale

That is so simple. :slight_smile:
Then I don’t need to worry about letterboxes or screen aspect ratios at all. This can be used for games like strategy, card games etc where the amount of game area you see at a time does not exactly affect the game outcome, i.e. no unfair competition etc will occur. Maybe this cannot be used for online multiplayer action games where a bigger screen estate would be unfair. But that’s another question.

Now with Android we can’t do that of course, because we can’t get the true contentScaleFactor so we can’t know what design size we need for each device. And the artwork resolution selection cannot be done. A low resolution tablet versus a small high res phone will be so different. What do we do?