Advertisement
TimLai

ARCALView

Jul 7th, 2012
2,306
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #ARCALView.h
  2. #import <UIKit/UIKit.h>
  3. #import <QuartzCore/QuartzCore.h>
  4. #import <AVFoundation/AVFoundation.h>
  5. #import <QCAR/UIGLViewProtocol.h>
  6.  
  7. #import <GLKit/GLKit.h>
  8.  
  9. @class QCARutils;
  10.  
  11. // This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView
  12. // subclass.  The view content is basically an EAGL surface you render your
  13. // OpenGL scene into.  Note that setting the view non-opaque will only work if
  14. // the EAGL surface has an alpha channel.
  15. @interface ARCALView : UIView <UIGLViewProtocol>
  16.  
  17. {
  18. @public
  19.     NSMutableArray *textureList; // list of textures to load
  20.    
  21. @protected
  22.     EAGLContext *context_;
  23.     GLuint framebuffer_;
  24.     GLuint renderbuffer_;
  25.    
  26.     QCARutils *qUtils; // QCAR utils class
  27.     NSMutableArray* textures;   // loaded textures
  28.    
  29.     CALayer *cameraLayer;
  30.     AVPlayer *player;
  31.     AVPlayerLayer *playerLayer;
  32.     BOOL videoInitialized;
  33.     CATransform3D transform;
  34.    
  35.     int frameCount;
  36.     BOOL hideVideo;
  37. }
  38.  
  39. @property (nonatomic, retain) NSMutableArray *textureList;
  40. @property (nonatomic, retain) id cameraImage;
  41. - (void) useTextures:(NSMutableArray *)theTextures;
  42. @end
  43.  
  44.  
  45. #ARCALView.m
  46. #import "ARCALView.h"
  47. #import "Texture.h"
  48. #import <QCAR/QCAR.h>
  49.  
  50. #import <QCAR/Renderer.h>
  51. #import <QCAR/Image.h>
  52. #import "QCARutils.h"
  53.  
  54. #ifndef USE_OPENGL1
  55. #import "ShaderUtils.h"
  56. #define MAKESTRING(x) #x
  57. #endif
  58.  
  59. @interface ARCALView (PrivateMethods)
  60. - (int)loadTextures;
  61. @end
  62.  
  63.  
  64. @implementation ARCALView
  65. @synthesize textureList;
  66. @synthesize cameraImage;
  67.  
  68. + (Class)layerClass
  69. {
  70.     return [CAEAGLLayer class];
  71. }
  72.  
  73. - (CATransform3D) GLtoCATransform3D:(QCAR::Matrix44F)m
  74. {
  75.     CATransform3D t = CATransform3DIdentity;
  76.     t.m11 = m.data[0];
  77.     t.m12 = m.data[1];
  78.     t.m13 = m.data[2];
  79.     t.m14 = m.data[3];
  80.     t.m21 = m.data[4];
  81.     t.m22 = m.data[5];
  82.     t.m23 = m.data[6];
  83.     t.m24 = m.data[7];
  84.     t.m31 = m.data[8];
  85.     t.m32 = m.data[9];
  86.     t.m33 = m.data[10];
  87.     t.m34 = m.data[11];
  88.     t.m41 = m.data[12];
  89.     t.m42 = m.data[13];
  90.     t.m43 = m.data[14];
  91.     t.m44 = m.data[15];
  92.  
  93.     return t;
  94. }
  95.  
  96. - (CGImageRef)createCGImage:(const QCAR::Image *)qcarImage
  97. {
  98.     int width = qcarImage->getWidth();
  99.     int height = qcarImage->getHeight();
  100.     int bitsPerComponent = 8;
  101.     int bitsPerPixel = QCAR::getBitsPerPixel(QCAR::RGB888);
  102.     int bytesPerRow = qcarImage->getBufferWidth() * bitsPerPixel / bitsPerComponent;
  103.    
  104.     CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
  105.     CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaNone;
  106.     CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
  107.    
  108.     CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, qcarImage->getPixels(), QCAR::getBufferSize(width, height, QCAR::RGB888), NULL);
  109.    
  110.     CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
  111.    
  112.     CGDataProviderRelease(provider);
  113.     CGColorSpaceRelease(colorSpaceRef);
  114.  
  115.     return (CGImageRef)[(id)imageRef autorelease];
  116. }
  117.  
  118. - (void)createFrameBuffer {
  119.    
  120.     // This is called on main thread
  121.    
  122.     if (context_ && !framebuffer_)
  123.         [EAGLContext setCurrentContext:context_];
  124.    
  125.     glGenFramebuffers(1, &framebuffer_);
  126.     glGenRenderbuffers(1, &renderbuffer_);
  127.    
  128.     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
  129.     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
  130.    
  131.     [context_ renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
  132.     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer_);
  133.    
  134. }
  135.  
  136. - (void)render {
  137.     // Render video background and retrieve tracking state
  138.     QCAR::setFrameFormat(QCAR::RGB888, true);
  139.  
  140.     QCAR::State state = QCAR::Renderer::getInstance().begin();
  141.     //QCAR::Renderer::getInstance().drawVideoBackground();
  142.    
  143.     QCAR::Frame ff = state.getFrame();
  144.     if (ff.getNumImages() <= 0) {
  145.         QCAR::Renderer::getInstance().end();
  146.         return;
  147.     }
  148.    
  149.     for (int i = 0; i < ff.getNumImages(); i++) {
  150.         const QCAR::Image *qcarImage = ff.getImage(i);
  151.         if (qcarImage->getFormat() == QCAR::RGB888)
  152.         {
  153.             self.cameraImage = (id)[self createCGImage:qcarImage];
  154.             break;
  155.         }
  156.     }
  157.    
  158.    
  159.     if (state.getNumActiveTrackables() == 0 || videoInitialized == NO) {
  160.         [player pause];
  161.         hideVideo = YES;
  162.         QCAR::Renderer::getInstance().end();
  163.         return;
  164.     }
  165.    
  166.     hideVideo = NO;
  167.     if (player.rate == 0) {
  168.         [player play];
  169.     }
  170.    
  171.    
  172.     // Get the trackable
  173.     const QCAR::Trackable* trackable = state.getActiveTrackable(0);
  174.     QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(trackable->getPose());
  175.    
  176.     CGFloat ScreenScale = [[UIScreen mainScreen] scale];
  177.     float xscl = qUtils.viewport.sizeX/ScreenScale/2;
  178.     float yscl = qUtils.viewport.sizeY/ScreenScale/2;
  179.    
  180.     QCAR::Matrix44F scalingMatrix = {xscl,0,0,0,
  181.         0,yscl,0,0,
  182.         0,0,1,0,
  183.         0,0,0,1};
  184.    
  185.     QCAR::Matrix44F flipY = { 1, 0,0,0,
  186.         0,-1,0,0,
  187.         0, 0,1,0,
  188.         0, 0,0,1};
  189.    
  190.     ShaderUtils::translatePoseMatrix(0.0f, 0.0f, 3, &modelViewMatrix.data[0]);
  191.     ShaderUtils::multiplyMatrix(&modelViewMatrix.data[0], &flipY.data[0], &modelViewMatrix.data[0]);
  192.     ShaderUtils::multiplyMatrix(&qUtils.projectionMatrix.data[0],&modelViewMatrix.data[0], &modelViewMatrix.data[0]);
  193.     ShaderUtils::multiplyMatrix(&scalingMatrix.data[0], &modelViewMatrix.data[0], &modelViewMatrix.data[0]);
  194.     ShaderUtils::multiplyMatrix(&flipY.data[0], &modelViewMatrix.data[0], &modelViewMatrix.data[0]);
  195.     transform = [self GLtoCATransform3D:modelViewMatrix];
  196.  
  197.     QCAR::Renderer::getInstance().end();
  198.    
  199. }
  200.  
  201. - (void)initVideo {
  202.    
  203.     NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"video.mp4" ofType:nil]];
  204.     //NSURL *url = [NSURL URLWithString:@"http://dl.dropbox.com/u/6040916/video.mp4"];
  205.     AVURLAsset *avasset = [[AVURLAsset alloc] initWithURL:url options:nil];
  206.    
  207.     AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:avasset];
  208.     player = [[AVPlayer alloc] initWithPlayerItem:item];
  209.    
  210.     playerLayer = [[AVPlayerLayer playerLayerWithPlayer:player] retain];
  211.     CGSize size = self.bounds.size;
  212.     float x = size.width/2.0-187.0;
  213.     float y = size.height/2.0 - 125.0;
  214.  
  215.     playerLayer.frame = CGRectMake(x, y, 374, 250);
  216.     playerLayer.backgroundColor = [UIColor blackColor].CGColor;
  217.     [cameraLayer addSublayer:playerLayer];
  218.     playerLayer.hidden = hideVideo;
  219.     transform = CATransform3DIdentity;
  220.    
  221.     NSString *tracksKey = @"tracks";
  222.    
  223.     [avasset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:tracksKey] completionHandler:
  224.      ^{
  225.          dispatch_async(dispatch_get_main_queue(),
  226.                         ^{
  227.                             NSError *error = nil;
  228.                             AVKeyValueStatus status = [avasset statusOfValueForKey:tracksKey error:&error];
  229.                            
  230.                             if (status == AVKeyValueStatusLoaded) {
  231.                                
  232.                                 videoInitialized = YES;
  233.                             }
  234.                             else {
  235.                                 // You should deal with the error appropriately.
  236.                                 NSLog(@"The asset's tracks were not loaded:\n%@", [error localizedDescription]);
  237.                             }
  238.                         });
  239.      }];
  240. }
  241.  
  242. // test to see if the screen has hi-res mode
  243. - (BOOL) isRetinaEnabled
  244. {
  245.     return ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)]
  246.             &&
  247.             ([UIScreen mainScreen].scale == 2.0));
  248. }
  249.  
  250. // use to allow this view to access loaded textures
  251. - (void) useTextures:(NSMutableArray *)theTextures
  252. {
  253.     textures = theTextures;
  254. }
  255.  
  256. #pragma mark ---- view lifecycle ---
  257. /////////////////////////////////////////////////////////////////
  258. //
  259. - (id)initWithFrame:(CGRect)frame
  260. {
  261.     self = [super initWithFrame:frame];
  262.    
  263.     if (self) {
  264.         qUtils = [QCARutils getInstance];
  265.         textureList = [[NSMutableArray alloc] initWithCapacity:2];
  266.        
  267.         // switch on hi-res mode if available
  268.         if ([self isRetinaEnabled])
  269.         {
  270.             self.contentScaleFactor = 2.0f;
  271.             qUtils.contentScalingFactor = self.contentScaleFactor;
  272.         }
  273.        
  274.        
  275.  
  276.         qUtils.QCARFlags = QCAR::GL_20;
  277.        
  278.         CAEAGLLayer *layer = (CAEAGLLayer *)self.layer;
  279.         layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
  280.                                     kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
  281.                                     nil];
  282.        
  283.         context_ = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  284.        
  285.         frameCount = 0;
  286.         cameraLayer = [CALayer layer];
  287.         cameraLayer.contentsGravity = kCAGravityResizeAspectFill;
  288.         cameraLayer.frame = self.layer.bounds;
  289.         [self.layer addSublayer:cameraLayer];
  290.        
  291.         hideVideo = YES;
  292.         [self initVideo];
  293.         NSLog(@"QCAR OpenGL flag: %d", qUtils.QCARFlags);
  294.        
  295.     }
  296.    
  297.     return self;
  298. }
  299.  
  300. - (void)dealloc {
  301.     if (framebuffer_) {
  302.         glDeleteFramebuffers(1, &framebuffer_);
  303.         glDeleteFramebuffers(1, &renderbuffer_);
  304.     }
  305.    
  306.     if ([EAGLContext currentContext] == context_) {
  307.         [EAGLContext setCurrentContext:nil];
  308.     }
  309.    
  310.     [context_ release];
  311.     [textureList release];
  312.     [cameraImage release];
  313.     [super dealloc];
  314. }
  315.  
  316. - (void) postInitQCAR {
  317.     // These two calls to setHint tell QCAR to split work over multiple
  318.     // frames.  Depending on your requirements you can opt to omit these.
  319.     QCAR::setHint(QCAR::HINT_IMAGE_TARGET_MULTI_FRAME_ENABLED, 1);
  320.     QCAR::setHint(QCAR::HINT_IMAGE_TARGET_MILLISECONDS_PER_MULTI_FRAME, 40);
  321.    
  322.     // Here we could also make a QCAR::setHint call to set the maximum
  323.     // number of simultaneous targets                
  324.     // QCAR::setHint(QCAR::HINT_MAX_SIMULTANEOUS_IMAGE_TARGETS, 2);
  325. }
  326.  
  327. ////////////////////////////////////////////////////////////////////////////////
  328. // Draw the current frame using OpenGL
  329. //
  330. // This code is a TEMPLATE for the subclassing EAGLView to complete
  331. //
  332. // The subclass override of this method is called by QCAR when it wishes to render the current frame to
  333. // the screen.
  334. //
  335. // *** QCAR will call the subclassed method on a single background thread ***
  336. - (void)renderFrameQCAR {
  337.     if (!framebuffer_) {
  338.         [self performSelectorOnMainThread:@selector(createFrameBuffer) withObject:nil waitUntilDone:YES];
  339.     }
  340.    
  341.     [EAGLContext setCurrentContext:context_];
  342.    
  343.     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
  344.     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer_);
  345.    
  346.     //glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 1, 1);
  347.    
  348.     /*GLint width, height;
  349.     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  350.     glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  351.     glViewport(0, 0, width, height);*/
  352.    
  353.     if (frameCount < 5) {
  354.         frameCount++;
  355.         return;
  356.     }
  357.  
  358.     [self render];
  359.    
  360.     dispatch_async(dispatch_get_main_queue(), ^{
  361.        
  362.        
  363.         [CATransaction begin];
  364.         [CATransaction setValue:(id)kCFBooleanTrue
  365.                          forKey:kCATransactionDisableActions];
  366.         cameraLayer.contents = cameraImage;
  367.        
  368.         playerLayer.transform = transform;
  369.         playerLayer.hidden = hideVideo;
  370.         [CATransaction commit];
  371.     });
  372.  
  373. }
  374.  
  375. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement