Merge pull request #10 from gunyarakun/fix-invalid-return
[cocotron.git] / QuartzCore / CARenderer.m
blob5f30532956451d6287f30373d2a93c78093ce781
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;
13 @end
15 @implementation CARenderer
17 -(CGRect)bounds {
18    return _bounds;
21 -(void)setBounds:(CGRect)value {
22    _bounds=value;
25 @synthesize layer=_rootLayer;
27 -initWithCGLContext:(void *)cglContext options:(NSDictionary *)options {
28    _cglContext=cglContext;
29    _bounds=CGRectZero;
30    _rootLayer=nil;
31    return self;
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];
40    
41    for(NSString *key in keys){
42     CAAnimation *check=[layer animationForKey:key];
43     
44     if([check beginTime]==0.0)
45      [check setBeginTime:currentTime];
46     if(currentTime>[check beginTime]+[check duration]){
47      [layer removeAnimationForKey:key];
48     }
49     
50    }
51    
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){
65    return value*value;
68 static float applyMediaTimingFunction(CAMediaTimingFunction *function,float t){
69    float result;
70    float cp1[2];
71    float cp2[2];
72    
73    [function getControlPointAtIndex:1 values:cp1];
74    [function getControlPointAtIndex:2 values:cp2];
75    
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;
78    
79 // this is wrong
80    return y;
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];
89    
90    if(function==nil)
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];
98    
99    if(animation==nil)
100     return [[layer valueForKey:key] floatValue];
101    
102    if([animation isKindOfClass:[CABasicAnimation class]]){
103     CABasicAnimation *basic=(CABasicAnimation *)animation;
104     
105     id fromValue=[basic fromValue];
106     id toValue=[basic toValue];
107     
108     if(toValue==nil)
109      toValue=[layer valueForKey:key];
110     
111     float fromFloat=[fromValue floatValue];
112     float toFloat=[toValue floatValue];
113         
114     float        resultFloat;
115     double timingScale=mediaTimingScale(animation,currentTime);
116     
117     resultFloat=fromFloat+(toFloat-fromFloat)*timingScale;
118         
119     return resultFloat;
120    }
121    
122    return 0;
125 static CGPoint interpolatePointInLayerKey(CALayer *layer,NSString *key,CFTimeInterval currentTime){
126    CAAnimation *animation=[layer animationForKey:key];
127    
128    if(animation==nil)
129     return [[layer valueForKey:key] pointValue];
130    
131    if([animation isKindOfClass:[CABasicAnimation class]]){
132     CABasicAnimation *basic=(CABasicAnimation *)animation;
133     
134     id fromValue=[basic fromValue];
135     id toValue=[basic toValue];
136     
137     if(toValue==nil)
138      toValue=[layer valueForKey:key];
139     
140     CGPoint fromPoint=[fromValue pointValue];
141     CGPoint toPoint=[toValue pointValue];
142         
143     CGPoint        resultPoint;
144     double timingScale=mediaTimingScale(animation,currentTime);
145     
146     resultPoint.x=fromPoint.x+(toPoint.x-fromPoint.x)*timingScale;
147     resultPoint.y=fromPoint.y+(toPoint.y-fromPoint.y)*timingScale;
148         
149     return resultPoint;
150    }
151    
152    return CGPointMake(0,0);
155 static CGRect interpolateRectInLayerKey(CALayer *layer,NSString *key,CFTimeInterval currentTime){
156    CAAnimation *animation=[layer animationForKey:key];
158    if(animation==nil){
159     return [[layer valueForKey:key] rectValue];
160    }
161    
162    if([animation isKindOfClass:[CABasicAnimation class]]){
163     CABasicAnimation *basic=(CABasicAnimation *)animation;
164     
165     id fromValue=[basic fromValue];
166     id toValue=[basic toValue];
167     
168     if(toValue==nil)
169      toValue=[layer valueForKey:key];
170     
171     CGRect fromRect=[fromValue rectValue];
172     CGRect toRect=[toValue rectValue];
173     
174     double timingScale=mediaTimingScale(animation,currentTime);
175     
176     CGRect        resultRect;
177     
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;
182         
183     return resultRect;
184    }
185    
186    return CGRectMake(0,0,0,0);
189 static GLint interpolationFromName(NSString *name){
190    if(name==kCAFilterLinear)
191     return GL_LINEAR;
192    else if(name==kCAFilterNearest)
193     return GL_NEAREST;
194    else if([name isEqualToString:kCAFilterLinear])
195     return GL_LINEAR;
196    else if([name isEqualToString:kCAFilterNearest])
197     return GL_NEAREST;
198    else
199     return GL_LINEAR;   
202 void CATexImage2DCGImage(CGImageRef image){
203     size_t            imageWidth=CGImageGetWidth(image);
204     size_t            imageHeight=CGImageGetHeight(image);
205     CGBitmapInfo      bitmapInfo=CGImageGetBitmapInfo(image);
206    
207     CGDataProviderRef provider=CGImageGetDataProvider(image);
208     CFDataRef         data=CGDataProviderCopyData(provider);
209     const uint8_t    *pixelBytes=CFDataGetBytePtr(data);
210    
211    
212     GLenum glFormat=GL_BGRA;
213     GLenum glType=GL_UNSIGNED_INT_8_8_8_8_REV;
214    
215     CGImageAlphaInfo alphaInfo=bitmapInfo&kCGBitmapAlphaInfoMask;
216     CGBitmapInfo     byteOrder=bitmapInfo&kCGBitmapByteOrderMask;
217    
218     switch(alphaInfo){
219    
220         case kCGImageAlphaNone:
221             break;
223         case kCGImageAlphaPremultipliedLast:
224             if(byteOrder==kO2BitmapByteOrder32Big){
225                 glFormat=GL_RGBA;
226                 glType=GL_UNSIGNED_INT_8_8_8_8_REV;
227             }
228             break;
230         case kCGImageAlphaPremultipliedFirst: // ARGB
231             if(byteOrder==kCGBitmapByteOrder32Little){
232                 glFormat=GL_BGRA;
233                 glType=GL_UNSIGNED_INT_8_8_8_8_REV;
234             }
235             break;
237         case kCGImageAlphaLast:
238             break;
240         case kCGImageAlphaFirst:
241             break;
243         case kCGImageAlphaNoneSkipLast:
244             break;
246         case kCGImageAlphaNoneSkipFirst:
247             break;
249         case kCGImageAlphaOnly:
250             break;
251     }
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;
261    
262    if(texture==0)
263     loadPixelData=GL_TRUE;
264    else {
265    
266     if(glIsTexture(texture)==GL_FALSE){
267      loadPixelData=GL_TRUE;
268     }
269     glBindTexture(GL_TEXTURE_2D,texture);
270     
271    }
273     if(loadPixelData){
274         CGImageRef image=layer.contents;
275     
276         CATexImage2DCGImage(image);
278         GLint minFilter=interpolationFromName(layer.minificationFilter);
279         GLint magFilter=interpolationFromName(layer.magnificationFilter);
280    
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);
286    }
287    
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);
292    
293    GLfloat textureVertices[4*2];
294    GLfloat vertices[4*3];
295    
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;
305    vertices[0]=0;
306    vertices[1]=0;
307    vertices[2]=z;
308    
309    vertices[3]=bounds.size.width;
310    vertices[4]=0;
311    vertices[5]=z;
312    
313    vertices[6]=0;
314    vertices[7]=bounds.size.height;
315    vertices[8]=z;
317    vertices[9]=bounds.size.width;
318    vertices[10]=bounds.size.height;
319    vertices[11]=z;
320    
322    glPushMatrix();
323  //  glTranslatef(width/2,height/2,0);
324    glTexCoordPointer(2, GL_FLOAT, 0, textureVertices);
325    glVertexPointer(3, GL_FLOAT, 0, vertices);
326    
327    
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);
331    
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];
340    glPopMatrix();
343 -(void)render {
344    glMatrixMode(GL_MODELVIEW);                                           
345    glLoadIdentity();
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);
357    glEnable (GL_BLEND);
358    glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
359    
360    glAlphaFunc ( GL_GREATER, 0 ) ;
361    glEnable ( GL_ALPHA_TEST ) ;
362   
363    [self _renderLayer:_rootLayer z:0 currentTime:CACurrentMediaTime()];
365    glFlush();
368 -(void)endFrame {
371 @end