Multiple Resolution Support in Cocos2d-x v2.2.5 in Portrait mode - cocos2d-x

I am working on a game in cocos2d-x which is in portrait mode.
Now, for a long time now, I've been working on how to properly achieve multi resolution in cocos2d-x but failed. I followed this great tutorial on forum, but it wasn't enough, I also searched a lot but couldn't find a solution.
I also tried with different-different policies which are available with cocos-x.
I went through all the following links & tutorials
Using these links I could achieve for all ios resolutions but not for all android screens.
http://becomingindiedev.blogspot.in/2014/05/multi-resolution-support-in-ios-with.html
http://discuss.cocos2d-x.org/t/porting-ios-game-to-android-multi-resolution-suppor/5260/5
https://www.youtube.com/watch?v=CH9Ct4R0nBM
https://github.com/SonarSystems/Cocos2d-x-v3-C---Tutorial-4---Multi-Resolution-Support
I even tried with newer version of cocos2d-x, but they also not providing anything which can support both ios and android screens.

I use the following bit of code in my AppDelegate:
void AppDelegate::multiresolutionSupport()
{
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
cocos2d::Size designSize = cocos2d::Size(320, 480);
cocos2d::Size resourceSize = cocos2d::Size(320, 480);
cocos2d::Size screenSize = glview->getFrameSize();
float margin1 = (320 + 640) / 2;
float margin2 = (768 + 1536) / 2;
if (screenSize.width < margin1) {
FileUtils::getInstance()->addSearchResolutionsOrder("SD");
} else if (480 <= screenSize.width && screenSize.width < margin2) {
FileUtils::getInstance()->addSearchResolutionsOrder("HD");
designSize = cocos2d::Size(screenSize.width / 2, screenSize.height / 2);
} else {
FileUtils::getInstance()->addSearchResolutionsOrder("HDR");
designSize = cocos2d::Size(screenSize.width / 4, screenSize.height / 4);
}
resourceSize = screenSize;
director->setContentScaleFactor(resourceSize.width / designSize.width);
glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::NO_BORDER);
}
Call it before loading any assets and you should have it working properly. I call it right after my glview is created in AppDelegate::applicationDidFinishLaunching().
How it works:
it uses a bunch of magic numbers to determine (roughly) what texture
resolution should we use: SD(#1), HD(#2) or HDR(#4) and then adjusts
design size accordingly, by dividing it on the content scale factor
it adds appropriate search paths to FileUtils it sets design
resolution and content scale factor for the engine

We are the team who made the multi resolution tutorial for the github link, it does support Android but the folders are just named using iOS naming conventions thats all.
Hope this helps.
Regards
Sonar Systems

It's working for me this way for Portrait mode:
Below the header :
typedef struct tagResource
{
cocos2d::CCSize size;
char directory[100];
} Resource;
static Resource smallResource = { cocos2d::CCSizeMake(640, 960),"iPhone" };
static Resource mediumResource = { cocos2d::CCSizeMake(768, 1024),"iPad"};
static Resource largeResource = { cocos2d::CCSizeMake(1536, 2048),"iPadhd" };
static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(768, 1024);
in applicationDidFinishLaunching() method :
// initialize director
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
pDirector->setOpenGLView(pEGLView);
CCSize frameSize = pEGLView->getFrameSize();
std::vector<std::string> searchPaths;
// Set the design resolution
pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionExactFit);
if (frameSize.height <= smallResource.size.height)
{
searchPaths.push_back(mediumResource.directory);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
pDirector->setContentScaleFactor(mediumResource.size.height/designResolutionSize.height);
}
else if (frameSize.height <= mediumResource.size.height)
{
searchPaths.push_back(mediumResource.directory);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
pDirector->setContentScaleFactor(mediumResource.size.height/designResolutionSize.height);
}
else
{
searchPaths.push_back(largeResource.directory);
CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
pDirector->setContentScaleFactor(largeResource.size.height/designResolutionSize.height);
}

Related

How does a computer resize an image?

