1 #import <QuartzCore/CARenderer.h>
2 #import <QuartzCore/CALayer.h>
3 #import <QuartzCore/CAAnimation.h>
4 #import <QuartzCore/CAMediaTimingFunction.h>
5 #import <CoreVideo/CoreVideo.h>
6 #import <OpenGL/OpenGL.h>
7 #import <Onyx2D/O2Surface.h>
9 @interface CALayer(private)
10 -(void)_setContext:(CALayerContext *)context;
11 -(void)_setTextureId:(NSNumber *)value;
12 -(NSNumber *)_textureId;
15 @implementation CARenderer
21 -(void)setBounds:(CGRect)value {
25 @synthesize layer=_rootLayer;
27 -initWithCGLContext:(void *)cglContext options:(NSDictionary *)options {
28 _cglContext=cglContext;
34 +(CARenderer *)rendererWithCGLContext:(void *)cglContext options:(NSDictionary *)options {
35 return [[[self alloc] initWithCGLContext:cglContext options:options] autorelease];
38 static void startAnimationsInLayer(CALayer *layer,CFTimeInterval currentTime){
39 NSArray *keys=[layer animationKeys];
41 for(NSString *key in keys){
42 CAAnimation *check=[layer animationForKey:key];
44 if([check beginTime]==0.0)
45 [check setBeginTime:currentTime];
46 if(currentTime>[check beginTime]+[check duration]){
47 [layer removeAnimationForKey:key];
52 for(CALayer *child in layer.sublayers)
53 startAnimationsInLayer(child,currentTime);
56 -(void)beginFrameAtTime:(CFTimeInterval)currentTime timeStamp:(CVTimeStamp *)timeStamp {
57 startAnimationsInLayer(_rootLayer,currentTime);
60 static inline float cubed(float value){
61 return value*value*value;
64 static inline float squared(float value){
68 static float applyMediaTimingFunction(CAMediaTimingFunction *function,float t){
73 [function getControlPointAtIndex:1 values:cp1];
74 [function getControlPointAtIndex:2 values:cp2];
76 double x=cubed(1.0-t)*0.0+3*squared(1-t)*t*cp1[0]+3*(1-t)*squared(t)*cp2[0]+cubed(t)*1.0;
77 double y=cubed(1.0-t)*0.0+3*squared(1-t)*t*cp1[1]+3*(1-t)*squared(t)*cp2[1]+cubed(t)*1.0;
83 static float mediaTimingScale(CAAnimation *animation,CFTimeInterval currentTime){
84 CFTimeInterval begin=[animation beginTime];
85 CFTimeInterval duration=[animation duration];
86 CFTimeInterval delta=currentTime-begin;
87 double zeroToOne=delta/duration;
88 CAMediaTimingFunction *function=[animation timingFunction];
91 function=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
93 return applyMediaTimingFunction(function,zeroToOne);
96 static float interpolateFloatInLayerKey(CALayer *layer,NSString *key,CFTimeInterval currentTime){
97 CAAnimation *animation=[layer animationForKey:key];
100 return [[layer valueForKey:key] floatValue];
102 if([animation isKindOfClass:[CABasicAnimation class]]){
103 CABasicAnimation *basic=(CABasicAnimation *)animation;
105 id fromValue=[basic fromValue];
106 id toValue=[basic toValue];
109 toValue=[layer valueForKey:key];
111 float fromFloat=[fromValue floatValue];
112 float toFloat=[toValue floatValue];
115 double timingScale=mediaTimingScale(animation,currentTime);
117 resultFloat=fromFloat+(toFloat-fromFloat)*timingScale;
125 static CGPoint interpolatePointInLayerKey(CALayer *layer,NSString *key,CFTimeInterval currentTime){
126 CAAnimation *animation=[layer animationForKey:key];
129 return [[layer valueForKey:key] pointValue];
131 if([animation isKindOfClass:[CABasicAnimation class]]){
132 CABasicAnimation *basic=(CABasicAnimation *)animation;
134 id fromValue=[basic fromValue];
135 id toValue=[basic toValue];
138 toValue=[layer valueForKey:key];
140 CGPoint fromPoint=[fromValue pointValue];
141 CGPoint toPoint=[toValue pointValue];
144 double timingScale=mediaTimingScale(animation,currentTime);
146 resultPoint.x=fromPoint.x+(toPoint.x-fromPoint.x)*timingScale;
147 resultPoint.y=fromPoint.y+(toPoint.y-fromPoint.y)*timingScale;
152 return CGPointMake(0,0);
155 static CGRect interpolateRectInLayerKey(CALayer *layer,NSString *key,CFTimeInterval currentTime){
156 CAAnimation *animation=[layer animationForKey:key];
159 return [[layer valueForKey:key] rectValue];
162 if([animation isKindOfClass:[CABasicAnimation class]]){
163 CABasicAnimation *basic=(CABasicAnimation *)animation;
165 id fromValue=[basic fromValue];
166 id toValue=[basic toValue];
169 toValue=[layer valueForKey:key];
171 CGRect fromRect=[fromValue rectValue];
172 CGRect toRect=[toValue rectValue];
174 double timingScale=mediaTimingScale(animation,currentTime);
178 resultRect.origin.x=fromRect.origin.x+(toRect.origin.x-fromRect.origin.x)*timingScale;
179 resultRect.origin.y=fromRect.origin.y+(toRect.origin.y-fromRect.origin.y)*timingScale;
180 resultRect.size.width=fromRect.size.width+(toRect.size.width-fromRect.size.width)*timingScale;
181 resultRect.size.height=fromRect.size.height+(toRect.size.height-fromRect.size.height)*timingScale;
186 return CGRectMake(0,0,0,0);
189 static GLint interpolationFromName(NSString *name){
190 if(name==kCAFilterLinear)
192 else if(name==kCAFilterNearest)
194 else if([name isEqualToString:kCAFilterLinear])
196 else if([name isEqualToString:kCAFilterNearest])
202 void CATexImage2DCGImage(CGImageRef image){
203 size_t imageWidth=CGImageGetWidth(image);
204 size_t imageHeight=CGImageGetHeight(image);
205 CGBitmapInfo bitmapInfo=CGImageGetBitmapInfo(image);
207 CGDataProviderRef provider=CGImageGetDataProvider(image);
208 CFDataRef data=CGDataProviderCopyData(provider);
209 const uint8_t *pixelBytes=CFDataGetBytePtr(data);
212 GLenum glFormat=GL_BGRA;
213 GLenum glType=GL_UNSIGNED_INT_8_8_8_8_REV;
215 CGImageAlphaInfo alphaInfo=bitmapInfo&kCGBitmapAlphaInfoMask;
216 CGBitmapInfo byteOrder=bitmapInfo&kCGBitmapByteOrderMask;
220 case kCGImageAlphaNone:
223 case kCGImageAlphaPremultipliedLast:
224 if(byteOrder==kO2BitmapByteOrder32Big){
226 glType=GL_UNSIGNED_INT_8_8_8_8_REV;
230 case kCGImageAlphaPremultipliedFirst: // ARGB
231 if(byteOrder==kCGBitmapByteOrder32Little){
233 glType=GL_UNSIGNED_INT_8_8_8_8_REV;
237 case kCGImageAlphaLast:
240 case kCGImageAlphaFirst:
243 case kCGImageAlphaNoneSkipLast:
246 case kCGImageAlphaNoneSkipFirst:
249 case kCGImageAlphaOnly:
253 glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,imageWidth,imageHeight,0,glFormat,glType,pixelBytes);
257 -(void)_renderLayer:(CALayer *)layer z:(float)z currentTime:(CFTimeInterval)currentTime {
258 NSNumber *textureId=[layer _textureId];
259 GLuint texture=[textureId unsignedIntValue];
260 GLboolean loadPixelData=GL_FALSE;
263 loadPixelData=GL_TRUE;
266 if(glIsTexture(texture)==GL_FALSE){
267 loadPixelData=GL_TRUE;
269 glBindTexture(GL_TEXTURE_2D,texture);
274 CGImageRef image=layer.contents;
276 CATexImage2DCGImage(image);
278 GLint minFilter=interpolationFromName(layer.minificationFilter);
279 GLint magFilter=interpolationFromName(layer.magnificationFilter);
281 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,minFilter);
282 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,magFilter);
284 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
285 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
288 CGPoint anchorPoint=interpolatePointInLayerKey(layer,@"anchorPoint",currentTime);
289 CGPoint position=interpolatePointInLayerKey(layer,@"position",currentTime);
290 CGRect bounds=interpolateRectInLayerKey(layer,@"bounds",currentTime);
291 float opacity=interpolateFloatInLayerKey(layer,@"opacity",currentTime);
293 GLfloat textureVertices[4*2];
294 GLfloat vertices[4*3];
296 textureVertices[0]=0;
297 textureVertices[1]=1;
298 textureVertices[2]=1;
299 textureVertices[3]=1;
300 textureVertices[4]=0;
301 textureVertices[5]=0;
302 textureVertices[6]=1;
303 textureVertices[7]=0;
309 vertices[3]=bounds.size.width;
314 vertices[7]=bounds.size.height;
317 vertices[9]=bounds.size.width;
318 vertices[10]=bounds.size.height;
323 // glTranslatef(width/2,height/2,0);
324 glTexCoordPointer(2, GL_FLOAT, 0, textureVertices);
325 glVertexPointer(3, GL_FLOAT, 0, vertices);
328 glTranslatef(position.x-(bounds.size.width*anchorPoint.x),position.y-(bounds.size.height*anchorPoint.y),0);
329 // glTranslatef(position.x,position.y,0);
330 // glScalef(bounds.size.width,bounds.size.height,1);
332 // glRotatef(1,0,0,1);
333 glColor4f(opacity,opacity,opacity,opacity);
335 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
337 for(CALayer *child in layer.sublayers)
338 [self _renderLayer:child z:z+1 currentTime:currentTime];
344 glMatrixMode(GL_MODELVIEW);
347 glClearColor(0, 0, 0, 1);
348 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
350 glEnable(GL_DEPTH_TEST);
351 glDepthFunc(GL_LEQUAL);
353 glEnable( GL_TEXTURE_2D );
354 glEnableClientState(GL_VERTEX_ARRAY);
355 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
358 glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
360 glAlphaFunc ( GL_GREATER, 0 ) ;
361 glEnable ( GL_ALPHA_TEST ) ;
363 [self _renderLayer:_rootLayer z:0 currentTime:CACurrentMediaTime()];