For some reason, my OpenGL app is getting the wrong bounds information for CAEAGLLayer when running in the ios6 4-Inch Retina simulator.
The CAEAGLLayer bounds are printed out as
layer bounds are: (0.000000,0.000000), (320.000000,480.000000)
from this code:
- (id)initWithCoder:(NSCoder*)coder {
if ((self = [super initWithCoder:coder])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
printf("layer bounds are: (%f,%f), (%f,%f)\n", eaglLayer.bounds.origin.x, eaglLayer.bounds.origin.y, eaglLayer.bounds.size.width, eaglLayer.bounds.size.height );
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
animationInterval = 1.0 / 60.0;
}
return self;
}
The window contents are then shifted up, and 0,0 is no longer at the right location.
Anyone have any ideas why the CAEAGLLayer is being set to the incorrect width/height?
Thanks
Ah, someone else had this problem as well. Couldn't find it when I searched before.
This is the solution:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window.frame = CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, [[UIScreen mainScreen]bounds].size.height);
}
From here: How to make a uitableview in interface builder compatible with a 4 inch iPhone
Related
I am new to iOS, trying to create custom camera using AvCam. I am having trouble getting landscape orientation preview -- it rotates the view 90 degree clockwise and shows it on a half screen.
I get this message --
WARNING: -[ setOrientation:] is deprecated.
Please use AVCaptureConnection's -setVideoOrientation:
AVCaptureConnection already sets orientation, so I have no clue what am I supposed else.
I know this question was asked lots of times for previous versions of iOS (4,5), but non of those techniques/codes worked for me (iOS 6).
Original code (did not make any changes from Apple)
if ([self captureManager] == nil) {
AVCamCaptureManager *manager = [[AVCamCaptureManager alloc] init];
[self setCaptureManager:manager];
[manager release];
[[self captureManager] setDelegate:self];
if ([[self captureManager] setupSession]) {
// Create video preview layer and add it to the UI
AVCaptureVideoPreviewLayer *newCaptureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:[[self captureManager] session]];
UIView *view = [self videoPreviewView];
CALayer *viewLayer = [view layer];
[viewLayer setMasksToBounds:YES];
CGRect bounds = [view bounds];
[newCaptureVideoPreviewLayer setFrame:bounds];
if ([newCaptureVideoPreviewLayer isOrientationSupported]) {
[newCaptureVideoPreviewLayer setOrientation:AVCaptureVideoOrientationPortrait];
}
[newCaptureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[viewLayer insertSublayer:newCaptureVideoPreviewLayer below:[[viewLayer sublayers] objectAtIndex:0]];
[self setCaptureVideoPreviewLayer:newCaptureVideoPreviewLayer];
AVCaptureConnection chunk:
-(void)startRecordingWithOrientation:(AVCaptureVideoOrientation)videoOrientation; {
AVCaptureConnection *videoConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self movieFileOutput] connections]];
if ([videoConnection isVideoOrientationSupported])
[videoConnection setVideoOrientation:videoOrientation];
[[self movieFileOutput] startRecordingToOutputFileURL:[self outputFileURL] recordingDelegate:self];
}
Last time i also stumbled upon this issue. I solved this problem by doing two things
Getting the right orientation
Replace
if ([newCaptureVideoPreviewLayer isOrientationSupported]) {
[newCaptureVideoPreviewLayer setOrientation:AVCaptureVideoOrientationPortrait];
}
With
if ([newCaptureVideoPreviewLayer.connection isVideoOrientationSupported]) {
[newCaptureVideoPreviewLayer.connection setVideoOrientation:[UIDevice currentDevice].orientation];
}
Force the update of the video orientation during the initialization to catch video output in landscape mode by triggering
- (void)deviceOrientationDidChange manually within AVCaptureManager.m
I added it to:
- (BOOL) setupSession
{
BOOL success = NO;
...
AVCamRecorder *newRecorder = [[AVCamRecorder alloc] initWithSession:[self session] outputFileURL:self.lastOutputfileURL];
[newRecorder setDelegate:self];
[self performSelector:#selector(deviceOrientationDidChange)];
...
return success;
}
So, here's a workaround, but I am sure that there must be better solution than this. I got part of the code from this question :
iPhone App - Show AVFoundation video on landscape mode
But had to adjust frame for every orientation in order to make it work on iOS6 (and it still shows a warning):
-(void)willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
[CATransaction begin];
if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft){
captureVideoPreviewLayer.orientation = UIInterfaceOrientationLandscapeLeft;
captureVideoPreviewLayer.frame = CGRectMake(0, 0, 480, 320);
} else if (toInterfaceOrientation==UIInterfaceOrientationPortrait){
captureVideoPreviewLayer.orientation = UIInterfaceOrientationPortrait;
captureVideoPreviewLayer.frame = CGRectMake(0, 0, 320, 480);
} else if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight){
captureVideoPreviewLayer.orientation = UIInterfaceOrientationLandscapeRight;
captureVideoPreviewLayer.frame = CGRectMake(0, 0, 480, 320);
}
[CATransaction commit];
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
I have Automatic Reference Counting and Zombies enabled...
I keep getting EXC BAD ACCESS to different points in the code, most of the time with no further information coming from zombies.
The objective is to draw a rectangle to the screen with a texture on it that is loaded from an image. It does actually work! But often it is corrupted (the image and the vectors) and then often I just get the exc bad access warning.
I have this sort of structure...
App Delegate Class Declaration:
GWBackgroundScene* background;
EAGLContext *context;
GLKView *view;
GLKViewController *controller;
UIWindow *window;
and then window is made into a property and synthesized.
The did Finish Launching With Options:
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:context];
view = [[GLKView alloc] initWithFrame:[[UIScreen mainScreen] bounds] context:context];
view.delegate = self;
controller = [[GLKViewController alloc] init];
[controller shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait];
controller.delegate = self;
controller.view = view;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = controller;
[self.window makeKeyAndVisible];
background = [[GWBackgroundScene alloc] initWithImage:[UIImage imageNamed:#"DSC_0059.jpg"]];
The AppDelegate acts as an OpenGL delegate and OpenGL calls a function called 'render' in the class which then calls [background render];
My GWBackgroundScene class:
#interface GWBackgroundScene : NSObject
{
GLKTextureInfo *texture;
NSMutableData* vertexData;
NSMutableData* textureCoordinateData;
}
#property(readonly) GLKVector2 *vertices;
#property(readonly) GLKVector2 *textureCoordinates;
-(void) render;
-(id) initWithImage: (UIImage*)image;
Initialises with:
self = [super init];
if(self != nil)
{
texture = [GLKTextureLoader textureWithCGImage:image.CGImage options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:GLKTextureLoaderOriginBottomLeft] error:&error];
vertexData = [NSMutableData dataWithLength:4];
textureCoordinateData = [NSMutableData dataWithLength:4];
self.vertices[0] = GLKVector2Make(-2.0,3.0);
...
self.textureCoordinates[0] = GLKVector2Make(0,0);
...
}
return self;
and has these two functions for dealing with the vector and texture information
- (GLKVector2 *)vertices {
return [vertexData mutableBytes];
}
- (GLKVector2 *)textureCoordinates {
return [textureCoordinateData mutableBytes];
}
and then the render function (which is called by OpenGL via its delegate (the App delegate) uses:
texture:
GLKBaseEffect *effect = [[GLKBaseEffect alloc] init];
effect.texture2d0.envMode = GLKTextureEnvModeReplace;
effect.texture2d0.target = GLKTextureTarget2D;
effect.texture2d0.name = texture.name;
self.vertices:
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, self.vertices);
self.textureCordinates
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, self.textureCoordinates);
What are the obvious memory issues with what im doing?
Thanks very much
You create an NSMutableData object with size 4 bytes, but the data type GLKVector2 is larger than 1 byte. If you're expecting to store a few objects in there you should do
vertexData = [NSMutableData dataWithLength:4 * sizeof(GLKVector2)];
And similarly for textureCoordinateData.
I have a Universal app (iPhone/iPad) which has an iAd displayed at the bottom of the view.
I use the following code to position it on view load;
- (void)viewDidLoad {
bannerIsVisible = YES;
ADBannerView *adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
float origin_y;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
origin_y = 360.0;
else
origin_y = self.view.frame.size.height;
adView.frame = CGRectMake(0.0,origin_y, adView.frame.size.width, adView.frame.size.height);
adView.delegate = self;
if ( &ADBannerContentSizeIdentifierPortrait != NULL ) {
adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierPortrait];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
else {
adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifier320x50];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier320x50;
}
[self.view bringSubviewToFront:adView];
[webView addSubview:adView];
[super viewDidLoad];
}
Now I want to support all 4 orienations i.e. the iAd should move to the bottom on all the 4 orienations
So my question is simply how do I update the following code to support the same;
(BOOL)shouldAutorotateToInterfaceOrientationUIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;
}
Please note 2 things;
1. I need the same code to work on both iPhone/iPad
2. I am ready to update the fixed value of origin_y from 360.0 to whatever you can suggest.
Thank you.
You can work with the autoResizingMask, like this :
[adView setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin
| UIViewAutoresizingFlexibleTopMargin
| UIViewAutoresizingFlexibleHeight ];
Without the UIViewAutoresizingFlexibleBottomMargin, this means that the object will keep the same margin from the bottom of the screen in every device orientation, so stay at the bottom in your case.
Hey guys, I am writing a custom view for doing OpenGLES rendering. I got it working when I had a view in interface builder and set the class to my rendering view, but now I switched to creating the view with initWithFrame. (Note I can set the background color of the view and see it I just can't render anything in OpenGL not even the clear color) Everything seems to be getting called and the layer class seems ok too it just for some reason does not work outside of directly creating it with InterfaceBuilder. Any Ideas?
I have this setup code:
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
- (id)initWithCoder:(NSCoder*)coder
{
if (self = [super initWithCoder:coder])
{
[self setupView];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self setupView];
}
return self;
}
- (void)setupView
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!_context || ![EAGLContext setCurrentContext:_context])
{
NSLog(#"Error could not set context");
[self release];
}
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(renderView:)];
_displayLink.paused = YES;
_displayLink.frameInterval = FPS;
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[EAGLContext setCurrentContext:_context];
[self setup];
}
And then some layout code.
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:_context];
[self destroyBuffers];
if (![self createBuffers]){
NSLog(#"Failed to create framebuffer!");
}
[self resumeRendering];
}
And some rendering code:
- (void)renderView:(CADisplayLink*)sender
{
[EAGLContext setCurrentContext:_context];
glBindFramebuffer(GL_FRAMEBUFFER, _viewFrameBuffer);
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_COLOR_ATTACHMENT0};
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, attachments);
glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderBuffer);
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
I can't figure out why nothing is rendering as all the same things are getting called. If anyone can help me out that would be awesome!
I maybe speculating too much here but switching from IB to initWithFrame has a step omitted, that is loadView in your viewController, which is where you would instantiate your custom view class instead of a standard view class.
I want to reproduce my iPhone display for demoing purposes. I've tried
this and this, but both give me a black screen. Finally, I headed out to make my own solution. Here's what I have:
// Check for external screen.
if ([[UIScreen screens] count] > 1) {
externalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Internal display is 0, external is 1.
externalScreen = [[[UIScreen screens] objectAtIndex:1] retain];
screenModes = [externalScreen.availableModes retain];
UIScreenMode *desiredMode = [screenModes objectAtIndex:0];
externalScreen.currentMode = desiredMode;
externalWindow.screen = externalScreen;
[screenModes release];
[externalScreen release];
CGRect rect = CGRectZero;
rect.size = desiredMode.size;
externalWindow.frame = rect;
externalWindow.clipsToBounds = YES;
externalWindow.hidden = NO;
[externalWindow makeKeyAndVisible];
[externalWindow setUserInteractionEnabled:YES];
[externalWindow setMultipleTouchEnabled:YES];
//[[CCDirector sharedDirector] attachInView:externalWindow];
Now, I can display on the external display or on my iPhone, but I can't display on both at the same time, because [[CCDirector sharedDirector] attachInView:externalWindow]; will only take one UIWindow. How can I get around this and/or get the displayed image and set it to my external display?
Thanks,
Dave
The only solution i see is to render your scene to a texture and render that texture twice as a full screen quad to the backbuffer, once for each UIWindow