Cocos2dx. How to get length of 1cm(in real life) in pixel for any screen resolutions? - cocos2d-iphone

I have admob banner set up at the bottom of the screen.
I want to offset everything so that nothing is covered up by the banner.
I have no idea how to get the height of the admob banner DYNAMICALLY.
For iphone4, 120 is the height of admob, but for iphone 6, it's 100.
I guess it's something related to screen being scaled, but I couldn't figure it out.
My screen is set up like this in AppDelegate.cpp
cocos2d::Size designResolutionSize = cocos2d::Size(1136, 768);
and
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);

There is no real-metric like cm option in cocos2dx and in fact we don't need it.
But cocos2D-x 2.x and 3.x have very easy solution for multi-resolution problem ( either iDevices or Android devices) As you saw in Multi-resolution support document.
In fact you just need to set your DesignResolution and then just imagine your target device will has this resolution.
If target device really has this resolution ( or any other with same ratio) cocos2d will handle to fix screen and your game looks same in all devices.
And when ratio of target device is different, you have many option ( policy) to manage that.
For example if you use Exact fit policy, cocos2d will force your game ( and design) to fit target device screen (without that black boarder).
Exact fit
The entire application is visible in the specified area without trying
to preserve the original aspect ratio. Distortion can occur, and the
application may appear stretched or compressed.
For more detail just take a look at the official wiki.
Beside all above word, I found This Link (from V-Play engine) and Its Safe Zone definition really interesting and I highly recommend you to use recommended-resolution-value of this page for your work as I did.
Although this link is from another engine but the description helps you understand everything better. Here is a map between this page terms to cocos2d-x terms:
V-Play::letterbox => Cocos2dx::Show All
V-Play::ZoomToBiggerSide => Cocos2dx::NoBorder
In addition you did ask about required image size in cocos2dx development:
As you know the different size of image is not about game-look in different resolutions and you can publish your game with one size for each asset and your game/app looks good in all resolution with above description for resolution Policies.
But we need multiple image-size for each asset, to optimize memory usage. in this case ( as cocso2dx solution) we check device size and mark appropriate set of image ( each image set is in one folder with same-structure/different-size like HDR/HD/SD) as default folder of resource:
CCSize frameSize = pEGLView->getFrameSize();
if (frameSize.height > mediumResource.size.height)
{
searchPath.push_back(largeResource.directory); //mark HDR default
pDirector->setContentScaleFactor(largeResource.size.height/designResolutionSize.height); //handle scaling because of different between our programming-design-resolution and artist-design-canvase-resolution
}
else ...

Related

How can I horizontally mirror video in DirectShow?