Image resizing is nearly universal in any GUI framework. In fact, one of the first things you learn when starting out in web development is how to scale images using CSS or HTML's img attributes. But how does this work?
When I tell the computer to scale a 500x500 img to 100x50, or the reverse, how does the computer know which pixels to draw from the original image? Lastly, is it reasonably easy for me to write my own "image transformer" in another programming language without significant drops in performance?
Based on a bit of research, I can conclude that most web browser will use nearest neighbor or linear interpolation for image resizing. I've written a concept nearest neighbor algorithm that successfully resizes images, albeit VERY SLOWLY.
using System;
using System.Drawing;
using System.Timers;
namespace Image_Resize
{
class ImageResizer
{
public static Image Resize(Image baseImage, int newHeight, int newWidth)
{
var baseBitmap = new Bitmap(baseImage);
int baseHeight = baseBitmap.Height;
int baseWidth = baseBitmap.Width;
//Nearest neighbor interpolation converts pixels in the resized image to pixels closest to the old image. We have a 2x2 image, and want to make it a 9x9.
//Step 1. Take a 9x9 image and shrink it back to old value. To do this, divide the new width by old width (i.e. 9/2 = 4.5)
float widthRatio = (float)baseWidth/newWidth;
float heightRatio = (float)baseHeight/newHeight;
//Step 2. Perform an integer comparison for each pixel in old I believe. If we have a pixel in the new located at (4,5), then the proportional will be
//(.8888, 1.11111) which SHOULD GO DOWN to (0,1) coordinates on a 2x2. Seems counter intuitive, but imagining a 2x2 grid, (4.5) is on the left-bottom coordinate
//so it makes sense the to be on the (0,1) pixel.
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
Bitmap resized = new Bitmap(newWidth, newHeight);
int oldX = 0; int oldY = 0;
for (int i = 0; i < newWidth; i++)
{
oldX = (int)(i*widthRatio);
for (int j = 0; j < newHeight; j++)
{
oldY = (int)(j*heightRatio);
Color newColor = baseBitmap.GetPixel(oldX,oldY);
resized.SetPixel(i,j, newColor);
}
}
//This works, but is 100x slower than standard library methods due to GetPixel() and SetPixel() methods. The average time to set a 1920x1080 image is a second.
watch.Stop();
Console.WriteLine("Resizing the image took " + watch.Elapsed.TotalMilliseconds + "ms.");
return resized;
}
}
class Program
{
static void Main(string[] args)
{
var img = Image.FromFile(#"C:\Users\kpsin\Pictures\codeimage.jpg");
img = ImageResizer.Resize(img, 1000, 1500);
img.Save(#"C:\Users\kpsin\Pictures\codeimage1.jpg");
}
}
}
I do hope that someone else can come along and provide either a) a faster algorithm for nearest neighbor because I'm overlooking something silly, or b) another way that image scalers work that I'm not aware of. Otherwise, question... answered?

not finding ResolutionPolicy in cocos2d-x 3.0 for ios platform

I am not finding ResolutionPolicy inside CCEgleViewProtocol.
Can any one please help me in getting ResolutionPolicy, and setting images for mutiresolution.
I am using cocos2d-x 3.0 beta version.
Cocos2d-x 3.0 comes with the concepts of design resolution size (with associated resolution policy) and content scale factor that you can use as follow:
1) First you have to retrieve your glview
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLView::create("My game");
director->setOpenGLView(glview);
}
2) then you can access to real screen size
Size screenSize = glview->getFrameSize();
3) then you have to set your design size (it depends on your target devices and your assets resolution)
//set design size for iPad retina
Size designSize = Size(2048, 1536);
glview->setDesignResolutionSize (
designSize.width,
designSize.height,
ResolutionPolicy::SHOW_ALL <-- HERE YOU CAN SET RESOLUTION POLICY
);
4) Then you have to set your assets paths (landscape configuration is supposed here)
FileUtils::getInstance()->setSearchPaths({"assets"});
if (screenSize.height > 768) {
CCLOG("ipadhd chosed");
FileUtils::getInstance()->setSearchResolutionsOrder({"big"});
} else if (screenSize.height > 320) {
CCLOG("ipad or iphonehd chosed");
FileUtils::getInstance()->setSearchResolutionsOrder({"medium"});
} else {
CCLOG("iphone chosed");
FileUtils::getInstance()->setSearchResolutionsOrder({"small"});
}
This configuration presumes that your have put your assets in a 'assets' subfolder of 'Resources' folder. Then you have divided 'assets' into three subfolders called 'big', 'medium' and 'small'
5) Finally you have to set your content scale factor
director->setContentScaleFactor(screenSize.height/designSize.height);

used preferred back buffer height and width intersection is not working properly

