I have a Cocos2d project and I want a constant background throughout the app. In the applicationDidFinishLaunching method of its delegate, I have replaced the line:
I have changed the pixelFormat of glView from kEAGLColorFormatRGB565 to kEAGLColorFormatRGBA8. When I make that change, glView becomes transparent and I can see through it, but the fps drops dramatically. If I don't make that change, the view doesn't become transparent, but I don't see the huge drop in fps. I'm talking about a significant drop in fps, from 59.0-60.0 to about 35.0-42.0.
I am using this code right below the addSubview line above to make the view transparent:
director.openGLView.opaque = NO;
The whole applicationDidFinishLaunching method looks like this:
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
// Init the window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Try to use CADisplayLink director
// if it fails (SDK < 3.1) use the default director
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
CCDirector *director = [CCDirector sharedDirector];
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
//
// Create the EAGLView manually
// 1. Create a RGB565 format. Alternative: RGBA8
// 2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGBA8 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
// attach the openglView to the director
[director setOpenGLView:glView];
glView.opaque = NO;
// // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
//
// VERY IMPORTANT:
// If the rotation is going to be controlled by a UIViewController
// then the device orientation should be "Portrait".
//
// IMPORTANT:
// By default, this template only supports Landscape orientations.
// Edit the RootViewController.m file to edit the supported orientations.
//
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
#else
[director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];
#endif
[director setAnimationInterval:1.0/60];
[director setDisplayFPS:YES];
// make the OpenGLView a child of the view controller
[viewController setView:glView];
//Required in iOS6, recommended in 4 and 5
[window setRootViewController:viewController];
// make the View Controller a child of the main window, needed for iOS 4 and 5
[window addSubview: viewController.view];
[window makeKeyAndVisible];
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Removes the startup flicker
[self removeStartupFlicker];
// Run the intro Scene
[[CCDirector sharedDirector] runWithScene: [Intro scene]];
}
Any ideas as to why this is happening? I can provide more code if need be.
I forgot to mention one other code change that I did. In CCDirector.m setGLDefaultValuesI changed this line from this:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
To this:
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Anytime you add an alpha channel with transparency, the OpenGL engine is going to have to perform some form (albeit default) alpha blending. This is math per pixel that it wasnt having to do in the non-RGBA (i.e. RGB 565) case. Anytime you add to the math needed by the engine frame rates are going to drop.
This is to be expected. The RGBA8888 framebuffer uses twice as much memory and the GPU needs to perform more work to render into this framebuffer. This is why RGB565 is the default format.
Related
I've been trying to get the NSOpenGLView to resize correctly when resizing the window, but I keep getting weird behaviour which I cannot explain. It looks like so:
Original (What it looks like at the beginning):
After resize:
This is my resize code:
- (void)reshape
{
[super reshape];
CGLLockContext([[self openGLContext] CGLContextObj]);
NSRect viewRectPoints = [self bounds];
#if SUPPORT_RETINA_RESOLUTION
NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints];
#else //if !SUPPORT_RETINA_RESOLUTION
NSRect viewRectPixels = viewRectPoints;
#endif // !SUPPORT_RETINA_RESOLUTION
[self resizeWithWidth:viewRectPixels.size.width
AndHeight:viewRectPixels.size.height];
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
- (void) resizeWithWidth:(GLuint)width AndHeight:(GLuint)height
{
glViewport(0, 0, width, height);
m_width = width;
m_height = height;
}
and I'm using: "glViewport(0, 0, m_width, m_height);" whenever I call glDrawArrays();
Can anyone help?
When resizing the window you should also set the projection matrix to reflect the new dimensions. You didn't post your setup/drawing code, but usually that looks something like:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(...); // or glFrustum(), glOrtho(), gluOrtho2D(), ...
glMatrixMode(GL_MODELVIEW);
Seriously, in these days you might want to consider to leave NSOpenGLView behind and move to CAOpenGLLayer directly.
I've had too many issues with this silly class to bother any more about NSOpenGLView and in layer backed views particularly having a CAOpenGLLayer IMHO just gives you more flexibility - and control.
(and less bugs - try getting NSOpenGLView to work in a layer backed view hierarchy under 10.9 or pre..).
Plus more functionality right out of the box - or at least under your finger tips (like built-in CVDisplayLink support).
Just my 2c.
I tried rotate image and view, only view or only image, but I have not got view that I need. I want just image with faces on the top of the screen, I can rotate a window, but I use my code not in AppDelegate and also I not want to rotate other elements, my code here, it rotate all view .
-(void)markFaces:(UIImageView *)facePicture
{
// draw a CI image with the previously loaded face detection picture
CIImage* image = [CIImage imageWithCGImage:facePicture.image.CGImage];
// create a face detector - since speed is not an issue we'll use a high accuracy
// detector
CIDetector* detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil options:[NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy]];
// create an array containing all the detected faces from the detector
NSArray* features = [detector featuresInImage:image];
// we'll iterate through every detected face. CIFaceFeature provides us
// with the width for the entire face, and the coordinates of each eye
// and the mouth if detected. Also provided are BOOL's for the eye's and
// mouth so we can check if they already exist.
for(CIFaceFeature* faceFeature in features)
{
// get the width of the face
CGFloat faceWidth = faceFeature.bounds.size.width;
// create a UIView using the bounds of the face
UIView* faceView = [[UIView alloc] initWithFrame:faceFeature.bounds];
// add a border around the newly created UIView
faceView.layer.borderWidth = 1;
faceView.layer.borderColor = [[UIColor redColor] CGColor];
faceView.backgroundColor = [UIColor blackColor];
// add the new view to create a box around the face
//[faceView setTransform:CGAffineTransformMakeScale(-1, -1)];
[self.view addSubview:faceView];
[self.view setTransform:CGAffineTransformMakeScale(-1, -1)]; // !!!!
}
-(void)faceDetector
{
// Load the picture for face detection
UIImageView* image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test1.jpeg"]];
// Draw the face detection image
[self.view addSubview:image];
// Execute the method used to markFaces in background
[self performSelectorInBackground:#selector(markFaces:) withObject:image];
// flip image on y-axis to match coordinate system used by core image
[image setTransform:CGAffineTransformMakeScale(1, -1)];//!!
}
I created an empty iOS project and then added a custom GLView class which is then added to AppDelegate. I have following questions:
1) How do I enable hi-res retina mode on iPhone 4? Currently I am using the following code to check for device:
CGRect screenBounds = [[UIScreen mainScreen] bounds];
self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
// Override point for customization after application launch.
_view = [[GLView alloc] initWithFrame:screenBounds];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
NSLog(#"iPad detected");
}
else {
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2) {
NSLog(#"iPhone4 detected");
_view.contentScaleFactor = [[UIScreen mainScreen] scale];
}
else {
NSLog(#"iPhone detected");
}
}
self.window.backgroundColor = [UIColor whiteColor];
//self.window.rootViewController = [[[UIViewController alloc] initWithNibName:nil bundle:nil] autorelease];
[self.window addSubview:_view];
But even after setting content factor it is drawing pretty poor quality polygons with jagged edges as shown in the image below:
http://farm8.staticflickr.com/7358/8725549609_e2ed1e0e2a_b.jpg
Is there any way to set the resolution to 960x640 instead of the default 480x320 ?
Please note that I can not use "someImage#2x.png" because I am generating images at runtime in the render buffer.
2) Second problem I am having is this warning message:
"Application windows are expected to have a root view controller at the end of application launch"
Thank you for your time.
As for the first question I do not know the pipeline of GLView initializer but content scale must be set before the render buffer is made (usually before renderbufferStorage:: method). To see if dimensions of the buffer are correct (should be 960x640) use function:
GLint width;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width)
Even if the buffer is retina and dimensions are correct those polygons might still be jagged if you do not use any sort of anti-alias. The easiest way to make an antialiased GL view in iOS is probably multisampling, try searching for glResolveMultisampleFramebufferAPPLE() (you will need a few more lines beside this one though).
iPad App setup: SceneA contains layerA - 1024x768. Push a button in layerA, layerB drops down over top using a CCMoveTo action. LayerB is only 800x600 so you can see layerA behind it (think of an overlayed pause screen type effect). LayerB contains an 800x600 sprite that the user can zoom in on by pressing a button. The zoom effect is simply a combination of CCScaleTo and CCMoveTo to keep it centered on the part it's zooming in on. However, when the sprite scales, so does layerB overtop of layerA. Is there a way to scale the sprite within a contained window?
LayerB should use the GL_SCISSOR_TEST to trim the outside of itself. You can easily google for more information about it, it basically defines a rect and then uses glScissoron it to remove the outside. I have a class I extend when I need to do this, that goes as follows:
//
// CCNodeClip.h
//
// Created by Ignacio Orlandoni on 7/29/11.
//
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface CCNodeClip : CCLayer {
}
-(void)preVisit;
-(void)postVisit;
#end
-
//
// CCNodeClip.m
//
// Created by Ignacio Orlandoni on 7/29/11.
//
#import "CCNodeClip.h"
#implementation CCNodeClip
-(void)visit {
[self preVisit];
[super visit];
[self postVisit];
}
-(void)preVisit {
if (!self.visible)
return;
glEnable(GL_SCISSOR_TEST);
CGPoint position = [self position];
//I don't remember if this rect really serves for both orientations, so you may need to change the order of the values here.
CGRect scissorRect = CGRectMake(position.x, position.y, [self contentSize].width, [self contentSize].height);
// CCLOG(#"Scrissor Rect: X: %02f, Y:%02f, W: %02f, H: %02f", scissorRect.origin.x, scissorRect.origin.y, scissorRect.size.width, scissorRect.size.height);
// Handle Retina
scissorRect = CC_RECT_POINTS_TO_PIXELS(scissorRect);
glScissor((GLint) scissorRect.origin.x, (GLint) scissorRect.origin.y,
(GLint) scissorRect.size.width, (GLint) scissorRect.size.height);
}
-(void)postVisit {
glDisable(GL_SCISSOR_TEST);
}
#end
With that imported into LayerB, you can now define it as a CCNodeClip instead of CCLayer.
Some links...
glScissor << cocos2d Forum
Circle shape clipping with opengl-es in cocos2d << StackOverflow
Cocos2d iPhone - Sprite cliping/mask/frame << StackOverflow
Another Cocos2D gem: ClippingNode << Learn-Cocos2d.com
As a side note...
CCScaleTo + CCMoveTo can be avoided if the anchor point for the sprite is centered, so the image stays centered in the container as it scales. (.anchorPoint = ccp(0.5, 0.5);)
I have a Cocos2d project and I want a constant background throughout the app. In the applicationDidFinishLaunching method of its delegate, I have replaced the line:
[viewController setView:glView];
with
[[viewController view] addSubview:glView];
because I have added subviews to the RootViewController's view in it's initWithNib, and those changes are lost if the view is replaced with glView.
I have also changed the pixelFormat of glView from kEAGLColorFormatRGB565 to kEAGLColorFormatRGBA8. When I make that change, glView becomes transparent and I can see through it, but the fps drops dramatically. If I don't make that change, the view doesn't become transparent, but I don't see the huge drop in fps. I'm talking about a significant drop in fps, from 59.0-60.0 to about 35.0-42.0.
I am using this code right below the addSubview line above to make the view transparent:
glClearColor(0, 0, 0, 0);
director.openGLView.backgroundColor = [UIColor clearColor];
director.openGLView.opaque = NO;
The last two lines are the culprits; commenting them out (both, not just one) causes the large drop in fps, while commenting out the glClearColor line has no effect on fps.
The whole applicationDidFinishLaunching method looks like this:
- (void) applicationDidFinishLaunching:(UIApplication*)application {
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if(![CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeDefault];
CCDirector *director = [CCDirector sharedDirector];
// Init the View Controller
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
// Create the EAGLView manually
// 1. Create a RGB565 format. Alternative: RGBA8
// 2. depth format of 0 bit. Use 16 or 24 bit for 3d effects, like CCPageTurnTransition
//
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGBA8
depthFormat:0
];
// attach the openglView to the director
[director setOpenGLView:glView];
if(![director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
#if GAME_AUTOROTATION == kGameAutorotationUIViewController
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
#else
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
#endif
[director setAnimationInterval:1.0/60];
[director setDisplayFPS:YES];
// make the OpenGLView a child of the view controller
[[viewController view] addSubview:glView];
//***make glView transparent***
glClearColor(0, 0, 0, 0);
director.openGLView.backgroundColor = [UIColor clearColor];
director.openGLView.opaque = NO;
// make the View Controller a child of the main window
[window addSubview:viewController.view];
[window makeKeyAndVisible];
// Default texture format for PNG/BMP/TIFF/JPEG/GIF images
// It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
// You can change anytime.
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// Removes the startup flicker
[self removeStartupFlicker];
// Run the intro Scene
[[CCDirector sharedDirector] runWithScene:[MainMenu scene]];
}
Any ideas as to why this is happening? I can provide more code if need be.
If you're testing this on a 1st or 2nd generation device, the drop in framerate is to be expected. Nothing you can do about it. These devices are heavily fillrate-limited, and a transparent 32-bit GL view is just asking too much of the device.
If this happens on a 3rd or even 4th generation device, then there's got to be something wrong but I couldn't begin to tell what that might be.
If you're testing the performance on the Simulator, don't. It's irrelevant.