新しい GNUstep Project site が開設されています。
GNUstep 関連のドキュメントが整備され、再編集されています。
new GNUstep Project site
https://gnustep.github.io/
Core Animation Example

参考サイト
Core Animation Examples
https://medium.com/@quangtqag/core-animation-examples-742f9af00188
CoreAnimation
gnustep/libs-quartzcore
https://github.com/gnustep/libs-quartzcore
2024-10-17付 Camlkit v0.2 の記事に記載されている方法で、
CoreFoundation, CoreGraphics, CoreAnimation
をインストールします。
CAAppKitBridge の header files はグローバルにインストールされないので、
/usr/local/GNUstep/Local/Library/Frameworks/CAAppKitBridge.framework/Headers/
にコピーします。
header files
GSCAData.h
NSView+CAMethods.h
CAAppKitBridge.h
#import "GSCAData.h"
#import "NSView+CAMethods.h"
プログラム
Application project
main.m
AppController.h
AppController.m
TestView.h
TestView.m
TextLayer.h
TextLayer.m
GNUmakefile
main.m
#import "AppController.h"
#import <Foundation/Foundation.h>
int
main(int argc, const char ** argv, char ** environ)
{
NSAutoreleasePool * pool = [NSAutoreleasePool new];
id controller = [AppController new];
[[NSApplication sharedApplication] setDelegate: controller];
[NSProcessInfo initializeWithArguments: (char**)argv
count: argc
environment: environ];
[NSApp run];
[pool drain];
return 0;
}AppController
AppController.h
#import <Foundation/Foundation.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSMenu.h>
#import "TestView.h"
@interface AppController : NSObject
{
NSWindow *window;
TestView *view;
NSMenu *menu;
}
@endAppController.m
#import "AppController.h"
@implementation AppController
- (void) applicationDidFinishLaunching: (id)t
{
menu = [[NSMenu alloc] initWithTitle: @"Main Menu"];
[menu addItemWithTitle: @"CAAppKitBridgeTest"
action: @selector(orderFrontStandardAboutPanel:)
keyEquivalent: @""];
[menu addItemWithTitle: @"Quit"
action: @selector(terminate:)
keyEquivalent: @"q"];
[NSApp setMainMenu: menu];
[menu release];
window = [[NSWindow alloc] initWithContentRect: NSMakeRect(0,0,450,580)
styleMask: NSTitledWindowMask | NSClosableWindowMask
backing: NSBackingStoreBuffered
defer: NO];
NSLog(@"window %p", window);
view = [[TestView alloc] initWithFrame: window.frame];
NSLog(@"view %p", view);
[[window contentView] addSubview: view];
[window cascadeTopLeftFromPoint: NSMakePoint(150, 700)];
[window makeKeyAndOrderFront: nil];
[view prepareOpenGL];
}
-(BOOL)applicationShouldTerminateAfterLastWindowClosed: (id)sender
{
return YES;
}
-(void)dealloc
{
[super dealloc];
}
@endTestView
TestView.h
#import <Foundation/Foundation.h>
#import <GL/gl.h>
#import <QuartzCore/QuartzCore.h>
#import <CAAppKitBridge/CAAppKitBridge.h>
#import "TextLayer.h"
@interface TestView : NSView
{
CARenderer *renderer;
CALayer *rootLayer;
CALayer *subLayer1;
CALayer *subLayer2;
CALayer *subLayer3;
CALayer *subLayer4;
CALayer *subLayer5;
CALayer *subLayer6;
CALayer *subLayer7;
TextLayer *textLayer1;
TextLayer *textLayer2;
TextLayer *textLayer3;
TextLayer *textLayer4;
TextLayer *textLayer5;
TextLayer *textLayer6;
TextLayer *textLayer7;
NSTimer *_timer;
NSOpenGLContext *context;
NSMutableArray *sublayers;
NSMutableArray *textlayers;
}
@endTestView.m
#import "TestView.h"
CGColorRef NSColorToCGColor(NSColor *color)
{
return CGColorCreateGenericRGB(
color.redComponent,
color.greenComponent,
color.blueComponent,
color.alphaComponent);
}
@implementation TestView
- (void) prepareOpenGL
{
NSLog(@"view wantsLayer value: %d", self.wantsLayer);
NSLog(@"Setting view wantsLayer to true");
[self setWantsLayer: YES];
NSLog(@"view wantsLayer value: %d", self.wantsLayer);
CGColorRef whiteColor = CGColorCreateGenericRGB(1, 1, 1, 1);
CGColorRef blueColor = CGColorCreateGenericRGB(0, 0, 1, 1);
/* Create renderer */
renderer = [CARenderer rendererWithNSOpenGLContext: self._gsCreateOpenGLContext
options: nil];
[renderer retain];
[renderer setBounds: NSRectToCGRect(self.frame)];
/* Create root layer and sub layers */
{
rootLayer = self.makeBackingLayer;
[renderer setLayer: rootLayer];
[rootLayer setBounds: NSRectToCGRect(NSMakeRect(0,0,
self.frame.size.width,
self.frame.size.height))];
[rootLayer setBackgroundColor: whiteColor];
CGPoint midPos = CGPointMake(renderer.bounds.size.width/2,
renderer.bounds.size.height/2);
[rootLayer setPosition: midPos];
sublayers = [NSMutableArray new];
for (int i = 0; i < 7; i++) {
CALayer *subLayer = CALayer.layer;
[rootLayer addSublayer: subLayer];
subLayer.bounds = NSRectToCGRect(NSMakeRect(0, 0, 50, 50));
subLayer.position = CGPointMake(50, 530 - i*80);
subLayer.speed = 2;
[subLayer setNeedsDisplay];
[sublayers addObject: subLayer];
}
subLayer1 = sublayers[0];
subLayer1.backgroundColor = NSColorToCGColor(NSColor.orangeColor);
subLayer2 = sublayers[1];
subLayer2.backgroundColor = NSColorToCGColor(NSColor.yellowColor);
subLayer3 = sublayers[2];
subLayer3.backgroundColor = NSColorToCGColor(NSColor.magentaColor);
subLayer4 = sublayers[3];
subLayer4.backgroundColor = NSColorToCGColor(NSColor.purpleColor);
subLayer5 = sublayers[4];
subLayer5.backgroundColor = NSColorToCGColor(NSColor.redColor);
subLayer6 = sublayers[5];
subLayer6.backgroundColor = NSColorToCGColor(NSColor.redColor);
subLayer7 = sublayers[6];
subLayer7.backgroundColor = NSColorToCGColor(NSColor.redColor);
// TextLayer
textlayers = [NSMutableArray new];
for (int i = 0; i < 7; i++) {
TextLayer *textLayer = TextLayer.layer;
[rootLayer addSublayer: textLayer];
[textLayer setBounds: CGRectMake(0, 0, 300, 50)];
[textLayer setPosition: CGPointMake(250, 530 - i*80)];
[textLayer setColor: blueColor];
[textLayer setFontSize: 20];
[textLayer setNeedsDisplay];
[textlayers addObject: textLayer];
}
textLayer1 = textlayers[0];
[textLayer1 setText: @"Change Background Color"];
textLayer2 = textlayers[1];
[textLayer2 setText: @"Add Layer"];
textLayer3 = textlayers[2];
[textLayer3 setText: @"Shadow"];
textLayer4 = textlayers[3];
[textLayer4 setText: @"Opacity"];
textLayer5 = textlayers[4];
[textLayer5 setText: @"Translation"];
textLayer6 = textlayers[5];
[textLayer6 setText: @"Translation & Rotation"];
textLayer7 = textlayers[6];
[textLayer7 setText: @"Rotate3D"];
}
CGColorRelease(whiteColor);
CGColorRelease(blueColor);
context = [self _gsCreateOpenGLContext];
[context makeCurrentContext];
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, [self frame].size.width, 0, [self frame].size.height, -1500, 1500);
_timer = [NSTimer scheduledTimerWithTimeInterval: 1./60.
target: self
selector: @selector(timerAnimation:)
userInfo: nil
repeats: YES];
}
-(void) timerAnimation: (NSTimer*)t
{
[renderer beginFrameAtTime: CACurrentMediaTime()
timeStamp: NULL];
[self clearBounds: [renderer updateBounds]];
[renderer render];
glFlush();
[context flushBuffer];
}
- (void)clearBounds:(CGRect)bounds
{
glBegin(GL_QUADS);
glColor4f(0,0,0,1);
glVertex2f(bounds.origin.x, bounds.origin.y);
glVertex2f(bounds.origin.x+bounds.size.width, bounds.origin.y);
glVertex2f(bounds.origin.x+bounds.size.width, bounds.origin.y+bounds.size.height);
glVertex2f(bounds.origin.x, bounds.origin.y+bounds.size.height);
glEnd();
}
- (void) mouseDown:(NSEvent *)theEvent
{
NSLog(@"mouse down event");
NSPoint curPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
NSLog(@"mouse down event x: %f y: %f", curPoint.x, curPoint.y);
for (int i = 0; i < [sublayers count]; i++)
{
CALayer *sublayer = [sublayers objectAtIndex:i];
CGRect frame = [sublayer bounds];
frame.origin = CGPointMake([sublayer position].x - frame.size.width/2, [sublayer position].y - frame.size.height/2);
if (CGRectContainsPoint(frame, NSPointToCGPoint(curPoint)))
{
NSLog(@"sublayer position x: %f y: %f", sublayer.position.x, sublayer.position.y);
switch (i) {
case 0:
subLayer1.backgroundColor = NSColorToCGColor(NSColor.greenColor);
break;
case 1:
CALayer *alayer = CALayer.layer;
alayer.bounds = NSRectToCGRect(NSMakeRect(0, 0, 25, 25));
alayer.position = CGPointMake(12.5, 37.5);
alayer.backgroundColor = NSColorToCGColor(NSColor.blueColor);
[subLayer2 addSublayer: alayer];
break;
case 2:
subLayer3.shadowOpacity = 0.7;
subLayer3.shadowOffset = CGSizeMake(10, -10);
break;
case 3:
CABasicAnimation *opacity = [CABasicAnimation animationWithKeyPath:@"opacity"];
[opacity setFromValue: [NSNumber numberWithFloat: [subLayer4 opacity]]];
[opacity setToValue: [NSNumber numberWithFloat: 0.0]];
[opacity setDuration: 3];
[opacity setAutoreverses: YES];
[subLayer4 addAnimation: opacity forKey: @"pulse"];
break;
case 4:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration: 3];
[animation setFromValue: [NSValue valueWithPoint: NSMakePoint(50, 210)]];
[animation setToValue: [NSValue valueWithPoint: NSMakePoint(100, 210)]];
[animation setAutoreverses: YES];
[subLayer5 addAnimation: animation forKey:@"thePositionAnimation"];
break;
case 5:
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform"];
[animation2 setFromValue: [NSValue valueWithCATransform3D: [subLayer6 transform]]];
[animation2 setToValue: [NSValue valueWithCATransform3D: CATransform3DTranslate(CATransform3DRotate([subLayer6 transform], M_PI, 0, 0, 1), -80, 0, 0)]];
[animation2 setDuration: 4];
[animation2 setAutoreverses: YES];
[subLayer6 addAnimation: animation2 forKey: @"doABarrelRoll"];
break;
case 6:
CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"transform"];
[animation3 setFromValue: [NSValue valueWithCATransform3D: [subLayer7 transform]]];
[animation3 setToValue: [NSValue valueWithCATransform3D: CATransform3DRotate([subLayer7 transform], M_PI, 0, 1, 0)]];
[animation3 setDuration: 4];
[animation3 setAutoreverses: YES];
[subLayer7 addAnimation: animation3 forKey: @"transform"];
break;
default:
break;
}
}
}
}
@endTextLayer
TextLayer.h, TextLayer.m ともに quartzcore/Demo 内にあるファイルをそのまま
使用している。
GNUmakefile
include $(GNUSTEP_MAKEFILES)/common.make
APP_NAME = CAAppKitBridgeTest
CAAppKitBridgeTest_OBJC_FILES = \
main.m \
AppController.m \
TestView.m \
TextLayer.m
ADDITIONAL_LDFLAGS += $(shell pkg-config --libs cairo) -L../Source/CAAppKitBridge.framework
ADDITIONAL_OBJCFLAGS += -Wall -g -O0 -std=gnu11
ADDITIONAL_CFLAGS += -Wall -g -O0 -std=gnu11
ADDITIONAL_TOOL_LIBS = -lgnustep-gui -lGL -lGLU -lopal -lQuartzCore -lCAAppKitBridge
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/tool.make
include $(GNUSTEP_MAKEFILES)/application.make
-include GNUmakefile.postamble