i wanted to develop a game which can support all types of display sizes,
so i am using following code to multiscale.
graphics.PreferredBackBufferHeight = 768;
graphics.PreferredBackBufferWidth = 1024;
shootrect = new Rectangle( 900,650 , 100, 100);
touchrect = new Rectangle(mouse.X, mouse.Y, 0, 0);
if (mouse.LeftButton == ButtonState.Pressed && !jump && shootrect.Intersects(touchrect))
{
jump = true;
}
using this code i am trying to intersect the mouse coordinates with shootrect (which is shoot button for make player to jump) if i touch in that rect intersection is working but somewhere else in the same width and height touch is working
when i remove graphics.PreferredBackBufferHeight = 768;
graphics.PreferredBackBufferWidth = 1024; those lines from code intersection is working fine but my scaling is not proper for other size of screens
You need to scale your logic by hand (rectangles for instance) if you use those magic numbers creating them. I suggest create those relative to the screen width and height.
actually graphics.PreferredBackBufferHeight = 768;
graphics.PreferredBackBufferWidth = 1024; because of this rectangle intersection is working properly if set my screens resolution to 1024 x768 then it works well but my resoolution is 1980x1020 so its not working

How to draw smooth text in libgdx?

I try to draw simple text in my android game on libgdx, but it's look sharp. How to make text look smooth in different resolutions? My Code:
private BitmapFont font;
font = new BitmapFont();
font.scale((ppuX*0.02f));
font.draw(spb, "Score:", width/2-ppuX*2f, height-0.5f*ppuY);
font.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
This gets the texture used in a BitmapFont and changes its filtering to bilinear, allowing higher resulting image quality while both up- and downscaling it at the cost of slightly slower (the difference is usually not noticeable) GPU rendering.
One solution is to use the FreeType extension to libgdx, as described here. This allows you to generate a bitmap font on the fly from a .ttf font. Typically you would do this at startup time once you know the target resolution.
Here's an example:
int viewportHeight;
BitmapFont titleFont;
BitmapFont textFont;
private void createFonts() {
FileHandle fontFile = Gdx.files.internal("data/Roboto-Bold.ttf");
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile);
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = 12;
textFont = generator.generateFont(parameter);
parameter.size = 24;
titleFont = generator.generateFont(parameter);
generator.dispose();
}
You should definitly have a quick look on custom font shaders and/or DistanceField-Fonts. They're easy to understand and similarly easy to implement:
https://github.com/libgdx/libgdx/wiki/Distance-field-fonts
DistanceFieldFonts stay smooth, even when you upscale them:
Create a .fnt file using hiero which is provided by libgdx website.
Set the size of font to 150; it will create a .fnt file and a .png file.
Copy both files into your assets folder.
Now declare the font:
BitmapFont font;
Now in create method:
font = new BitmapFont(Gdx.files.internal("data/100.fnt"), false); // 100 is the font name you can give your font any name
In render:
font.setscale(.2f);
font.draw(batch, "whatever you want to write", x,y);
In general you don't get sharp text because you are designing your game for a certain resolution and when you move to a different device, Libgdx scales everything to match the new resolution. Even with linear filtering scaling is bad on text because round corners are easily distorted. In a perfect world you would create the content dynamically at runtime according to the number of pixels available to you and not a single automatic scale would be used.
This is the approach I'm using: Building everything for small screen (480 x 320), and when you open it on a bigger resolution, I load the BitmapFont with a higher size and apply and inverse scale to the one that Libgdx will later do automatically.
Here's an example to make things clearer:
public static float SCALE;
public static final int VIRTUAL_WIDTH = 320;
public static final int VIRTUAL_HEIGHT = 480;
public void loadFont(){
// how much bigger is the real device screen, compared to the defined viewport
Screen.SCALE = 1.0f * Gdx.graphics.getWidth() / Screen.VIRTUAL_WIDTH ;
// prevents unwanted downscale on devices with resolution SMALLER than 320x480
if (Screen.SCALE<1)
Screen.SCALE = 1;
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("data/Roboto-Regular.ttf"));
// 12 is the size i want to give for the font on all devices
// bigger font textures = better results
labelFont = generator.generateFont((int) (12 * SCALE));
// aplly the inverse scale of what Libgdx will do at runtime
labelFont.setScale((float) (1.0 / SCALE));
// the resulting font scale is: 1.0 / SCALE * SCALE = 1
//Apply Linear filtering; best choice to keep everything looking sharp
labelFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
}
Bitmap fonts are textures and if you want to make smaller textures look smoother when you are resizing them to bigger sizes you need to make sure you use the right texture filter.
This blog post deals with such issues
With many things deprecated after the update, this is what's working for me:
public void regenerateFonts(OrthographicCamera cam, Game game) {
int size = 18;
if (cam != null && game != null) {
// camera and game are provided, recalculate sizes
float ratioX = cam.viewportWidth / game.getW();
float ratioY = cam.viewportHeight / game.getH();
System.out.println("Ratio: [" + ratioX + ":" + ratioY + "]");
size *= ratioY;
}
// font parameters for this size
FreeTypeFontParameter params = new FreeTypeFontParameter();
params.flip = true; // if your cam is flipped
params.characters = LETTERS; // your String containing all letters you need
params.size = size;
params.magFilter = TextureFilter.Linear; // used for resizing quality
params.minFilter = TextureFilter.Linear; // also
// Lato Light generator
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/Lato-Light.ttf"));
// make the font
fontLatoLight = generator.generateFont(params);
generator.dispose(); // dispose to avoid memory leaks
}
And when you want to render it on the screen:
// text rendering
fontLatoLight.setColor(Color.WHITE); // set color here (has other overloads too)
fontLatoLight.draw(batch, "Hello World!", xCoord, yCoord);
My Solution for smooth text with Libgdx
I use BitmapFont and I generate 3 different size same fonts using Hiero tool
example Arial 16 , Arial 32, Arial 64
I put them in my assets file and use (load) only one of them depeding on the size of screen
if(Gdx.graphics.getWidth() < (480*3)/2)
{
textGametFont = BitmapFont(Gdx.files.internal(nameFont+16+".fnt"),
Gdx.files.internal(nameFont+16+".png"), false);
}else
{
if(Gdx.graphics.getWidth() < (3*920)/2)
{
textGametFont = new BitmapFont(Gdx.files.internal(nameFont+32+".fnt"),
Gdx.files.internal(nameFont+32+".png"), false);
}else
{
textGametFont = new BitmapFont(Gdx.files.internal(nameFont+64+".fnt"),
Gdx.files.internal(nameFont+64+".png"), false);
}
}
then I use this line of code to higher result quality of down and up Scaling
textGametFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
scale the image
to handle the size of the font for all type of resolution of device I use those two functions
public static float xTrans(float x)
{
return x*Gdx.graphics.width/(YourModel.SCREEN_WIDTH);
}
public static float yTrans(float y)
{
return y*Gdx.graphics.height/YourModel.SCREEN_Height;
}
the model screen resolution that i use is
SCREEN_WIDTH = 480
SCREEN_HEIGHT = 320
Set the scale to the font
textGametFont.setScale((xtrans(yourScale)+ ytrans(yourScale))/2f);
and finally draw your text
textGametFont.draw(batch, "WINNER !!", xTrans(250), yTrans(236));
Hope this was clear and helpful !!!
private BitmapFont font;
font = new BitmapFont();
font.scale((ppuX*0.02f));
font.draw(spb, "Score:", width/2-ppuX*2f, height-0.5f*ppuY);
Check out [this](http://www.badlogicgames.com/wordpress/?p=2300) blog post.
??? This just explains how to use the .scale() method which I'm stating is deprecated in the current release.
In scene2d, if you want apply antialiasing to all your labels, put this on constructor of your first screen:
skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
This is the first screen in my game:
...
public class MainMenuScreen implements Screen {
public MainMenuScreen() {
...
skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
}
}
Font name is in ui.json file, check for BitmapFont and Label$LabelStyle section:
"com.badlogic.gdx.graphics.g2d.BitmapFont": {
"default-font": {
"file": "default.fnt"
}
},
"com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle": {
"default": {
"font": "default-font",
"fontColor": "white",
}
},

Centering an image inside a Loader

I'm developing an ActionScript 3.0 app for Blackberry Playbook.
I have a Loader with a fixed size of 240x240px. The images that can be loaded inside are smaller or bigger than 240x240px, and also they aren't squared.
I use this code to resize that images:
private function onLoadedEvent(event:Event):void
{
var targetLoader:Loader = Loader(event.target.loader);
var factor:Number;
if (targetLoader.content.height > targetLoader.content.width) {
factor = 240/targetLoader.content.height;
}
else
{
factor = 240/targetLoader.content.width;
}
targetLoader.content.height = targetLoader.content.height * factor;
targetLoader.content.width = targetLoader.content.width * factor;
}
How can I do to set that images centered vertically inside that Loader?
I think this should do (putting it after the resize) unless I misunderstood your question:
targetLoader.content.y = (240 - targetLoader.content.height) / 2