I need to display the local webcam stream on the screen,
horizontally flipped,
so that the screen appears as a mirror.
I have a DirectShow graph which does all of this,
except for mirroring the image.
I have tried several approaches to mirror the image,
but none have worked.
Approach A: VideoControlFlag_FlipHorizontal
I tried setting the VideoControlFlag_FlipHorizontal flag
on the output pin of the webcam filter,
like so:
IAMVideoControl* pAMVidControl;
IPin* pWebcamOutputPin;
// ...
// Omitting error-handing for brevity
pAMVidControl->SetMode(pWebcamOutputPin, VideoControlFlag_FlipHorizontal);
However, this has no effect.
Indeed, the webcam filter claims to not have this capability,
or any other capabilities:
long supportedModes;
hr = pAMVidControl->GetCaps(pWebcamOutputPin, &supportedModes);
// Prints 0, i.e. no capabilities
printf("Supported modes: %ld\n", supportedModes);
Approach B: SetVideoPosition
I tried flipping the image by flipping the rectangles passed to SetVideoPosition.
(I am using an Enhanced Video Renderer filter, in windowless mode.)
There are two rectangles:
a source rectangle and a destination rectangle.
I tried both.
Here's approach B(i),
flipping the source rectangle:
MFVideoNormalizedRect srcRect;
srcRect.left = 1.0; // note flipped
srcRect.right = 0.0; // note flipped
srcRect.top = 0.0;
srcRect.bottom = 0.5;
return m_pVideoDisplay->SetVideoPosition(&srcRect, &destRect);
This results in nothing being displayed.
It works in other configurations,
but appears to dislike srcRect.left > srcRect.right.
Here's approach B(ii),
flipping the destination rectangle:
RECT destRect;
GetClientRect(hwnd, &destRect);
LONG left = destRect.left;
destRect.left = destRect.right;
destRect.right = left;
return m_pVideoDisplay->SetVideoPosition(NULL, &destRect);
This also results in nothing being displayed.
It works in other configurations,
but appears to dislike destRect.left > destRect.right.
Approach C: IMFVideoProcessorControl::SetMirror
IMFVideoProcessorControl::SetMirror(MF_VIDEO_PROCESSOR_MIRROR)
sounds like what I want.
This IMFVideoProcessorControl interface is implemented by the Video Processor MFT.
Unfortunately, this is a Media Foundation Transform,
and I can't see how I could use it in DirectShow.
Approach D: Video Resizer DSP
The Video Resizer DSP
is "a COM object that can act as a DMO",
so theoretically I could use it in DirectShow.
Unfortunately, I have no experience with DMOs,
and in any case,
the docs for the Video Resizer don't say whether it would support flipping the image.
Approach E: IVMRMixerControl9::SetOutputRect
I found
IVMRMixerControl9::SetOutputRect,
which explicitly says:
Because this rectangle exists in compositional space,
there is no such thing as an "invalid" rectangle.
For example, set left greater than right to mirror the video in the x direction.
However, IVMRMixerControl9 appears to be deprecated,
and I'm using an EVR rather than a VMR,
and there are no docs on how to obtain a IVMRMixerControl9 anyway.
Approach F: Write my own DirectShow filter
I'm reluctant to try this one unless I have to.
It will be a major investment,
and I'm not sure it will be performant enough anyway.
Approach G: start again with Media Foundation
Media Foundation would possibly allow me to solve this problem,
because it provides "Media Foundation Transforms".
But it's not even clear that Media Foundation would fit all my other requirements.
I'm very surprised that I am looking at such radical solutions
for a transform that seems so standard.
What other approaches exist?
Is there anything I've overlooked in the approaches I've tried?
How can I horizontally mirror video in DirectShow?
If Option E does not work (see comment above; neither source nor destination rectangle allows mirroring), and given that it's DirectShow I would offer looking into Option F.
However writing a full filter might be not so trivial if you never did this before. There are a few shortcuts here though. You don't need to develop a full filter: similar functionality can be reached at least using two alternate methods:
Sample Grabber Filter with a ISampleGrabberCB::SampleCB callback. You will find lots of mentions for this technic: when inserted into graph your code can receive a callback for every processed frame. If you rearrange pixels in frame buffer within the callback, the image will be mirrored.
Implement a DMO and insert it into filter graph with the help of DMO Wrapper Filter. You will have a chance to similarly rearrange pixels of frames, with a bit more of flexibility at the expense of more code to write.
Both mentioned will be easier to do because you don't have to use DirectShow BaseClasses, which are notoriously obsolete in 2020.
Both mentioned will not require to understand data flow in DirectShow filter. Both and also developing full DirectShow filter assume that your code supports rearrangement in a limited set of pixel formats. You can go with 24-bit RGB for example, or typical formats of webcams such as NV12 (nowadays).
If your pixel data rearrangement is well done without need to super-optimize the code, you can ignore performance impact - either way it can be neglected in most of the cases.
I expect integration of Media Foundation solution to be more complicated, and much more complicated if Media Foundation solution is to be really well optimized.
The complexity of the problem in first place is the combination of the following factors.
First, you mixed different solutions:
Mirroring right in web camera (driver) where your setup to mirror results that video frames are already mirrored at the very beginning.
Mirroring as data flows through pipeline. Even though this sounds simple, it is not: sometimes the frames are yet compressed (webcams quite so often send JPEGs), sometimes frames can be backed by video memory, there are multiple pixel formats etc
Mirroring as video is presented.
Your approach A is #1 above. However if there is no support for the respected mode, you can't mirror.
Mirroring in EVR renderer #3 is apparently possible in theory. EVR used Direct3D 9 and internally renders a surface (texture) into scene so it's absolutely possible to setup 3D position of the surface in the way that it becomes mirrored. However, the problem here is that API design and coordinate checks are preventing from passing mirroring arguments.
Then Direct3D 9 is pretty much deprecated, and DirectShow itself and even DirectShow/Media Foundation's EVR are in no way compatible to current Direct3D 11. Even though a capability to mirror via hardware might exist, you might have hard time to consume it through the legacy API.
As you want a simple solution you are limited with mirroring as the data is streamed through, #2 that is. Even though this is associated with reasonable performance impact you don't need to rely on specific camera or video hardware support: you just swap the pixels in every frame and that's it.
As I mentioned the easiest way is to setup SampleCB callback using either 24-bit RGB and/or NV12 pixel format. It depends on whatever else your application is doing too, but with no such information I would say that it is sufficient to implement 24-bit RGB and having the video frame data you would just go row by row and swap the three byte pixel data width/2 times. If the application pipeline allows you might want to have additional code path to flip NV12, which is similar but does not have the video to be converted to RGB in first place and so is a bit more efficient. If NV12 can't work, RGB24 would be a backup code path.
See also: Mirror effect with DirectShow.NET - I seem to already explained something similar 8 years ago.

How do I change the resolution of a window in SDL? Everything is too large

I am making a game in SDL and had an oversight of the resolution. Everything (the sprites) are too large and I want to know if I can bump up the resolution so everything is smaller without changing every sprite or modifying how the surfaces are created? Here is what I am dealing with:
Since SDL 2.0.0, you can use the function SDL_RenderSetLogicalSize to set a device independent resolution for rendering.
This way, you can set up your renderer with the desired target resolution and draw everything as if you are working with that resolution.
I cite the official documentation:
This is nice in that you can change the logical rendering size to achieve various effects, but the primary use is this: instead of trying to make the system work with your rendering size, we can now make your rendering size work with the system. On my 1920x1200 monitor, this app thinks it's talking to a 640x480 resolution now, but SDL is using the GPU to scale it up to use all those pixels. Note that 640x480 and 1920x1200 aren't the same aspect ratio: SDL takes care of that, too, scaling as much as possible and letterboxing the difference.
Please, note that you can control how scaling happens with a bunch of hints, as an example SDL_HINT_RENDER_SCALE_QUALITY.
Yes you can bumb the resolution up. It would make your sprite looks smaller if you're using fullscreen mode, just like when you adjust your monitor resolution. When you're in Window mode, the window would get bigger but the sprite would look the same.
You can resorts to virtual resolution as #skypjack mentioned as well. One approach is to use SDL_RenderSetLogicalSize(), another is to do render target.
You can also resize the sprite, either online (specify the target rect which is smaller than the source), or off-line (using batch image processing tool like ACDSee or Photoshop).
In the end you'd have more space to fill.
My advise is, when you're working with graphics, try having a target resolution in mind, 1280x720 or 800x600 for example. Then designing all the asset around this resolution. In the end you will have the assets that fits well together without resorting to programming trick. Then if you run into devices with different resolution, you can use the 'virtual resolution' I mentioned above to fix it. There are a few tricks like safe-frame or letterboxing that would be needed too, but let's leave it as an advance question :-).

Cocos2d-x coordinates

I just started with Cocos2D-x after some years using Cocos2d-iPhone/swift/spritebuilder.
What I notice is that the coordinate system in X seems not to use the POINT system common since iOS development. Ie a box of 10x10 points used to be 10x10 pixels on 1x devices, 20x20 pixels on 2x devices and so on.
So my question is, does cocos2d-x only deal with pixels? How do we address this in code - because we used to be able to put a sprite at say 50x20 and it would end up in the right spot on any device regardless of resolution. Not possible in cocos2d-x? I have 3.5.
What would be related is this document, however it says that it is outdated. Is there a newer document anywhere? I really don't find anything else. http://www.cocos2d-x.org/wiki/Multi_resolution_support
You can look into using different asset folders for various resolution sizes. So you might have "/sd/" for < 480 height, "/hd/" for < 800 height, and "/ipadhd/" for others.
FileUtils::getInstance()->setSearchResolutionsOrder(...)
You can also change the content scale factor yourself in the AppController.mm using:
// should behave as if all art is #1x device
Director::getInstance()->setContentScaleFactor(1.0);
// should behave as if all art is #2x device
Director::getInstance()->setContentScaleFactor(2.0);
// should behave as if all art is #4x
Director::getInstance()->setContentScaleFactor(4.0);
This hasn't been updated yet, but still has some info:
http://www.cocos2d-x.org/wiki/Multi_resolution_support

Does "Design Resolution Size" affect how sprites created using OpenGL renders them on screen?

In cocos2d-x, there is the the concept of "Design Resolution Size", which lets you pick the appropriate asset, depending on the size of the screen, and you can apply the appropriate content scaling factor.
Here is the problem:
I draw a 2d Sin Curve by passing in a set of vertices. These vertices are computed for a screen of 480x320.
What happens when I run it on a device which has a resolution of 1920x1200, even though the design resolution is set to 480x320 ? Do I have to recompute the vertices so that the same number of crests / troughs are seen on the higher resolution device, or is there some way to do this without extra computation ?
I don't have any more devices to test this, so I don't know how to figure this out.
EDIT: I now use cocos2d-x v3.
Anything drawn directly/solely with OpenGL will bypass/ignore any and all cocos2d internal settings and code paths, such as design resolution.
You can always use a simulator to test your resolution-specific code. For iOS the simulator comes with Xcode, for Android use the Emulator.
After purchasing and testing this on a number of devices with cocos2d-x v3, I find that scaling is handled automatically. Regardless of the resolution of the actual device, my openGl draw commands seem to result in the same output on all devices. It appears that cocos2d-x does something internally, so things looks the same on all devices.

is it possible to use iPhone 4/5's full native resolution instead of using the half-size coordinates of older iPhones

The problem is, Cocos seems to think retina devices are the same resolution as standard devices. If you draw a sprite at 768,1024 on the ipad, it will put it at the upper right corner. If you draw a sprite at 768,1024 on the retina ipad, content scaling makes it so it also puts it in the upper right corner. Yet if you draw a sprite on the retina iphone 5 at 640,1136 it isn't in the upper right corner, its off the screen by 2x the distance. In order to put it in the corner you have to draw it at 320,568 because of the content scaling.
I do have a Default-568h#2x.png image, and I am on version 2.1.
My question is: Is there a way to get Cocos2d to make it so that drawing a sprite at 640,1136 on an iPhone5 will result in the sprite being in the upper right corner?
Is it possible to set up a cocos2d custom GL projection and set winSizeInPoints to equal winSizeInPixels and content scale 1.0 so that you can use the iPhone 4/5's full native resolution instead of using the half-size coordinates of older iPhones.
You can easily do this by changing the iPad suffix to use "-hd" via CCFileUtils. That way iPad devices will load the regular -hd assets for Retina iPhones.
Update regarding comments:
The positions on devices is measured in points, not pixels. So a non-retina iPad and a retina iPad both have a point resolution of 1024x768. This is great exactly because it makes adapting to screens with different pixel densities a no-brainer. This also works on the iPhone devices.
My suspicion is that you simply haven't added the Default-568h#2x.png launch image to your project yet, which may cause the widescreen devices to be treated differently.
And specifically on older cocos2d versions dated before iPhone 5 there's a bug that will treat the iPhone 5 as a non-Retina device, proper default image or not.
Yes You can share, easy way to do this is put all common sprite in sprite sheet and in runtime check if iPad, if yes then load iPhone HD sheet. We did this in many project and worked.
if(IS_IPAD)
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"GameSpriteSheet-hd.plist"];
}
else
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"GameSpriteSheet.plist"];
}
For background image, good to have separate iPad image, if scaling not look bad then you can scale image at runtime.
As far as I can understand what you are trying to do, the following approach should work:
call [director enableRetinaDisplay:NO] when setting up your CCDirector;
hack or override the following methods in CCDirector's so that winSizeInPixels is defines as the full screen resolution:
a. setContentScaleFactor:;
b. reshapeProjection:;
c. setView:;
Step 1 will make sure that no scaling factor is ever applied when rendering sprites or doing calculations; Step 2 will ensure that the full screen resolution is used whenever required (e.g., when defining the projection, but likely elsewhere as well).
About Step 2, you will notice that all listed methods show a statement like this:
winSizeInPixels_ = CGSizeMake( winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height * __ccContentScaleFactor );
__ccContentScaleFactor is made equal to 1 by step 1, and you should leave it like that; you could, e.g. customise winSizeInPixels calculation to your aim, like this:
if (<IPHONE_4INCHES>)
winSizeInPixels_ = CGSizeMake( winSizeInPoints_.width * 2, winSizeInPoints_.height * 2 );
else
winSizeInPixels_ = CGSizeMake( winSizeInPoints_.width * __ccContentScaleFactor, winSizeInPoints_.height * __ccContentScaleFactor );
Defining a custom projection would unfortunately not work because winSizeInPixels is always calculated based on __ccContentScaleFactor; but, __ccContentScaleFactor is also used everywhere in Cocos2D to position/size sprites and the likes.
A final note on implementation, you could hack this changes into the existing CCDirectorIOS class or you could derive from it your own MYCCDirectorIOS and override the methods there.
Hope it helps.