├── .babelrc-future ├── .eslintrc ├── .gitignore ├── App ├── images │ ├── 3BxEO8i.png │ ├── TT2lmN4.png │ ├── do8589m.png │ └── jbSVFgy.png └── sounds │ ├── crr.mp3 │ ├── gameover.mp3 │ ├── pf1.mp3 │ ├── pf2.mp3 │ └── pf3.mp3 ├── Ejecta.xcodeproj └── project.pbxproj ├── README.md ├── Resources ├── Icon-60.png ├── Icon-60@2x.png ├── Icon-72.png ├── Icon-72@2x.png ├── Icon-76.png ├── Icon-76@2x.png ├── Icon.png ├── Icon@2x.png ├── Images-TV.xcassets │ ├── Contents.json │ └── LaunchImage.launchimage │ │ ├── Contents.json │ │ └── LaunchScreen-TV.png ├── Info-TV.plist ├── Info.plist ├── LaunchScreen.xib └── ejecta-logo.png ├── Source ├── AppDelegate.h ├── AppDelegate.m ├── Ejecta │ ├── EJAppViewController.h │ ├── EJAppViewController.m │ ├── EJAudio │ │ ├── EJAudioSource.h │ │ ├── EJAudioSourceAVAudio.h │ │ ├── EJAudioSourceAVAudio.m │ │ ├── EJAudioSourceOpenAL.h │ │ ├── EJAudioSourceOpenAL.m │ │ ├── EJBindingAudio.h │ │ ├── EJBindingAudio.m │ │ ├── EJOpenALBuffer.h │ │ ├── EJOpenALBuffer.m │ │ ├── EJSharedOpenALManager.h │ │ └── EJSharedOpenALManager.m │ ├── EJBindingBase.h │ ├── EJBindingBase.m │ ├── EJBindingEjectaCore.h │ ├── EJBindingEjectaCore.m │ ├── EJBindingEventedBase.h │ ├── EJBindingEventedBase.m │ ├── EJBindingVideo.h │ ├── EJBindingVideo.m │ ├── EJCanvas │ │ ├── 2D │ │ │ ├── EJBindingCanvasContext2D.h │ │ │ ├── EJBindingCanvasContext2D.m │ │ │ ├── EJBindingCanvasGradient.h │ │ │ ├── EJBindingCanvasGradient.m │ │ │ ├── EJBindingCanvasPattern.h │ │ │ ├── EJBindingCanvasPattern.m │ │ │ ├── EJBindingImageData.h │ │ │ ├── EJBindingImageData.m │ │ │ ├── EJBindingTextMetrics.h │ │ │ ├── EJBindingTextMetrics.m │ │ │ ├── EJCanvas2DTypes.h │ │ │ ├── EJCanvasContext2D.h │ │ │ ├── EJCanvasContext2D.m │ │ │ ├── EJCanvasContext2DScreen.h │ │ │ ├── EJCanvasContext2DScreen.m │ │ │ ├── EJCanvasContext2DTexture.h │ │ │ ├── EJCanvasContext2DTexture.m │ │ │ ├── EJCanvasGradient.h │ │ │ ├── EJCanvasGradient.m │ │ │ ├── EJCanvasPattern.h │ │ │ ├── EJCanvasPattern.m │ │ │ ├── EJCanvasShaders.h │ │ │ ├── EJConvertColorRGBA.h │ │ │ ├── EJConvertColorRGBA.m │ │ │ ├── EJFont.h │ │ │ ├── EJFont.mm │ │ │ ├── EJFontCache.h │ │ │ ├── EJFontCache.m │ │ │ ├── EJGLProgram2D.h │ │ │ ├── EJGLProgram2D.m │ │ │ ├── EJGLProgram2DRadialGradient.h │ │ │ ├── EJGLProgram2DRadialGradient.m │ │ │ ├── EJImageData.h │ │ │ ├── EJImageData.m │ │ │ ├── EJPath.h │ │ │ └── EJPath.mm │ │ ├── EAGLView.h │ │ ├── EAGLView.m │ │ ├── EJBindingCanvas.h │ │ ├── EJBindingCanvas.m │ │ ├── EJBindingCanvasStyle.h │ │ ├── EJBindingCanvasStyle.m │ │ ├── EJBindingImage.h │ │ ├── EJBindingImage.m │ │ ├── EJCanvasContext.h │ │ ├── EJCanvasContext.m │ │ ├── EJDrawable.h │ │ ├── EJPresentable.h │ │ ├── EJSharedTextureCache.h │ │ ├── EJSharedTextureCache.m │ │ ├── EJTexture.h │ │ ├── EJTexture.m │ │ ├── EJTextureStorage.h │ │ ├── EJTextureStorage.m │ │ └── WebGL │ │ │ ├── EJBindingCanvasContextWebGL.h │ │ │ ├── EJBindingCanvasContextWebGL.m │ │ │ ├── EJBindingWebGLExtensions.h │ │ │ ├── EJBindingWebGLExtensions.m │ │ │ ├── EJBindingWebGLObjects.h │ │ │ ├── EJBindingWebGLObjects.m │ │ │ ├── EJCanvasContextWebGL.h │ │ │ ├── EJCanvasContextWebGL.m │ │ │ ├── EJCanvasContextWebGLScreen.h │ │ │ ├── EJCanvasContextWebGLScreen.m │ │ │ ├── EJCanvasContextWebGLTexture.h │ │ │ ├── EJCanvasContextWebGLTexture.m │ │ │ ├── EJConvertWebGL.h │ │ │ └── EJConvertWebGL.m │ ├── EJClassLoader.h │ ├── EJClassLoader.m │ ├── EJConvert.h │ ├── EJConvert.m │ ├── EJJavaScriptView.h │ ├── EJJavaScriptView.m │ ├── EJNonRetainingProxy.h │ ├── EJNonRetainingProxy.m │ ├── EJSharedOpenGLContext.h │ ├── EJSharedOpenGLContext.m │ ├── EJTimer.h │ ├── EJTimer.m │ ├── EJUtils │ │ ├── EJBindingAdBanner.h │ │ ├── EJBindingAdBanner.m │ │ ├── EJBindingDeviceMotion.h │ │ ├── EJBindingDeviceMotion.m │ │ ├── EJBindingGameCenter.h │ │ ├── EJBindingGameCenter.m │ │ ├── EJBindingGeolocation.h │ │ ├── EJBindingGeolocation.m │ │ ├── EJBindingHttpRequest.h │ │ ├── EJBindingHttpRequest.m │ │ ├── EJBindingImagePicker.h │ │ ├── EJBindingImagePicker.m │ │ ├── EJBindingKeyInput.h │ │ ├── EJBindingKeyInput.m │ │ ├── EJBindingLocalStorage.h │ │ ├── EJBindingLocalStorage.m │ │ ├── EJBindingTouchInput.h │ │ ├── EJBindingTouchInput.m │ │ ├── EJBindingWebSocket.h │ │ ├── EJBindingWebSocket.m │ │ ├── EJBindingWindowEvents.h │ │ ├── EJBindingWindowEvents.m │ │ ├── Gamepad │ │ │ ├── EJBindingGamepad.h │ │ │ ├── EJBindingGamepad.m │ │ │ ├── EJBindingGamepadButton.h │ │ │ ├── EJBindingGamepadButton.m │ │ │ ├── EJBindingGamepadProvider.h │ │ │ └── EJBindingGamepadProvider.m │ │ └── IAP │ │ │ ├── EJBindingIAPManager.h │ │ │ ├── EJBindingIAPManager.m │ │ │ ├── EJBindingIAPProduct.h │ │ │ ├── EJBindingIAPProduct.m │ │ │ ├── EJBindingIAPTransaction.h │ │ │ └── EJBindingIAPTransaction.m │ └── Ejecta.js ├── Prefix.pch ├── lib │ ├── SocketRocket │ │ ├── SRWebSocket.h │ │ ├── SRWebSocket.m │ │ └── SocketRocket-Prefix.pch │ ├── ios │ │ └── JavaScriptCore.framework │ │ │ ├── Headers │ │ │ ├── JavaScriptCore │ │ │ └── Versions │ │ │ ├── A │ │ │ ├── Headers │ │ │ │ ├── JSBase.h │ │ │ │ ├── JSContext.h │ │ │ │ ├── JSContextRef.h │ │ │ │ ├── JSExport.h │ │ │ │ ├── JSManagedValue.h │ │ │ │ ├── JSObjectRef.h │ │ │ │ ├── JSStringRef.h │ │ │ │ ├── JSStringRefCF.h │ │ │ │ ├── JSTypedArray.h │ │ │ │ ├── JSValue.h │ │ │ │ ├── JSValueRef.h │ │ │ │ ├── JSVirtualMachine.h │ │ │ │ ├── JavaScript.h │ │ │ │ ├── JavaScriptCore.h │ │ │ │ └── WebKitAvailability.h │ │ │ └── JavaScriptCore │ │ │ └── Current │ └── tvos │ │ └── JavaScriptCore.framework │ │ ├── Headers │ │ ├── JavaScriptCore │ │ └── Versions │ │ ├── A │ │ ├── Headers │ │ │ ├── JSBase.h │ │ │ ├── JSContext.h │ │ │ ├── JSContextRef.h │ │ │ ├── JSExport.h │ │ │ ├── JSManagedValue.h │ │ │ ├── JSObjectRef.h │ │ │ ├── JSStringRef.h │ │ │ ├── JSStringRefCF.h │ │ │ ├── JSTypedArray.h │ │ │ ├── JSValue.h │ │ │ ├── JSValueRef.h │ │ │ ├── JSVirtualMachine.h │ │ │ ├── JavaScript.h │ │ │ ├── JavaScriptCore.h │ │ │ └── WebKitAvailability.h │ │ └── JavaScriptCore │ │ └── Current └── main.m ├── hot-server.js ├── package.json ├── server.js ├── src ├── AddFlakesRandomly.js ├── Flake.js ├── Game.js ├── appStateProvider.js ├── createFlake.js ├── index.js ├── junk-drawer-nothing-to-see-here │ ├── Ticker.js │ ├── raf.js │ └── random.js ├── materials.js ├── react-three-ejecta.js └── sounds.js ├── web ├── dev.html ├── images │ ├── 3BxEO8i.png │ ├── TT2lmN4.png │ ├── do8589m.png │ └── jbSVFgy.png ├── index.html └── sounds │ ├── crr.mp3 │ ├── gameover.mp3 │ ├── pf1.mp3 │ ├── pf2.mp3 │ └── pf3.mp3 ├── webpack.config.hot.js ├── webpack.config.js ├── webpack.config.web-dev.js └── webpack.config.web.js /.babelrc-future: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "jsx": true, 4 | "modules": true 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true 9 | }, 10 | "parser": "babel-eslint", 11 | "rules": { 12 | "no-undef": 2, 13 | "no-unused-vars": [2, { "args": "none" }], 14 | "quotes": [2, "single"], 15 | "strict": [2, "never"], 16 | "react/jsx-uses-react": 2, 17 | "react/jsx-uses-vars": 2, 18 | "react/react-in-jsx-scope": 2 19 | }, 20 | "plugins": [ 21 | "react" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | node_modules/ 19 | App/index.js 20 | App/index.js.map 21 | 22 | # Ignoring App folder for 23 | # ease of implementation 24 | # App 25 | -------------------------------------------------------------------------------- /App/images/3BxEO8i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/images/3BxEO8i.png -------------------------------------------------------------------------------- /App/images/TT2lmN4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/images/TT2lmN4.png -------------------------------------------------------------------------------- /App/images/do8589m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/images/do8589m.png -------------------------------------------------------------------------------- /App/images/jbSVFgy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/images/jbSVFgy.png -------------------------------------------------------------------------------- /App/sounds/crr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/sounds/crr.mp3 -------------------------------------------------------------------------------- /App/sounds/gameover.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/sounds/gameover.mp3 -------------------------------------------------------------------------------- /App/sounds/pf1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/sounds/pf1.mp3 -------------------------------------------------------------------------------- /App/sounds/pf2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/sounds/pf2.mp3 -------------------------------------------------------------------------------- /App/sounds/pf3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/App/sounds/pf3.mp3 -------------------------------------------------------------------------------- /Resources/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-60.png -------------------------------------------------------------------------------- /Resources/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-60@2x.png -------------------------------------------------------------------------------- /Resources/Icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-72.png -------------------------------------------------------------------------------- /Resources/Icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-72@2x.png -------------------------------------------------------------------------------- /Resources/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-76.png -------------------------------------------------------------------------------- /Resources/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon-76@2x.png -------------------------------------------------------------------------------- /Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon.png -------------------------------------------------------------------------------- /Resources/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Icon@2x.png -------------------------------------------------------------------------------- /Resources/Images-TV.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Resources/Images-TV.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "tv", 6 | "filename" : "LaunchScreen-TV.png", 7 | "extent" : "full-screen", 8 | "minimum-system-version" : "9.0", 9 | "scale" : "1x" 10 | } 11 | ], 12 | "info" : { 13 | "version" : 1, 14 | "author" : "xcode" 15 | } 16 | } -------------------------------------------------------------------------------- /Resources/Images-TV.xcassets/LaunchImage.launchimage/LaunchScreen-TV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/Images-TV.xcassets/LaunchImage.launchimage/LaunchScreen-TV.png -------------------------------------------------------------------------------- /Resources/Info-TV.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIcons 14 | 15 | CFBundlePrimaryIcon 16 | 17 | CFBundleIconFiles 18 | 19 | Icon.png 20 | Icon@2x.png 21 | Icon-60.png 22 | Icon-60@2x.png 23 | Icon-72.png 24 | Icon-72@2x.png 25 | Icon-76.png 26 | Icon-76@2x.png 27 | 28 | 29 | 30 | CFBundleIdentifier 31 | $(PRODUCT_BUNDLE_IDENTIFIER) 32 | CFBundleInfoDictionaryVersion 33 | 6.0 34 | CFBundleName 35 | ${PRODUCT_NAME} 36 | CFBundlePackageType 37 | APPL 38 | CFBundleSignature 39 | ???? 40 | CFBundleVersion 41 | 1.0 42 | LSRequiresIPhoneOS 43 | 44 | UIInterfaceOrientation 45 | UIInterfaceOrientationPortrait 46 | UIStatusBarHidden 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UISupportedInterfaceOrientations~ipad 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIcons 14 | 15 | CFBundlePrimaryIcon 16 | 17 | CFBundleIconFiles 18 | 19 | Icon.png 20 | Icon@2x.png 21 | Icon-60.png 22 | Icon-60@2x.png 23 | Icon-72.png 24 | Icon-72@2x.png 25 | Icon-76.png 26 | Icon-76@2x.png 27 | 28 | 29 | 30 | CFBundleIdentifier 31 | $(PRODUCT_BUNDLE_IDENTIFIER) 32 | CFBundleInfoDictionaryVersion 33 | 6.0 34 | CFBundleName 35 | ${PRODUCT_NAME} 36 | CFBundlePackageType 37 | APPL 38 | CFBundleSignature 39 | ???? 40 | CFBundleVersion 41 | 1.0 42 | LSRequiresIPhoneOS 43 | 44 | UIInterfaceOrientation 45 | UIInterfaceOrientationPortrait 46 | UILaunchStoryboardName 47 | LaunchScreen 48 | UIStatusBarHidden 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIRequiresFullScreen 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Resources/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Resources/ejecta-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Resources/ejecta-logo.png -------------------------------------------------------------------------------- /Source/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJAppViewController.h" 3 | 4 | @interface AppDelegate : NSObject 5 | 6 | @property (nonatomic, retain) UIWindow *window; 7 | @end 8 | 9 | -------------------------------------------------------------------------------- /Source/AppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | #import "AppDelegate.h" 3 | #import "EJJavaScriptView.h" 4 | @implementation AppDelegate 5 | @synthesize window; 6 | 7 | #pragma mark - 8 | #pragma mark Application lifecycle 9 | 10 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 11 | 12 | // Optionally set the idle timer disabled, this prevents the device from sleep when 13 | // not being interacted with by touch. ie. games with motion control. 14 | application.idleTimerDisabled = YES; 15 | 16 | window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; 17 | [self loadViewControllerWithScriptAtPath:@"index.js"]; 18 | 19 | [window makeKeyAndVisible]; 20 | return YES; 21 | } 22 | 23 | - (void)loadViewControllerWithScriptAtPath:(NSString *)path { 24 | // Release any previous ViewController 25 | window.rootViewController = nil; 26 | 27 | EJAppViewController *vc = [[EJAppViewController alloc] initWithScriptAtPath:path]; 28 | window.rootViewController = vc; 29 | [vc release]; 30 | } 31 | 32 | 33 | #pragma mark - 34 | #pragma mark Memory management 35 | 36 | - (void)dealloc { 37 | window.rootViewController = nil; 38 | [window release]; 39 | [super dealloc]; 40 | } 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAppViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EJAppViewController : UIViewController { 4 | BOOL landscapeMode; 5 | NSString *path; 6 | } 7 | 8 | - (id)initWithScriptAtPath:(NSString *)pathp; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAppViewController.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "EJAppViewController.h" 4 | #import "EJJavaScriptView.h" 5 | 6 | @implementation EJAppViewController 7 | 8 | - (id)initWithScriptAtPath:(NSString *)pathp { 9 | if( self = [super init] ) { 10 | path = [pathp retain]; 11 | if ([[NSBundle mainBundle] infoDictionary][@"UIInterfaceOrientation"]) 12 | { 13 | landscapeMode = [[[NSBundle mainBundle] infoDictionary][@"UIInterfaceOrientation"] hasPrefix:@"UIInterfaceOrientationLandscape"]; 14 | } 15 | else 16 | { 17 | landscapeMode = [[[NSBundle mainBundle] infoDictionary][@"UISupportedInterfaceOrientations"][0] hasPrefix:@"UIInterfaceOrientationLandscape"]; 18 | } 19 | } 20 | return self; 21 | } 22 | 23 | - (void)dealloc { 24 | self.view = nil; 25 | [path release]; 26 | [super dealloc]; 27 | } 28 | 29 | - (void)didReceiveMemoryWarning { 30 | [(EJJavaScriptView *)self.view clearCaches]; 31 | [super didReceiveMemoryWarning]; 32 | } 33 | 34 | - (void)loadView { 35 | CGRect frame = UIScreen.mainScreen.bounds; 36 | 37 | // iOS pre 8.0 doesn't rotate the frame size in landscape mode, so we have to 38 | // do it ourselfs 39 | if( landscapeMode && EJECTA_SYSTEM_VERSION_LESS_THAN(@"8.0") ) { 40 | frame.size = CGSizeMake(frame.size.height, frame.size.width); 41 | } 42 | 43 | EJJavaScriptView *view = [[EJJavaScriptView alloc] initWithFrame:frame]; 44 | self.view = view; 45 | 46 | [view loadScriptAtPath:path]; 47 | [view release]; 48 | } 49 | 50 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 51 | if( landscapeMode ) { 52 | // Allow Landscape Left and Right 53 | return UIInterfaceOrientationMaskLandscape; 54 | } 55 | else { 56 | if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) { 57 | // Allow Portrait UpsideDown on iPad 58 | return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; 59 | } 60 | else { 61 | // Only Allow Portrait 62 | return UIInterfaceOrientationMaskPortrait; 63 | } 64 | } 65 | } 66 | 67 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { 68 | // Deprecated in iOS6 - supportedInterfaceOrientations is the new way to do this 69 | // We just use the mask returned by supportedInterfaceOrientations here to check if 70 | // this particular orientation is allowed. 71 | return ( self.supportedInterfaceOrientations & (1 << orientation) ); 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJAudioSource.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol EJAudioSourceDelegate; 4 | @protocol EJAudioSource 5 | 6 | - (id)initWithPath:(NSString *)path; 7 | - (void)play; 8 | - (void)pause; 9 | - (void)setLooping:(BOOL)loop; 10 | - (void)setVolume:(float)volume; 11 | - (void)setPlaybackRate:(float)playbackRate; 12 | 13 | @property (nonatomic) float duration; 14 | @property (nonatomic) float currentTime; 15 | @property (nonatomic, assign) NSObject *delegate; 16 | 17 | @end 18 | 19 | @protocol EJAudioSourceDelegate 20 | - (void)sourceDidFinishPlaying:(NSObject *)source; 21 | @end 22 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJAudioSourceAVAudio.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "EJAudioSource.h" 5 | 6 | @interface EJAudioSourceAVAudio : NSObject { 7 | NSString *path; 8 | AVAudioPlayer *player; 9 | NSObject *delegate; 10 | } 11 | 12 | @property (nonatomic) float currentTime; 13 | @property (nonatomic) float duration; 14 | @property (nonatomic, assign) NSObject *delegate; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJAudioSourceAVAudio.m: -------------------------------------------------------------------------------- 1 | #import "EJAudioSourceAVAudio.h" 2 | 3 | 4 | @implementation EJAudioSourceAVAudio 5 | 6 | @synthesize delegate; 7 | 8 | - (id)initWithPath:(NSString *)pathp { 9 | if( self = [super init] ) { 10 | path = [pathp retain]; 11 | player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil]; 12 | player.delegate = self; 13 | } 14 | return self; 15 | } 16 | 17 | - (void)dealloc { 18 | [path release]; 19 | [player release]; 20 | 21 | [super dealloc]; 22 | } 23 | 24 | - (void)play { 25 | [player play]; 26 | } 27 | 28 | - (void)pause { 29 | [player pause]; 30 | } 31 | 32 | - (void)setLooping:(BOOL)loop { 33 | player.numberOfLoops = loop ? -1 : 0; 34 | } 35 | 36 | - (void)setVolume:(float)volume { 37 | player.volume = volume; 38 | } 39 | 40 | - (void)setPlaybackRate:(float)playbackRate { 41 | player.enableRate = YES; 42 | player.rate = playbackRate; 43 | } 44 | 45 | - (float)currentTime { 46 | return player.currentTime; 47 | } 48 | 49 | - (void)setCurrentTime:(float)time { 50 | player.currentTime = time; 51 | } 52 | 53 | - (float)duration { 54 | return player.duration; 55 | } 56 | 57 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { 58 | [delegate sourceDidFinishPlaying:self]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJAudioSourceOpenAL.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | 6 | #import "EJAudioSource.h" 7 | #import "EJSharedOpenALManager.h" 8 | #import "EJOpenALBuffer.h" 9 | 10 | @interface EJAudioSourceOpenAL : NSObject { 11 | NSString *path; 12 | unsigned int sourceId; 13 | EJOpenALBuffer *buffer; 14 | BOOL looping; 15 | 16 | NSTimer *endTimer; 17 | NSObject *delegate; 18 | } 19 | 20 | @property (nonatomic) float currentTime; 21 | @property (nonatomic) float duration; 22 | @property (nonatomic, assign) NSObject *delegate; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJAudioSourceOpenAL.m: -------------------------------------------------------------------------------- 1 | #import "EJAudioSourceOpenAL.h" 2 | #import "EJAppViewController.h" 3 | 4 | @implementation EJAudioSourceOpenAL 5 | 6 | @synthesize delegate; 7 | 8 | - (id)initWithPath:(NSString *)pathp { 9 | if( self = [super init] ) { 10 | path = [pathp retain]; 11 | 12 | buffer = [[EJOpenALBuffer cachedBufferWithPath:pathp] retain]; 13 | 14 | alGenSources(1, &sourceId); 15 | alSourcei(sourceId, AL_BUFFER, buffer.bufferId); 16 | alSourcef(sourceId, AL_PITCH, 1.0f); 17 | alSourcef(sourceId, AL_GAIN, 1.0f); 18 | } 19 | return self; 20 | } 21 | 22 | - (void)dealloc { 23 | if( sourceId ) { 24 | alDeleteSources(1, &sourceId); 25 | } 26 | 27 | [buffer release]; 28 | [path release]; 29 | [endTimer invalidate]; 30 | 31 | [super dealloc]; 32 | } 33 | 34 | - (void)play { 35 | alSourcePlay( sourceId ); 36 | 37 | [endTimer invalidate]; 38 | 39 | float targetTime = buffer.duration - self.currentTime; 40 | endTimer = [NSTimer scheduledTimerWithTimeInterval:targetTime 41 | target:self selector:@selector(ended:) userInfo:nil repeats:NO]; 42 | } 43 | 44 | - (void)pause { 45 | alSourceStop( sourceId ); 46 | [endTimer invalidate]; 47 | endTimer = nil; 48 | } 49 | 50 | - (void)setLooping:(BOOL)loop { 51 | looping = loop; 52 | alSourcei( sourceId, AL_LOOPING, loop ? AL_TRUE : AL_FALSE ); 53 | } 54 | 55 | - (void)setVolume:(float)volume { 56 | alSourcef( sourceId, AL_GAIN, volume ); 57 | } 58 | 59 | - (void)setPlaybackRate:(float)playbackRate { 60 | alSourcef( sourceId, AL_PITCH, playbackRate); 61 | } 62 | 63 | - (float)currentTime { 64 | float time; 65 | alGetSourcef( sourceId, AL_SEC_OFFSET, &time ); 66 | return time; 67 | } 68 | 69 | - (void)setCurrentTime:(float)time { 70 | alSourcef( sourceId, AL_SEC_OFFSET, time ); 71 | } 72 | 73 | - (float)duration { 74 | return buffer.duration; 75 | } 76 | 77 | - (void)ended:(NSTimer *)timer { 78 | endTimer = nil; 79 | if( !looping ) { 80 | [delegate sourceDidFinishPlaying:self]; 81 | } 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJBindingAudio.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | 4 | #import "EJAudioSourceOpenAL.h" 5 | #import "EJAudioSourceAVAudio.h" 6 | 7 | // Max file size of audio effects using OpenAL; beyond that, the AVAudioPlayer is used 8 | #define EJ_AUDIO_OPENAL_MAX_SIZE 512 * 1024 // 512kb 9 | 10 | 11 | typedef enum { 12 | kEJAudioPreloadNone, 13 | kEJAudioPreloadMetadata, 14 | kEJAudioPreloadAuto 15 | } EJAudioPreload; 16 | 17 | typedef enum { 18 | kEJAudioHaveNothing = 0, 19 | kEJAudioHaveMetadata = 1, 20 | kEJAudioHaveCurrentData = 2, 21 | kEJAudioHaveFutureData = 3, 22 | kEJAudioHaveEnoughData = 4 23 | } EJAudioReadyState; 24 | 25 | @interface EJBindingAudio : EJBindingEventedBase { 26 | NSString *path; 27 | EJAudioPreload preload; 28 | NSObject *source; 29 | 30 | BOOL loop, ended, paused, muted; 31 | BOOL loading, playAfterLoad; 32 | float volume, playbackRate; 33 | NSOperation *loadCallback; 34 | } 35 | 36 | - (void)load; 37 | - (void)setSourcePath:(NSString *)pathp; 38 | 39 | @property (nonatomic) BOOL loop; 40 | @property (nonatomic) BOOL ended; 41 | @property (nonatomic) float volume; 42 | @property (nonatomic, retain) NSString *path; 43 | @property (nonatomic) EJAudioPreload preload; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJOpenALBuffer.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | 6 | @interface EJOpenALBuffer : NSObject { 7 | unsigned int bufferId; 8 | ALenum format; 9 | ALsizei size; 10 | ALsizei sampleRate; 11 | 12 | NSString *path; 13 | float duration; 14 | } 15 | 16 | + (id)cachedBufferWithPath:(NSString *)path; 17 | - (id)initWithPath:(NSString *)pathp; 18 | - (void*)getAudioDataWithURL:(NSURL *)url; 19 | 20 | @property (readonly) unsigned int bufferId; 21 | @property (readonly) float duration; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJSharedOpenALManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | 6 | @interface EJSharedOpenALManager : NSObject { 7 | ALCcontext *context; 8 | ALCdevice *device; 9 | NSMutableDictionary *buffers; 10 | } 11 | 12 | + (EJSharedOpenALManager *)instance; 13 | @property (readonly, nonatomic) NSMutableDictionary *buffers; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Source/Ejecta/EJAudio/EJSharedOpenALManager.m: -------------------------------------------------------------------------------- 1 | #import "EJSharedOpenALManager.h" 2 | 3 | @implementation EJSharedOpenALManager 4 | 5 | static EJSharedOpenALManager *sharedOpenALManager; 6 | 7 | + (EJSharedOpenALManager *)instance { 8 | if( !sharedOpenALManager ) { 9 | sharedOpenALManager = [[[EJSharedOpenALManager alloc] init] autorelease]; 10 | } 11 | return sharedOpenALManager; 12 | } 13 | 14 | - (NSMutableDictionary*)buffers { 15 | if( !buffers ) { 16 | // Create a non-retaining Dictionary to hold the cached buffers 17 | buffers = (NSMutableDictionary*)CFDictionaryCreateMutable(NULL, 8, &kCFCopyStringDictionaryKeyCallBacks, NULL); 18 | 19 | // Create the OpenAL device when .buffers is first accessed 20 | device = alcOpenDevice(NULL); 21 | if( device ) { 22 | context = alcCreateContext( device, NULL ); 23 | alcMakeContextCurrent( context ); 24 | } 25 | } 26 | 27 | return buffers; 28 | } 29 | 30 | - (void)dealloc { 31 | sharedOpenALManager = nil; 32 | [buffers release]; 33 | 34 | if( context ) { alcDestroyContext( context ); } 35 | if( device ) { alcCloseDevice( device ); } 36 | [super dealloc]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Source/Ejecta/EJBindingBase.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJClassLoader.h" 3 | #import 4 | 5 | 6 | @implementation EJBindingBase 7 | @synthesize scriptView; 8 | 9 | - (id)initWithContext:(JSContextRef)ctxp argc:(size_t)argc argv:(const JSValueRef [])argv { 10 | if( self = [super init] ) { 11 | } 12 | return self; 13 | } 14 | 15 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 16 | jsObject = obj; 17 | scriptView = view; 18 | } 19 | 20 | - (void)prepareGarbageCollection { 21 | // Called in EJBindingBaseFinalize before sending 'release'. 22 | // Cancel loading callbacks and the like here. 23 | } 24 | 25 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 26 | scriptView:(EJJavaScriptView *)scriptView 27 | instance:(EJBindingBase *)instance 28 | { 29 | // Create JSObject with the JSClass for this ObjC-Class 30 | EJLoadedJSClass *class = [scriptView.classLoader getJSClass:self]; 31 | JSObjectRef obj = JSObjectMake( ctx, class.jsClass, NULL ); 32 | 33 | // Attach all constant values to the object. Doing this on instantiation is a bit slower 34 | // than just having the callbacks in the StaticProperties, but it makes access to them 35 | // much faster because we never have to leave JS land. This is especially important for 36 | // the CanvasContextWebGL which has A LOT of const values. 37 | NSDictionary *constantValues = class.constantValues; 38 | 39 | for( NSString* key in constantValues ) { 40 | NSObject *value = [constantValues objectForKey:key]; 41 | JSValueRef jsValue = [value isKindOfClass:NSString.class] 42 | ? NSStringToJSValue(ctx, (NSString *)value) 43 | : JSValueMakeNumber(ctx, ((NSNumber *)value).doubleValue); 44 | 45 | JSStringRef name = JSStringCreateWithCFString((CFStringRef)key); 46 | JSObjectSetProperty( 47 | ctx, obj, name, jsValue, 48 | kJSPropertyAttributeReadOnly|kJSPropertyAttributeDontDelete, NULL 49 | ); 50 | JSStringRelease(name); 51 | } 52 | 53 | // The JSObject retains the instance; it will be released by EJBindingBaseFinalize 54 | JSObjectSetPrivate( obj, (void *)[instance retain] ); 55 | [instance createWithJSObject:obj scriptView:scriptView]; 56 | 57 | return obj; 58 | } 59 | 60 | void EJBindingBaseFinalize(JSObjectRef object) { 61 | EJBindingBase *instance = (EJBindingBase *)JSObjectGetPrivate(object); 62 | [instance prepareGarbageCollection]; 63 | [instance release]; 64 | } 65 | 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Source/Ejecta/EJBindingEjectaCore.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | #import "EJFont.h" 4 | 5 | typedef enum { 6 | kEJCoreAudioSessionAmbient, 7 | kEJCoreAudioSessionSoloAmbient, 8 | kEJCoreAudioSessionPlayback 9 | } EJCoreAudioSession; 10 | 11 | @interface EJBindingEjectaCore : EJBindingBase { 12 | NSString *deviceName; 13 | EJCoreAudioSession audioSession; 14 | NSTimeInterval baseTime; 15 | } 16 | 17 | @property (readwrite, nonatomic) EJCoreAudioSession audioSession; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Source/Ejecta/EJBindingEventedBase.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | 3 | 4 | // ------------------------------------------------------------------------------------ 5 | // Events; shorthand for EJ_BIND_GET/SET - use with EJ_BIND_EVENT( eventname ); 6 | 7 | #define EJ_BIND_EVENT(NAME) \ 8 | static JSValueRef _get_on##NAME( \ 9 | JSContextRef ctx, \ 10 | JSObjectRef object, \ 11 | JSStringRef propertyName, \ 12 | JSValueRef* exception \ 13 | ) { \ 14 | EJBindingEventedBase *instance = (EJBindingEventedBase*)JSObjectGetPrivate(object); \ 15 | return [instance getCallbackWithType:( @ #NAME) ctx:ctx]; \ 16 | } \ 17 | __EJ_GET_POINTER_TO(_get_on##NAME) \ 18 | \ 19 | static bool _set_on##NAME( \ 20 | JSContextRef ctx, \ 21 | JSObjectRef object, \ 22 | JSStringRef propertyName, \ 23 | JSValueRef value, \ 24 | JSValueRef* exception \ 25 | ) { \ 26 | EJBindingEventedBase *instance = (EJBindingEventedBase*)JSObjectGetPrivate(object); \ 27 | [instance setCallbackWithType:( @ #NAME) ctx:ctx callback:value]; \ 28 | return true; \ 29 | } \ 30 | __EJ_GET_POINTER_TO(_set_on##NAME) 31 | 32 | 33 | typedef struct { 34 | const char *name; 35 | JSValueRef value; 36 | } JSEventProperty; 37 | 38 | @interface EJBindingEventedBase : EJBindingBase { 39 | NSMutableDictionary *eventListeners; // for addEventListener 40 | NSMutableDictionary *onCallbacks; // for on* setters 41 | } 42 | 43 | - (JSObjectRef)getCallbackWithType:(NSString *)type ctx:(JSContextRef)ctx; 44 | - (void)setCallbackWithType:(NSString *)type ctx:(JSContextRef)ctx callback:(JSValueRef)callback; 45 | - (void)triggerEvent:(NSString *)type argc:(int)argc argv:(JSValueRef[])argv; 46 | - (void)triggerEvent:(NSString *)type properties:(JSEventProperty[])properties; 47 | - (void)triggerEvent:(NSString *)type; 48 | 49 | @end 50 | 51 | 52 | @interface EJBindingEvent : EJBindingBase { 53 | NSString *type; 54 | JSObjectRef jsTarget; 55 | } 56 | 57 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 58 | scriptView:(EJJavaScriptView *)scriptView 59 | type:(NSString *)type 60 | target:(JSObjectRef)target; 61 | 62 | @end 63 | 64 | -------------------------------------------------------------------------------- /Source/Ejecta/EJBindingVideo.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingEventedBase.h" 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | 8 | @interface EJBindingVideo : EJBindingEventedBase { 9 | NSString *path; 10 | BOOL loaded; 11 | BOOL ended; 12 | BOOL loop; 13 | AVPlayerViewController *controller; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingCanvasContext2D.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingBase.h" 3 | #import "EJCanvasContext2D.h" 4 | 5 | @interface EJBindingCanvasContext2D : EJBindingBase { 6 | JSObjectRef jsCanvas; 7 | EJCanvasContext2D *renderingContext; 8 | } 9 | 10 | - (id)initWithRenderingContext:(EJCanvasContext2D *)renderingContextp; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingCanvasGradient.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJCanvasGradient.h" 3 | 4 | @interface EJBindingCanvasGradient : EJBindingBase { 5 | EJCanvasGradient *gradient; 6 | } 7 | 8 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 9 | scriptView:(EJJavaScriptView *)scriptView 10 | gradient:(EJCanvasGradient *)gradient; 11 | + (EJCanvasGradient *)gradientFromJSValue:(JSValueRef)value; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingCanvasGradient.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingCanvasGradient.h" 2 | #import "EJConvertColorRGBA.h" 3 | 4 | @implementation EJBindingCanvasGradient 5 | 6 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 7 | scriptView:(EJJavaScriptView *)view 8 | gradient:(EJCanvasGradient *)gradient 9 | { 10 | EJBindingCanvasGradient *binding = [[EJBindingCanvasGradient alloc] initWithContext:ctx argc:0 argv:NULL]; 11 | binding->gradient = [gradient retain]; 12 | 13 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:binding]; 14 | [binding release]; 15 | return obj; 16 | } 17 | 18 | + (EJCanvasGradient *)gradientFromJSValue:(JSValueRef)value { 19 | if( !value ) { return NULL; } 20 | 21 | EJBindingCanvasGradient *binding = (EJBindingCanvasGradient *)JSValueGetPrivate(value); 22 | return (binding && [binding isKindOfClass:[EJBindingCanvasGradient class]]) ? binding->gradient : NULL; 23 | } 24 | 25 | - (void)dealloc { 26 | [gradient release]; 27 | [super dealloc]; 28 | } 29 | 30 | EJ_BIND_FUNCTION(addColorStop, ctx, argc, argv) { 31 | if( argc < 2 ) { return NULL; } 32 | 33 | float offset = JSValueToNumberFast(ctx, argv[0]); 34 | if( offset < 0 || offset > 1 ) { return NULL; } 35 | 36 | EJColorRGBA color = JSValueToColorRGBA(ctx, argv[1]); 37 | 38 | [gradient addStopWithColor:color at:offset]; 39 | return NULL; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingCanvasPattern.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJCanvasPattern.h" 3 | 4 | @interface EJBindingCanvasPattern : EJBindingBase { 5 | EJCanvasPattern *pattern; 6 | } 7 | 8 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 9 | scriptView:(EJJavaScriptView *)scriptView 10 | pattern:(EJCanvasPattern *)pattern; 11 | + (EJCanvasPattern *)patternFromJSValue:(JSValueRef)value; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingCanvasPattern.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingCanvasPattern.h" 2 | 3 | @implementation EJBindingCanvasPattern 4 | 5 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 6 | scriptView:(EJJavaScriptView *)view 7 | pattern:(EJCanvasPattern *)pattern 8 | { 9 | EJBindingCanvasPattern *binding = [[EJBindingCanvasPattern alloc] initWithContext:ctx argc:0 argv:NULL]; 10 | binding->pattern = [pattern retain]; 11 | 12 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:binding]; 13 | [binding release]; 14 | return obj; 15 | } 16 | 17 | + (EJCanvasPattern *)patternFromJSValue:(JSValueRef)value { 18 | if( !value ) { return NULL; } 19 | 20 | EJBindingCanvasPattern *binding = (EJBindingCanvasPattern *)JSValueGetPrivate(value); 21 | return (binding && [binding isKindOfClass:[EJBindingCanvasPattern class]]) ? binding->pattern : NULL; 22 | } 23 | 24 | - (void)dealloc { 25 | [pattern release]; 26 | [super dealloc]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingImageData.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJImageData.h" 3 | #import "EJDrawable.h" 4 | 5 | @interface EJBindingImageData : EJBindingBase { 6 | EJImageData *imageData; 7 | JSObjectRef dataArray; 8 | } 9 | 10 | - (id)initWithImageData:(EJImageData *)data; 11 | 12 | @property (readonly, nonatomic) EJImageData *imageData; 13 | @property (readonly, nonatomic) EJTexture *texture; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingImageData.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingImageData.h" 2 | #import "EJJavaScriptView.h" 3 | #import 4 | 5 | @implementation EJBindingImageData 6 | @synthesize imageData; 7 | 8 | - (id)initWithImageData:(EJImageData *)data { 9 | if( self = [super initWithContext:NULL argc:0 argv:NULL] ) { 10 | imageData = [data retain]; 11 | dataArray = NULL; 12 | } 13 | return self; 14 | } 15 | 16 | - (void)dealloc { 17 | if( dataArray ) { 18 | JSValueUnprotectSafe(scriptView.jsGlobalContext, dataArray); 19 | } 20 | 21 | [imageData release]; 22 | [super dealloc]; 23 | } 24 | 25 | - (EJImageData *)imageData { 26 | if( dataArray ) { 27 | // Copy values from the JSArray back into the imageData and premultiply it 28 | int byteLength = imageData.width * imageData.height * 4; 29 | 30 | [EJTexture 31 | premultiplyPixels:JSObjectGetTypedArrayDataPtr(scriptView.jsGlobalContext, dataArray, NULL) 32 | to:imageData.pixels.mutableBytes 33 | byteLength:byteLength format:GL_RGBA]; 34 | } 35 | 36 | return imageData; 37 | } 38 | 39 | - (EJTexture *)texture { 40 | return imageData.texture; 41 | } 42 | 43 | EJ_BIND_GET(data, ctx ) { 44 | if( !dataArray ) { 45 | // Copy values from image data into a JSArray and unpremultiply it 46 | int byteLength = imageData.width * imageData.height * 4; 47 | 48 | dataArray = JSObjectMakeTypedArray(ctx, kJSTypedArrayTypeUint8ClampedArray, byteLength); 49 | JSValueProtect(ctx, dataArray); 50 | 51 | [EJTexture 52 | unPremultiplyPixels:imageData.pixels.bytes 53 | to:JSObjectGetTypedArrayDataPtr(ctx, dataArray, NULL) 54 | byteLength:byteLength format:GL_RGBA]; 55 | } 56 | return dataArray; 57 | } 58 | 59 | EJ_BIND_GET(width, ctx ) { 60 | return JSValueMakeNumber( ctx, imageData.width); 61 | } 62 | 63 | EJ_BIND_GET(height, ctx ) { 64 | return JSValueMakeNumber( ctx, imageData.height ); 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingTextMetrics.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJFont.h" 3 | 4 | @interface EJBindingTextMetrics : EJBindingBase { 5 | EJTextMetrics metrics; 6 | } 7 | 8 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx scriptView:(EJJavaScriptView *)scriptView metrics:(EJTextMetrics)metrics; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJBindingTextMetrics.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingTextMetrics.h" 2 | 3 | @implementation EJBindingTextMetrics 4 | 5 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 6 | scriptView:(EJJavaScriptView *)view 7 | metrics:(EJTextMetrics)metrics 8 | { 9 | EJBindingTextMetrics *binding = [[EJBindingTextMetrics alloc] initWithContext:ctx argc:0 argv:NULL]; 10 | binding->metrics = metrics; 11 | 12 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:binding]; 13 | [binding release]; 14 | return obj; 15 | } 16 | 17 | EJ_BIND_GET(width, ctx) { 18 | return JSValueMakeNumber(ctx, metrics.width); 19 | } 20 | 21 | EJ_BIND_GET(actualBoundingBoxAscent, ctx) { 22 | return JSValueMakeNumber(ctx, metrics.ascent); 23 | } 24 | 25 | EJ_BIND_GET(actualBoundingBoxDescent, ctx) { 26 | return JSValueMakeNumber(ctx, metrics.descent); 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvas2DTypes.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | typedef union { 5 | struct { 6 | unsigned char r, g, b, a; 7 | } rgba; 8 | unsigned char components[4]; 9 | unsigned int hex; 10 | } EJColorRGBA; 11 | 12 | typedef struct { 13 | float x, y; 14 | } EJVector2; 15 | 16 | typedef struct { 17 | EJVector2 pos; 18 | EJVector2 uv; 19 | EJColorRGBA color; 20 | } EJVertex; 21 | 22 | 23 | static inline EJVector2 EJVector2Make( float x, float y ) { 24 | EJVector2 p = {x, y}; 25 | return p; 26 | } 27 | 28 | static inline EJVector2 EJVector2Add( EJVector2 a, EJVector2 b ) { 29 | EJVector2 p = {a.x + b.x, a.y + b.y}; 30 | return p; 31 | } 32 | 33 | static inline EJVector2 EJVector2Sub( EJVector2 a, EJVector2 b ) { 34 | EJVector2 p = {a.x - b.x, a.y - b.y}; 35 | return p; 36 | } 37 | 38 | static inline EJVector2 EJVector2Normalize( EJVector2 v ) { 39 | double ln = sqrtf( v.x*v.x + v.y*v.y ); 40 | if (ln == 0) { return v; } 41 | 42 | v.x /= ln; 43 | v.y /= ln; 44 | return v; 45 | } 46 | 47 | static inline float EJVector2Length( EJVector2 v ) { 48 | return sqrtf( v.x*v.x + v.y*v.y ); 49 | } 50 | 51 | static inline float EJVector2LengthSquared( EJVector2 v ) { 52 | return v.x*v.x + v.y*v.y; 53 | } 54 | 55 | static inline float EJVector2Dot( const EJVector2 v1, const EJVector2 v2 ) { 56 | return v1.x * v2.x + v1.y * v2.y; 57 | } 58 | 59 | static inline float EJVector2Distance( const EJVector2 v1, const EJVector2 v2 ) { 60 | return (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y); 61 | } 62 | 63 | static inline float EJDistanceToLineSegmentSquared(const EJVector2 p, const EJVector2 v, const EJVector2 w) { 64 | float l2 = EJVector2Distance(v, w); 65 | if (l2 == 0) return EJVector2Distance(p, v); 66 | float t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2; 67 | if (t < 0) return EJVector2Distance(p, v); 68 | if (t > 1) return EJVector2Distance(p, w); 69 | return EJVector2Distance(p, EJVector2Make(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y) )); 70 | } 71 | 72 | static inline float EJDistanceToLineSegment(const EJVector2 p, const EJVector2 v, const EJVector2 w) { 73 | return sqrtf(EJDistanceToLineSegmentSquared(p,v,w)); 74 | } 75 | 76 | static inline EJVector2 EJVector2ApplyTransform(EJVector2 p, CGAffineTransform t) { 77 | EJVector2 pt = { 78 | t.a * p.x + t.c * p.y + t.tx, 79 | t.b * p.x + t.d * p.y + t.ty 80 | }; 81 | return pt; 82 | } 83 | 84 | static inline float CGAffineTransformGetScale( CGAffineTransform t ) { 85 | return sqrtf( t.a*t.a + t.c*t.c ); 86 | } 87 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasContext2DScreen.h: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContext2D.h" 2 | #import "EAGLView.h" 3 | #import "EJPresentable.h" 4 | 5 | @interface EJCanvasContext2DScreen : EJCanvasContext2D { 6 | EAGLView *glview; 7 | CGRect style; 8 | } 9 | 10 | - (void)present; 11 | - (void)finish; 12 | 13 | @property (readonly, nonatomic) EJTexture *texture; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasContext2DScreen.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJCanvasContext2DScreen.h" 3 | #import "EJJavaScriptView.h" 4 | 5 | @implementation EJCanvasContext2DScreen 6 | @synthesize style; 7 | 8 | - (void)dealloc { 9 | [glview removeFromSuperview]; 10 | [glview release]; 11 | [super dealloc]; 12 | } 13 | 14 | - (void)setStyle:(CGRect)newStyle { 15 | if( 16 | (style.size.width ? style.size.width : width) != newStyle.size.width || 17 | (style.size.height ? style.size.height : height) != newStyle.size.height 18 | ) { 19 | // Must resize 20 | style = newStyle; 21 | 22 | // Only resize if we already have a viewFrameBuffer. Otherwise the style 23 | // will be honored in the 'create' call. 24 | if( viewFrameBuffer ) { 25 | [self resizeToWidth:width height:height]; 26 | } 27 | } 28 | else { 29 | // Just reposition 30 | style = newStyle; 31 | if( glview ) { 32 | glview.frame = self.frame; 33 | } 34 | } 35 | } 36 | 37 | - (CGRect)frame { 38 | // Returns the view frame with the current style. If the style's witdth/height 39 | // is zero, the canvas width/height is used 40 | return CGRectMake( 41 | style.origin.x, 42 | style.origin.y, 43 | (style.size.width ? style.size.width : width), 44 | (style.size.height ? style.size.height : height) 45 | ); 46 | } 47 | 48 | - (void)resizeToWidth:(short)newWidth height:(short)newHeight { 49 | [self flushBuffers]; 50 | 51 | bufferWidth = width = newWidth; 52 | bufferHeight = height = newHeight; 53 | 54 | CGRect frame = self.frame; 55 | float contentScale = bufferWidth / frame.size.width; 56 | 57 | NSLog( 58 | @"Creating ScreenCanvas (2D): " 59 | @"size: %dx%d, " 60 | @"style: %.0fx%.0f, " 61 | @"antialias: %@, preserveDrawingBuffer: %@", 62 | width, height, 63 | frame.size.width, frame.size.height, 64 | (msaaEnabled ? [NSString stringWithFormat:@"yes (%d samples)", msaaSamples] : @"no"), 65 | (preserveDrawingBuffer ? @"yes" : @"no") 66 | ); 67 | 68 | 69 | if( !glview ) { 70 | // Create the OpenGL UIView with final screen size and content scaling (retina) 71 | glview = [[EAGLView alloc] initWithFrame:frame contentScale:contentScale retainedBacking:preserveDrawingBuffer]; 72 | 73 | // Append the OpenGL view to Ejecta's main view 74 | [scriptView addSubview:glview]; 75 | } 76 | else { 77 | // Resize an existing view 78 | glview.frame = frame; 79 | glview.contentScaleFactor = contentScale; 80 | glview.layer.contentsScale = contentScale; 81 | } 82 | 83 | // Set up the renderbuffer 84 | glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer); 85 | [glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)glview.layer]; 86 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderBuffer); 87 | 88 | // Flip the screen - OpenGL has the origin in the bottom left corner. We want the top left. 89 | upsideDown = true; 90 | 91 | [super resetFramebuffer]; 92 | } 93 | 94 | - (void)finish { 95 | glFinish(); 96 | } 97 | 98 | - (void)present { 99 | [self flushBuffers]; 100 | 101 | if( !needsPresenting ) { return; } 102 | 103 | if( msaaEnabled ) { 104 | //Bind the MSAA and View frameBuffers and resolve 105 | glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, msaaFrameBuffer); 106 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, viewFrameBuffer); 107 | glResolveMultisampleFramebufferAPPLE(); 108 | 109 | glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer); 110 | [glContext presentRenderbuffer:GL_RENDERBUFFER]; 111 | glBindFramebuffer(GL_FRAMEBUFFER, msaaFrameBuffer); 112 | } 113 | else { 114 | [glContext presentRenderbuffer:GL_RENDERBUFFER]; 115 | } 116 | needsPresenting = NO; 117 | } 118 | 119 | - (EJTexture *)texture { 120 | // This context may not be the current one, but it has to be in order for 121 | // glReadPixels to succeed. 122 | EJCanvasContext *previousContext = scriptView.currentRenderingContext; 123 | scriptView.currentRenderingContext = self; 124 | 125 | EJTexture *texture = [self getImageDataSx:0 sy:0 sw:width sh:height].texture; 126 | 127 | scriptView.currentRenderingContext = previousContext; 128 | return texture; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasContext2DTexture.h: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContext2D.h" 2 | 3 | @interface EJCanvasContext2DTexture : EJCanvasContext2D { 4 | EJTexture *texture; 5 | } 6 | 7 | @property (readonly, nonatomic) EJTexture *texture; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasContext2DTexture.m: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContext2DTexture.h" 2 | #import "EJJavaScriptView.h" 3 | 4 | @implementation EJCanvasContext2DTexture 5 | 6 | - (void)dealloc { 7 | [texture release]; 8 | [super dealloc]; 9 | } 10 | 11 | - (void)resizeToWidth:(short)newWidth height:(short)newHeight { 12 | [self flushBuffers]; 13 | 14 | bufferWidth = width = newWidth; 15 | bufferHeight = height = newHeight; 16 | 17 | NSLog( 18 | @"Creating Offscreen Canvas (2D): " 19 | @"size: %dx%d, " 20 | @"antialias: %@", 21 | width, height, 22 | (msaaEnabled ? [NSString stringWithFormat:@"yes (%d samples)", msaaSamples] : @"no") 23 | ); 24 | 25 | // Release previous texture if any, create the new texture and set it as 26 | // the rendering target for this framebuffer 27 | [texture release]; 28 | texture = [[EJTexture alloc] initAsRenderTargetWithWidth:newWidth height:newHeight 29 | fbo:viewFrameBuffer]; 30 | 31 | glBindFramebuffer(GL_FRAMEBUFFER, viewFrameBuffer); 32 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.textureId, 0); 33 | 34 | [self resetFramebuffer]; 35 | } 36 | 37 | - (EJTexture *)texture { 38 | // If this texture Canvas uses MSAA, we need to resolve the MSAA first, 39 | // before we can use the texture for drawing. 40 | if( msaaEnabled && needsPresenting ) { 41 | GLint boundFrameBuffer; 42 | glGetIntegerv( GL_FRAMEBUFFER_BINDING, &boundFrameBuffer ); 43 | 44 | //Bind the MSAA and View frameBuffers and resolve 45 | glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, msaaFrameBuffer); 46 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, viewFrameBuffer); 47 | glResolveMultisampleFramebufferAPPLE(); 48 | 49 | glBindFramebuffer(GL_FRAMEBUFFER, boundFrameBuffer); 50 | needsPresenting = NO; 51 | } 52 | 53 | // Special case where this canvas is drawn into itself - we have to use glReadPixels to get a texture 54 | if( scriptView.currentRenderingContext == self ) { 55 | return [self getImageDataSx:0 sy:0 sw:width sh:height].texture; 56 | } 57 | 58 | // Just use the framebuffer texture directly 59 | else { 60 | return texture; 61 | } 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasGradient.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJCanvas2DTypes.h" 3 | #import "EJCanvasContext2D.h" 4 | #import "EJTexture.h" 5 | 6 | #define EJ_CANVAS_GRADIENT_WIDTH 1024 7 | 8 | typedef enum { 9 | kEJCanvasGradientTypeLinear, 10 | kEJCanvasGradientTypeRadial 11 | } EJCanvasGradientType; 12 | 13 | typedef struct { 14 | float pos; 15 | unsigned int order; 16 | EJColorRGBA color; 17 | } EJCanvasGradientColorStop; 18 | 19 | @interface EJCanvasGradient : NSObject { 20 | EJCanvasGradientType type; 21 | EJVector2 p1, p2; 22 | float r1, r2; 23 | 24 | NSMutableArray *colorStops; 25 | EJTexture *texture; 26 | } 27 | 28 | - (id)initLinearGradientWithP1:(EJVector2)p1 p2:(EJVector2)p2; 29 | - (id)initRadialGradientWithP1:(EJVector2)p1 r1:(float)r1 p2:(EJVector2)p2 r2:(float)r2; 30 | 31 | - (void)addStopWithColor:(EJColorRGBA)color at:(float)pos; 32 | - (void)rebuild; 33 | - (NSData *)getPixelsWithWidth:(int)width forSortedStops:(NSArray *)stops; 34 | 35 | @property (readonly, nonatomic) EJCanvasGradientType type; 36 | @property (readonly, nonatomic) EJTexture *texture; 37 | @property (readonly, nonatomic) EJVector2 p1; 38 | @property (readonly, nonatomic) EJVector2 p2; 39 | @property (readonly, nonatomic) float r1; 40 | @property (readonly, nonatomic) float r2; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasPattern.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJTexture.h" 3 | #import "EJCanvasContext2D.h" 4 | 5 | typedef enum { 6 | kEJCanvasPatternNoRepeat = 0, 7 | kEJCanvasPatternRepeatX = 1, 8 | kEJCanvasPatternRepeatY = 2, 9 | kEJCanvasPatternRepeat = 1 | 2 10 | } EJCanvasPatternRepeat; 11 | 12 | @interface EJCanvasPattern : NSObject { 13 | EJTexture *texture; 14 | EJCanvasPatternRepeat repeat; 15 | } 16 | 17 | - (id)initWithTexture:(EJTexture *)texturep repeat:(EJCanvasPatternRepeat)repeatp; 18 | 19 | @property (readonly, nonatomic) EJTexture *texture; 20 | @property (readonly, nonatomic) EJCanvasPatternRepeat repeat; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasPattern.m: -------------------------------------------------------------------------------- 1 | #import "EJCanvasPattern.h" 2 | 3 | @implementation EJCanvasPattern 4 | 5 | @synthesize texture; 6 | @synthesize repeat; 7 | 8 | - (id)initWithTexture:(EJTexture *)texturep repeat:(EJCanvasPatternRepeat)repeatp { 9 | if( self = [super init] ) { 10 | texture = texturep.copy; 11 | repeat = repeatp; 12 | } 13 | return self; 14 | } 15 | 16 | - (void)dealloc { 17 | [texture release]; 18 | [super dealloc]; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJCanvasShaders.h: -------------------------------------------------------------------------------- 1 | #define EJ_SHADER_SOURCE(NAME, ...) const char * const NAME = #__VA_ARGS__; 2 | 3 | EJ_SHADER_SOURCE(EJShaderVertex, 4 | attribute vec2 pos; 5 | attribute vec2 uv; 6 | attribute vec4 color; 7 | 8 | varying lowp vec4 vColor; 9 | varying highp vec2 vUv; 10 | 11 | uniform highp vec2 screen; 12 | 13 | void main() { 14 | vColor = color; 15 | vUv = uv; 16 | 17 | gl_Position = vec4(pos * (vec2(2,2)/screen) - clamp(screen,-1.0,1.0), 0.0, 1.0); 18 | } 19 | ); 20 | 21 | EJ_SHADER_SOURCE(EJShaderAlphaTexture, 22 | varying lowp vec4 vColor; 23 | varying highp vec2 vUv; 24 | 25 | uniform sampler2D texture; 26 | 27 | void main() { 28 | gl_FragColor = texture2D(texture, vUv).aaaa * vColor; 29 | } 30 | ); 31 | 32 | EJ_SHADER_SOURCE(EJShaderFlat, 33 | varying lowp vec4 vColor; 34 | varying highp vec2 vUv; 35 | 36 | void main() { 37 | gl_FragColor = vColor; 38 | } 39 | ); 40 | 41 | EJ_SHADER_SOURCE(EJShaderPattern, 42 | varying lowp vec4 vColor; 43 | varying highp vec2 vUv; 44 | 45 | uniform sampler2D texture; 46 | 47 | void main() { 48 | gl_FragColor = texture2D(texture, mod(vUv, vec2(1.0, 1.0)) ) * vColor; 49 | } 50 | ); 51 | 52 | EJ_SHADER_SOURCE(EJShaderTexture, 53 | varying lowp vec4 vColor; 54 | varying highp vec2 vUv; 55 | 56 | uniform sampler2D texture; 57 | 58 | void main() { 59 | gl_FragColor = texture2D(texture, vUv) * vColor; 60 | } 61 | ); 62 | 63 | EJ_SHADER_SOURCE(EJShaderRadialGradient, 64 | precision highp float; 65 | 66 | varying highp vec2 vUv; 67 | varying lowp vec4 vColor; 68 | 69 | uniform mediump vec3 inner; // x, y, z=radius 70 | uniform mediump vec3 diff; // x, y, z=radius 71 | 72 | uniform sampler2D texture; 73 | 74 | void main() { 75 | vec2 p2 = vUv - inner.xy; 76 | 77 | float A = dot(diff.xy, diff.xy) - diff.z * diff.z; 78 | float B = dot(p2.xy, diff.xy) + inner.z * diff.z; 79 | float C = dot(p2, p2) - (inner.z * inner.z); 80 | float D = (B * B) - (A * C); 81 | 82 | float DA = sqrt(D) / A; 83 | float BA = B / A; 84 | 85 | float t = max(BA+DA, BA-DA); 86 | 87 | lowp float keep = sign(diff.z * t + inner.z); // discard if < 0.0 88 | gl_FragColor = texture2D(texture, vec2(t, 0.0)) * vColor * keep; 89 | } 90 | ); 91 | 92 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJConvertColorRGBA.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "EJCanvas2DTypes.h" 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | EJColorRGBA JSValueToColorRGBA( JSContextRef ctx, JSValueRef value ); 10 | JSValueRef ColorRGBAToJSValue( JSContextRef ctx, EJColorRGBA c ); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJFont.h: -------------------------------------------------------------------------------- 1 | #import "EJTexture.h" 2 | #import 3 | #import 4 | 5 | 6 | #define EJ_FONT_TEXTURE_SIZE 1024 7 | #define EJ_FONT_GLYPH_PADDING 2 8 | 9 | 10 | typedef struct { 11 | float width; 12 | float ascent; 13 | float descent; 14 | } EJTextMetrics; 15 | 16 | typedef struct { 17 | float x, y, w, h; 18 | unsigned short textureIndex; 19 | float tx, ty, tw, th; 20 | } EJFontGlyphInfo; 21 | 22 | typedef struct { 23 | unsigned short textureIndex; 24 | CGGlyph glyph; 25 | float xpos; 26 | EJFontGlyphInfo *info; 27 | } EJFontGlyphLayout; 28 | 29 | 30 | 31 | @interface EJFontDescriptor : NSObject { 32 | NSString *name; 33 | float size; 34 | NSUInteger hash; 35 | } 36 | + (id)descriptorWithName:(NSString *)name size:(float)size; 37 | 38 | @property (readonly, nonatomic) NSString *name; 39 | @property (readonly, nonatomic) float size; 40 | 41 | @end 42 | 43 | 44 | 45 | @interface EJFontLayout : NSObject { 46 | NSData *glyphLayout; 47 | EJTextMetrics metrics; 48 | NSInteger glyphCount; 49 | } 50 | 51 | - (id)initWithGlyphLayout:(NSData *)layoutp glyphCount:(NSInteger)count metrics:(EJTextMetrics)metrics; 52 | @property (readonly, nonatomic) EJFontGlyphLayout *layout; 53 | @property (readonly, nonatomic) NSInteger glyphCount; 54 | @property (readonly, nonatomic) EJTextMetrics metrics; 55 | 56 | @end 57 | 58 | 59 | 60 | int EJFontGlyphLayoutSortByTextureIndex(const void *a, const void *b); 61 | 62 | @class EJCanvasContext2D; 63 | @interface EJFont : NSObject { 64 | NSMutableArray *textures; 65 | float txLineX, txLineY, txLineH; 66 | BOOL useSingleGlyphTextures; 67 | 68 | // Font preferences 69 | float pointSize, ascent, descent, leading, contentScale, glyphPadding, xHeight; 70 | BOOL fill; 71 | float lineWidth; 72 | 73 | // Font references 74 | CTFontRef ctMainFont; 75 | 76 | // Core text variables for line layout 77 | CGGlyph *glyphsBuffer; 78 | CGPoint *positionsBuffer; 79 | 80 | NSCache *layoutCache; 81 | } 82 | 83 | - (id)initWithDescriptor:(EJFontDescriptor *)desc fill:(BOOL)fillp lineWidth:(float)lineWidthp contentScale:(float)contentScalep; 84 | + (void)loadFontAtPath:(NSString *)path; 85 | - (void)drawString:(NSString *)string toContext:(EJCanvasContext2D *)context x:(float)x y:(float)y; 86 | - (EJTextMetrics)measureString:(NSString *)string forContext:(EJCanvasContext2D *)context; 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJFontCache.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJFont.h" 3 | 4 | #define EJ_FONT_CACHE_MAX_CONTENT_SCALE 32 5 | 6 | 7 | // EJFontCache is a singleton and can be shared between 2D contexts 8 | 9 | @interface EJFontCache : NSObject { 10 | NSMutableDictionary *fonts; 11 | } 12 | 13 | + (EJFontCache *)instance; 14 | 15 | - (void)clear; 16 | - (EJFont *)fontWithDescriptor:(EJFontDescriptor *)desc contentScale:(float)contentScale; 17 | - (EJFont *)outlineFontWithDescriptor:(EJFontDescriptor *)desc lineWidth:(float)lineWidth contentScale:(float)contentScale; 18 | 19 | 20 | @end -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJFontCache.m: -------------------------------------------------------------------------------- 1 | #import "EJFontCache.h" 2 | 3 | // An instance of EJFontCacheKey fully describes an internal Font in Ejecta: 4 | // - descriptor (name and size) 5 | // - solid or outlined 6 | // - line width 7 | // - content scale 8 | 9 | @interface EJFontCacheKey : NSObject { 10 | EJFontDescriptor *descriptor; 11 | float lineWidth; 12 | int normalizedContentScale; 13 | NSUInteger hash; 14 | } 15 | 16 | + keyWithDescriptor:(EJFontDescriptor *)descriptor lineWidth:(float)lineWidth contentScale:(float)contentScale; 17 | 18 | @property (readonly) int normalizedContentScale; 19 | 20 | @end 21 | 22 | static float kEJFontCacheKeyLineWidthNoneFilled = -1; 23 | 24 | @implementation EJFontCacheKey 25 | @synthesize normalizedContentScale; 26 | 27 | + (id)keyWithDescriptor:(EJFontDescriptor *)descriptor lineWidth:(float)lineWidth contentScale:(float)contentScale { 28 | 29 | // Find the next power of two for the normalized content scale 30 | int scale = 1; 31 | while(scale < contentScale && scale < EJ_FONT_CACHE_MAX_CONTENT_SCALE) { 32 | scale *= 2; 33 | } 34 | 35 | EJFontCacheKey *key = [[EJFontCacheKey alloc] init]; 36 | key->descriptor = [descriptor retain]; 37 | key->normalizedContentScale = scale; 38 | key->lineWidth = lineWidth; 39 | key->hash = [descriptor hash] + (scale * 673) + (int)(lineWidth * 487); 40 | 41 | return [key autorelease]; 42 | } 43 | 44 | - (void)dealloc { 45 | [descriptor release]; 46 | [super dealloc]; 47 | } 48 | 49 | - (NSUInteger)hash { 50 | return hash; 51 | } 52 | 53 | - (BOOL)isEqual:(id)anObject { 54 | if( ![anObject isKindOfClass:[EJFontCacheKey class]] ) { 55 | return NO; 56 | } 57 | 58 | EJFontCacheKey *otherKey = (EJFontCacheKey *)anObject; 59 | return ( 60 | otherKey->normalizedContentScale == normalizedContentScale && 61 | otherKey->lineWidth == lineWidth && 62 | [otherKey->descriptor isEqual:descriptor] 63 | ); 64 | } 65 | 66 | - (id)copyWithZone:(NSZone *)zone { 67 | EJFontCacheKey *keyCopy = [[EJFontCacheKey allocWithZone:zone] init]; 68 | keyCopy->descriptor = [descriptor retain]; 69 | keyCopy->normalizedContentScale = normalizedContentScale; 70 | keyCopy->lineWidth = lineWidth; 71 | keyCopy->hash = hash; 72 | return keyCopy; 73 | } 74 | 75 | @end 76 | 77 | 78 | 79 | 80 | 81 | @implementation EJFontCache 82 | 83 | static EJFontCache *fontCache; 84 | 85 | + (EJFontCache *)instance { 86 | if( !fontCache ) { 87 | fontCache = [[[EJFontCache alloc] init] autorelease]; 88 | } 89 | return fontCache; 90 | } 91 | 92 | - (id)init { 93 | if( self = [super init] ) { 94 | fonts = [NSMutableDictionary new]; 95 | [[NSNotificationCenter defaultCenter] addObserver:self 96 | selector:@selector(didReceiveMemoryWarning) 97 | name:UIApplicationDidReceiveMemoryWarningNotification 98 | object:nil]; 99 | } 100 | return self; 101 | } 102 | 103 | - (void)dealloc { 104 | fontCache = nil; 105 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 106 | [fonts release]; 107 | [super dealloc]; 108 | } 109 | 110 | - (void)didReceiveMemoryWarning { 111 | [self clear]; 112 | } 113 | 114 | - (void)clear { 115 | [fonts removeAllObjects]; 116 | } 117 | 118 | - (EJFont *)fontWithDescriptor:(EJFontDescriptor *)desc contentScale:(float)contentScale { 119 | EJFontCacheKey *key = [EJFontCacheKey keyWithDescriptor:desc 120 | lineWidth:kEJFontCacheKeyLineWidthNoneFilled contentScale:contentScale]; 121 | 122 | EJFont *font = fonts[key]; 123 | if( !font ) { 124 | font = [[EJFont alloc] initWithDescriptor:desc fill:YES lineWidth:0 contentScale:key.normalizedContentScale]; 125 | fonts[key] = font; 126 | [font autorelease]; 127 | } 128 | return font; 129 | } 130 | 131 | - (EJFont *)outlineFontWithDescriptor:(EJFontDescriptor *)desc lineWidth:(float)lineWidth contentScale:(float)contentScale { 132 | EJFontCacheKey *key = [EJFontCacheKey keyWithDescriptor:desc 133 | lineWidth:lineWidth contentScale:contentScale]; 134 | 135 | EJFont *font = fonts[key]; 136 | if( !font ) { 137 | font = [[EJFont alloc] initWithDescriptor:desc fill:NO lineWidth:lineWidth contentScale:key.normalizedContentScale]; 138 | fonts[key] = font; 139 | [font autorelease]; 140 | } 141 | return font; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJGLProgram2D.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "EJCanvas2DTypes.h" 6 | 7 | enum { 8 | kEJGLProgram2DAttributePos, 9 | kEJGLProgram2DAttributeUV, 10 | kEJGLProgram2DAttributeColor, 11 | }; 12 | 13 | @interface EJGLProgram2D : NSObject { 14 | GLuint program; 15 | GLuint screen; 16 | } 17 | 18 | - (id)initWithVertexShader:(const char *)vertexShaderSource fragmentShader:(const char *)fragmentShaderSource; 19 | - (void)bindAttributeLocations; 20 | - (void)getUniforms; 21 | 22 | + (GLint)compileShaderSource:(const char *)source type:(GLenum)type; 23 | + (void)linkProgram:(GLuint)program; 24 | 25 | @property (nonatomic, readonly) GLuint program; 26 | @property (nonatomic, readonly) GLuint screen; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJGLProgram2D.m: -------------------------------------------------------------------------------- 1 | #import "EJGLProgram2D.h" 2 | 3 | @implementation EJGLProgram2D 4 | 5 | @synthesize program; 6 | @synthesize screen; 7 | 8 | - (id)initWithVertexShader:(const char *)vertexShaderSource fragmentShader:(const char *)fragmentShaderSource { 9 | if( self = [super init] ) { 10 | program = glCreateProgram(); 11 | GLuint vertexShader = [EJGLProgram2D compileShaderSource:vertexShaderSource type:GL_VERTEX_SHADER]; 12 | GLuint fragmentShader = [EJGLProgram2D compileShaderSource:fragmentShaderSource type:GL_FRAGMENT_SHADER]; 13 | 14 | glAttachShader(program, vertexShader); 15 | glAttachShader(program, fragmentShader); 16 | 17 | [self bindAttributeLocations]; 18 | 19 | [EJGLProgram2D linkProgram:program]; 20 | 21 | [self getUniforms]; 22 | 23 | glDetachShader(program, vertexShader); 24 | glDeleteShader(vertexShader); 25 | 26 | glDetachShader(program, fragmentShader); 27 | glDeleteShader(fragmentShader); 28 | } 29 | return self; 30 | } 31 | 32 | - (void)dealloc { 33 | if( program ) { glDeleteProgram(program); } 34 | [super dealloc]; 35 | } 36 | 37 | - (void)bindAttributeLocations { 38 | glBindAttribLocation(program, kEJGLProgram2DAttributePos, "pos"); 39 | glBindAttribLocation(program, kEJGLProgram2DAttributeUV, "uv"); 40 | glBindAttribLocation(program, kEJGLProgram2DAttributeColor, "color"); 41 | } 42 | 43 | - (void)getUniforms { 44 | screen = glGetUniformLocation(program, "screen"); 45 | } 46 | 47 | + (GLint)compileShaderSource:(const char *)source type:(GLenum)type { 48 | GLint shader = glCreateShader(type); 49 | glShaderSource(shader, 1, &source, NULL); 50 | glCompileShader(shader); 51 | 52 | GLint status; 53 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 54 | if( status == 0 ) { 55 | GLint logLength; 56 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); 57 | if( logLength > 0 ) { 58 | GLchar *log = (GLchar *)malloc(logLength); 59 | glGetShaderInfoLog(shader, logLength, &logLength, log); 60 | NSLog(@"Shader compile log:\n%s", log); 61 | free(log); 62 | } 63 | glDeleteShader(shader); 64 | return 0; 65 | } 66 | 67 | return shader; 68 | } 69 | 70 | + (void)linkProgram:(GLuint)program { 71 | GLint status; 72 | glLinkProgram(program); 73 | 74 | glGetProgramiv(program, GL_LINK_STATUS, &status); 75 | if( status == 0 ) { 76 | GLint logLength; 77 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); 78 | if( logLength > 0 ) { 79 | GLchar *log = (GLchar *)malloc(logLength); 80 | glGetProgramInfoLog(program, logLength, &logLength, log); 81 | NSLog(@"Program link log:\n%s", log); 82 | free(log); 83 | } 84 | } 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJGLProgram2DRadialGradient.h: -------------------------------------------------------------------------------- 1 | #import "EJGLProgram2D.h" 2 | 3 | @interface EJGLProgram2DRadialGradient : EJGLProgram2D { 4 | GLuint inner, diff; 5 | } 6 | 7 | @property (nonatomic, readonly) GLuint inner; 8 | @property (nonatomic, readonly) GLuint diff; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJGLProgram2DRadialGradient.m: -------------------------------------------------------------------------------- 1 | #import "EJGLProgram2DRadialGradient.h" 2 | 3 | @implementation EJGLProgram2DRadialGradient 4 | @synthesize inner, diff; 5 | 6 | - (void)getUniforms { 7 | [super getUniforms]; 8 | 9 | inner = glGetUniformLocation(program, "inner"); 10 | diff = glGetUniformLocation(program, "diff"); 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJImageData.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJTexture.h" 3 | 4 | @interface EJImageData : NSObject { 5 | int width, height; 6 | NSMutableData *pixels; 7 | } 8 | 9 | - (id)initWithWidth:(int)width height:(int)height pixels:(NSMutableData *)pixels; 10 | 11 | @property (readonly, nonatomic) EJTexture *texture; 12 | @property (readonly, nonatomic) int width; 13 | @property (readonly, nonatomic) int height; 14 | @property (readonly, nonatomic) NSMutableData *pixels; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJImageData.m: -------------------------------------------------------------------------------- 1 | #import "EJImageData.h" 2 | 3 | @implementation EJImageData 4 | 5 | @synthesize width, height, pixels; 6 | 7 | - (id)initWithWidth:(int)widthp height:(int)heightp pixels:(NSMutableData *)pixelsp { 8 | if( self = [super init] ) { 9 | width = widthp; 10 | height = heightp; 11 | pixels = [pixelsp retain]; 12 | } 13 | return self; 14 | } 15 | 16 | - (void)dealloc { 17 | [pixels release]; 18 | [super dealloc]; 19 | } 20 | 21 | - (EJTexture *)texture { 22 | return [[[EJTexture alloc] initWithWidth:width height:height pixels:pixels] autorelease]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/2D/EJPath.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJCanvas2DTypes.h" 3 | 4 | #define EJ_PATH_RECURSION_LIMIT 8 5 | #define EJ_PATH_DISTANCE_EPSILON 1.0f 6 | #define EJ_PATH_COLLINEARITY_EPSILON FLT_EPSILON 7 | #define EJ_PATH_MIN_STEPS_FOR_CIRCLE 20.0f 8 | #define EJ_PATH_MAX_STEPS_FOR_CIRCLE 64.0f 9 | 10 | typedef enum { 11 | kEJPathPolygonTargetColor, 12 | kEJPathPolygonTargetDepth 13 | } EJPathPolygonTarget; 14 | 15 | typedef enum { 16 | kEJPathFillRuleNonZero, 17 | kEJPathFillRuleEvenOdd 18 | } EJPathFillRule; 19 | 20 | @class EJCanvasContext2D; 21 | 22 | @interface EJPath : NSObject { 23 | EJVector2 currentPos, lastPushed; 24 | EJVector2 minPos, maxPos; 25 | EJPathFillRule fillRule; 26 | unsigned int longestSubpath; 27 | 28 | float distanceTolerance; 29 | 30 | CGAffineTransform transform; 31 | } 32 | 33 | @property (nonatomic,assign) CGAffineTransform transform; 34 | @property (readonly) EJPathFillRule fillRule; 35 | 36 | - (void)push:(EJVector2)v; 37 | - (void)reset; 38 | - (void)close; 39 | - (void)endSubPath; 40 | - (void)moveToX:(float)x y:(float)y; 41 | - (void)lineToX:(float)x y:(float)y; 42 | - (void)bezierCurveToCpx1:(float)cpx1 cpy1:(float)cpy1 cpx2:(float)cpx2 cpy2:(float)cpy2 x:(float)x y:(float)y scale:(float)scale; 43 | - (void)recursiveBezierX1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 x4:(float)x4 y4:(float)y4 level:(int)level; 44 | - (void)quadraticCurveToCpx:(float)cpx cpy:(float)cpy x:(float)x y:(float)y scale:(float)scale; 45 | - (void)recursiveQuadraticX1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 level:(int)level; 46 | - (void)arcToX1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 radius:(float)radius; 47 | - (void)arcX:(float)x y:(float)y radius:(float)radius startAngle:(float)startAngle endAngle:(float)endAngle antiClockwise:(BOOL)antiClockwise; 48 | 49 | - (void)drawPolygonsToContext:(EJCanvasContext2D *)context fillRule:(EJPathFillRule)fillRule target:(EJPathPolygonTarget)target; 50 | - (void)drawLinesToContext:(EJCanvasContext2D *)context; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EAGLView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | 6 | #import 7 | 8 | @interface EAGLView : UIView 9 | 10 | - (id)initWithFrame:(CGRect)frame contentScale:(float)contentScale retainedBacking:(BOOL)retainedBacking; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EAGLView.m: -------------------------------------------------------------------------------- 1 | #import "EAGLView.h" 2 | 3 | @implementation EAGLView 4 | 5 | + (Class)layerClass { 6 | return [CAEAGLLayer class]; 7 | } 8 | 9 | - (id)initWithFrame:(CGRect)frame contentScale:(float)contentScale retainedBacking:(BOOL)retainedBacking { 10 | if( self = [super initWithFrame:frame] ) { 11 | #if !TARGET_OS_TV 12 | [self setMultipleTouchEnabled:YES]; 13 | #endif 14 | 15 | CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; 16 | 17 | self.contentScaleFactor = contentScale; 18 | eaglLayer.contentsScale = contentScale; 19 | 20 | eaglLayer.opaque = TRUE; 21 | 22 | eaglLayer.drawableProperties = @{ 23 | kEAGLDrawablePropertyRetainedBacking: @(retainedBacking), 24 | kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8 25 | }; 26 | } 27 | return self; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJBindingCanvas.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJTexture.h" 3 | #import "EJDrawable.h" 4 | #import "EJCanvasContext.h" 5 | #import "EJBindingCanvasStyle.h" 6 | 7 | #define EJ_CANVAS_DEFAULT_JPEG_QUALITY 0.9 8 | #define EJ_CANVAS_DATA_URL_PREFIX_JPEG @"data:image/jpeg;base64," 9 | #define EJ_CANVAS_DATA_URL_PREFIX_PNG @"data:image/png;base64," 10 | 11 | @class EJJavaScriptView; 12 | 13 | typedef enum { 14 | kEJCanvasContextModeInvalid, 15 | kEJCanvasContextMode2D, 16 | kEJCanvasContextModeWebGL 17 | } EJCanvasContextMode; 18 | 19 | @interface EJBindingCanvas : EJBindingBase { 20 | JSObjectRef jsCanvasContext; 21 | EJCanvasContext *renderingContext; 22 | EJCanvasContextMode contextMode; 23 | short width, height; 24 | 25 | EJBindingCanvasStyle *styleObject; 26 | CGRect style; 27 | 28 | BOOL isScreenCanvas; 29 | } 30 | 31 | @property (nonatomic) float styleLeft; 32 | @property (nonatomic) float styleTop; 33 | @property (nonatomic) float styleWidth; 34 | @property (nonatomic) float styleHeight; 35 | @property (readonly, nonatomic) EJTexture *texture; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJBindingCanvasStyle.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | 3 | @class EJBindingCanvas; 4 | @interface EJBindingCanvasStyle : EJBindingBase { 5 | EJBindingCanvas *binding; 6 | } 7 | 8 | @property (assign, nonatomic) EJBindingCanvas *binding; 9 | @property (readonly, nonatomic) JSObjectRef jsObject; 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJBindingCanvasStyle.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingCanvasStyle.h" 2 | 3 | #import "EJBindingCanvas.h" 4 | 5 | @implementation EJBindingCanvasStyle 6 | @synthesize binding; 7 | 8 | - (JSObjectRef)jsObject { 9 | return jsObject; 10 | } 11 | 12 | #define EJ_BIND_PX_STYLE(NAME, TARGET) \ 13 | EJ_BIND_GET(NAME, ctx) { \ 14 | return NSStringToJSValue(ctx, [NSString stringWithFormat:@"%fpx", TARGET]);\ 15 | } \ 16 | \ 17 | EJ_BIND_SET(NAME, ctx, value) { \ 18 | if( JSValueIsNumber(ctx, value) ) { \ 19 | TARGET = JSValueToNumberFast(ctx, value); \ 20 | return; \ 21 | } \ 22 | NSString *valueString = JSValueToNSString(ctx, value); \ 23 | if( valueString.length > 0 ) { \ 24 | float NAME; \ 25 | sscanf( valueString.UTF8String, "%fpx", &NAME); \ 26 | TARGET = NAME; \ 27 | } \ 28 | else { \ 29 | TARGET = 0; \ 30 | } \ 31 | } 32 | 33 | EJ_BIND_PX_STYLE(width, binding.styleWidth); 34 | EJ_BIND_PX_STYLE(height, binding.styleHeight); 35 | EJ_BIND_PX_STYLE(left, binding.styleLeft); 36 | EJ_BIND_PX_STYLE(top, binding.styleTop); 37 | 38 | #undef EJ_BIND_PX_STYLE 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJBindingImage.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingEventedBase.h" 2 | #import "EJTexture.h" 3 | #import "EJDrawable.h" 4 | 5 | @interface EJBindingImage : EJBindingEventedBase { 6 | EJTexture *texture; 7 | NSString *path; 8 | BOOL loading; 9 | NSOperation *loadCallback; 10 | } 11 | 12 | @property (readonly, nonatomic) EJTexture *texture; 13 | 14 | - (void)setTexture:(EJTexture *)texturep path:(NSString *)pathp; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJBindingImage.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingImage.h" 2 | #import "EJJavaScriptView.h" 3 | #import "EJNonRetainingProxy.h" 4 | #import "EJTexture.h" 5 | 6 | @implementation EJBindingImage 7 | @synthesize texture; 8 | 9 | - (void)beginLoad { 10 | // This will begin loading the texture in a background thread and will call the 11 | // JavaScript onload callback when done 12 | loading = YES; 13 | 14 | // Protect this image object from garbage collection, as its callback function 15 | // may be the only thing holding on to it 16 | JSValueProtect(scriptView.jsGlobalContext, jsObject); 17 | 18 | NSString *fullPath; 19 | 20 | // If path is a Data URI or remote URL we don't want to prepend resource paths 21 | if( [path hasPrefix:@"data:"] ) { 22 | NSLog(@"Loading Image from Data URI"); 23 | fullPath = path; 24 | } 25 | else if( [path hasPrefix:@"http:"] || [path hasPrefix:@"https:"] ) { 26 | NSLog(@"Loading Image from URL: %@", path); 27 | fullPath = path; 28 | } 29 | else { 30 | NSLog(@"Loading Image (lazy): %@", path); 31 | fullPath = [scriptView pathForResource:path]; 32 | } 33 | 34 | // Use a non-retaining proxy for the callback operation and take care that the 35 | // loadCallback is always cancelled when dealloc'ing 36 | loadCallback = [[NSInvocationOperation alloc] 37 | initWithTarget:[EJNonRetainingProxy proxyWithTarget:self] 38 | selector:@selector(endLoad) object:nil]; 39 | 40 | texture = [[EJTexture cachedTextureWithPath:fullPath 41 | loadOnQueue:scriptView.backgroundQueue callback:loadCallback] retain]; 42 | } 43 | 44 | - (void)prepareGarbageCollection { 45 | [loadCallback cancel]; 46 | [loadCallback release]; 47 | loadCallback = nil; 48 | } 49 | 50 | - (void)dealloc { 51 | [loadCallback cancel]; 52 | [loadCallback release]; 53 | 54 | [texture release]; 55 | 56 | [path release]; 57 | [super dealloc]; 58 | } 59 | 60 | - (void)endLoad { 61 | loading = NO; 62 | [loadCallback release]; 63 | loadCallback = nil; 64 | 65 | if( texture.lazyLoaded || texture.textureId ) { 66 | [self triggerEvent:@"load"]; 67 | } 68 | else { 69 | [self triggerEvent:@"error"]; 70 | } 71 | 72 | JSValueUnprotect(scriptView.jsGlobalContext, jsObject); 73 | } 74 | 75 | - (void)setTexture:(EJTexture *)texturep path:(NSString *)pathp { 76 | texture = [texturep retain]; 77 | path = [pathp retain]; 78 | } 79 | 80 | EJ_BIND_GET(src, ctx ) { 81 | return NSStringToJSValue(ctx, path ? path : @""); 82 | } 83 | 84 | EJ_BIND_SET(src, ctx, value) { 85 | // If the texture is still loading, do nothing to avoid confusion 86 | // This will break some edge cases; FIXME 87 | if( loading ) { return; } 88 | 89 | NSString *newPath = JSValueToNSString( ctx, value ); 90 | 91 | // Same as the old path? Nothing to do here 92 | if( [path isEqualToString:newPath] ) { return; } 93 | 94 | 95 | // Release the old path and texture? 96 | if( path ) { 97 | [path release]; 98 | path = nil; 99 | } 100 | 101 | if( texture ) { 102 | [texture release]; 103 | texture = nil; 104 | } 105 | 106 | if( !JSValueIsNull(ctx, value) && newPath.length ) { 107 | path = [newPath retain]; 108 | [self beginLoad]; 109 | } 110 | } 111 | 112 | EJ_BIND_GET(width, ctx ) { 113 | return JSValueMakeNumber( ctx, texture.width ); 114 | } 115 | 116 | EJ_BIND_GET(height, ctx ) { 117 | return JSValueMakeNumber( ctx, texture.height ); 118 | } 119 | 120 | EJ_BIND_GET(complete, ctx ) { 121 | return JSValueMakeBoolean(ctx, (texture && (texture.lazyLoaded || texture.textureId)) ); 122 | } 123 | 124 | EJ_BIND_EVENT(load); 125 | EJ_BIND_EVENT(error); 126 | 127 | EJ_BIND_CONST(nodeName, "IMG"); 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJCanvasContext.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class EAGLContext; 4 | @interface EJCanvasContext : NSObject { 5 | short width, height; 6 | 7 | BOOL preserveDrawingBuffer; 8 | BOOL msaaEnabled; 9 | BOOL needsPresenting; 10 | int msaaSamples; 11 | EAGLContext *glContext; 12 | } 13 | 14 | - (void)create; 15 | - (void)flushBuffers; 16 | - (void)prepare; 17 | 18 | @property (nonatomic) BOOL preserveDrawingBuffer; 19 | @property (nonatomic) BOOL msaaEnabled; 20 | @property (nonatomic) int msaaSamples; 21 | @property (nonatomic) short width; 22 | @property (nonatomic) short height; 23 | @property (nonatomic, readonly) EAGLContext *glContext; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJCanvasContext.m: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContext.h" 2 | 3 | @implementation EJCanvasContext 4 | 5 | @synthesize glContext; 6 | @synthesize width, height; 7 | @synthesize msaaEnabled, msaaSamples; 8 | @synthesize preserveDrawingBuffer; 9 | 10 | - (void)create {} 11 | - (void)flushBuffers {} 12 | - (void)prepare {} 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJDrawable.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJTexture.h" 3 | 4 | @protocol EJDrawable 5 | 6 | @property (readonly, nonatomic) EJTexture *texture; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJPresentable.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol EJPresentable 4 | 5 | - (void)present; 6 | - (void)finish; 7 | 8 | @property (nonatomic) CGRect style; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJSharedTextureCache.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface EJSharedTextureCache : NSObject { 4 | NSMutableDictionary *textures; 5 | NSMutableData *premultiplyTable; 6 | NSMutableData *unPremultiplyTable; 7 | } 8 | 9 | + (EJSharedTextureCache *)instance; 10 | - (void)releaseStoragesOlderThan:(NSTimeInterval)seconds; 11 | 12 | @property (nonatomic, readonly) NSMutableDictionary *textures; 13 | @property (nonatomic, readonly) NSData *premultiplyTable; 14 | @property (nonatomic, readonly) NSData *unPremultiplyTable; 15 | 16 | @end -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJSharedTextureCache.m: -------------------------------------------------------------------------------- 1 | #import "EJSharedTextureCache.h" 2 | #import "EJTexture.h" 3 | 4 | @implementation EJSharedTextureCache 5 | @synthesize textures; 6 | 7 | static EJSharedTextureCache *sharedTextureCache; 8 | 9 | + (EJSharedTextureCache *)instance { 10 | if( !sharedTextureCache ) { 11 | sharedTextureCache = [[[EJSharedTextureCache alloc] init] autorelease]; 12 | } 13 | return sharedTextureCache; 14 | } 15 | 16 | - (id)init { 17 | if( self = [super init] ) { 18 | // Create a non-retaining Dictionary to hold the cached textures 19 | textures = (NSMutableDictionary *)CFDictionaryCreateMutable(NULL, 8, &kCFCopyStringDictionaryKeyCallBacks, NULL); 20 | } 21 | return self; 22 | } 23 | 24 | - (void)releaseStoragesOlderThan:(NSTimeInterval)seconds { 25 | NSTimeInterval now = NSProcessInfo.processInfo.systemUptime; 26 | for( NSString *key in textures ) { 27 | EJTexture *texture = [textures objectForKey:key]; 28 | if( now - texture.lastUsed > seconds ) { 29 | [texture maybeReleaseStorage]; 30 | } 31 | } 32 | } 33 | 34 | - (void)dealloc { 35 | sharedTextureCache = nil; 36 | [textures release]; 37 | [premultiplyTable release]; 38 | [unPremultiplyTable release]; 39 | [super dealloc]; 40 | } 41 | 42 | 43 | // Lookup tables for fast [un]premultiplied alpha color values 44 | // From https://bugzilla.mozilla.org/show_bug.cgi?id=662130 45 | 46 | - (NSData *)premultiplyTable { 47 | if( !premultiplyTable ) { 48 | premultiplyTable = [[NSMutableData alloc] initWithLength:256*256]; 49 | 50 | unsigned char *data = premultiplyTable.mutableBytes; 51 | for( int a = 0; a <= 255; a++ ) { 52 | for( int c = 0; c <= 255; c++ ) { 53 | data[a*256+c] = (a * c + 254) / 255; 54 | } 55 | } 56 | } 57 | 58 | return premultiplyTable; 59 | } 60 | 61 | - (NSData *)unPremultiplyTable { 62 | if( !unPremultiplyTable ) { 63 | unPremultiplyTable = [[NSMutableData alloc] initWithLength:256*256]; 64 | 65 | unsigned char *data = unPremultiplyTable.mutableBytes; 66 | // a == 0 case 67 | for( int c = 0; c <= 255; c++ ) { 68 | data[c] = c; 69 | } 70 | 71 | for( int a = 1; a <= 255; a++ ) { 72 | for( int c = 0; c <= 255; c++ ) { 73 | data[a*256+c] = (c * 255) / a; 74 | } 75 | } 76 | } 77 | 78 | return unPremultiplyTable; 79 | } 80 | 81 | 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJTexture.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #import "EJTextureStorage.h" 7 | 8 | @interface EJTexture : NSObject { 9 | BOOL cached; 10 | BOOL drawFlippedY; 11 | BOOL isCompressed; 12 | BOOL lazyLoaded; 13 | BOOL dimensionsKnown; 14 | short width, height; 15 | NSString *fullPath; 16 | EJTextureStorage *textureStorage; 17 | GLenum format; 18 | GLuint fbo; 19 | 20 | EJTextureParams params; 21 | NSBlockOperation *loadCallback; 22 | } 23 | - (id)initEmptyForWebGL; 24 | - (id)initWithPath:(NSString *)path; 25 | + (id)cachedTextureWithPath:(NSString *)path loadOnQueue:(NSOperationQueue *)queue callback:(NSOperation *)callback; 26 | - (id)initWithPath:(NSString *)path loadOnQueue:(NSOperationQueue *)queue callback:(NSOperation *)callback; 27 | 28 | - (id)initWithWidth:(int)widthp height:(int)heightp; 29 | - (id)initWithWidth:(int)widthp height:(int)heightp format:(GLenum) format; 30 | - (id)initWithWidth:(int)widthp height:(int)heightp pixels:(NSData *)pixels; 31 | - (id)initAsRenderTargetWithWidth:(int)widthp height:(int)heightp fbo:(GLuint)fbo; 32 | - (id)initWithUIImage:(UIImage *)image; 33 | 34 | - (void)maybeReleaseStorage; 35 | 36 | - (void)ensureMutableKeepPixels:(BOOL)keepPixels forTarget:(GLenum)target; 37 | 38 | - (void)createWithTexture:(EJTexture *)other; 39 | - (void)createWithPixels:(NSData *)pixels format:(GLenum)format; 40 | - (void)createWithPixels:(NSData *)pixels format:(GLenum)formatp target:(GLenum)target; 41 | - (void)uploadCompressedPixels:(NSData *)pixels target:(GLenum)target; 42 | - (void)updateWithPixels:(NSData *)pixels atX:(int)x y:(int)y width:(int)subWidth height:(int)subHeight; 43 | 44 | - (NSMutableData *)loadPixelsFromPath:(NSString *)path; 45 | - (NSMutableData *)loadPixelsFromUIImage:(UIImage *)image; 46 | 47 | - (GLint)getParam:(GLenum)pname; 48 | - (void)setParam:(GLenum)pname param:(GLenum)param; 49 | 50 | - (void)bindWithFilter:(GLenum)filter; 51 | - (void)bindToTarget:(GLenum)target; 52 | 53 | - (UIImage *)image; 54 | + (UIImage *)imageWithPixels:(NSData *)pixels width:(int)width height:(int)height; 55 | 56 | + (void)premultiplyPixels:(const GLubyte *)inPixels to:(GLubyte *)outPixels byteLength:(int)byteLength format:(GLenum)format; 57 | + (void)unPremultiplyPixels:(const GLubyte *)inPixels to:(GLubyte *)outPixels byteLength:(int)byteLength format:(GLenum)format; 58 | + (void)flipPixelsY:(GLubyte *)pixels bytesPerRow:(int)bytesPerRow rows:(int)rows; 59 | 60 | @property (readwrite, nonatomic) BOOL drawFlippedY; 61 | @property (readonly, nonatomic) BOOL isDynamic; 62 | @property (readonly, nonatomic) BOOL lazyLoaded; 63 | @property (readonly, nonatomic) NSMutableData *pixels; 64 | @property (readonly, nonatomic) GLuint textureId; 65 | @property (readonly, nonatomic) GLenum format; 66 | @property (readonly, nonatomic) short width, height; 67 | @property (readonly, nonatomic) NSTimeInterval lastUsed; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJTextureStorage.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | typedef enum { 7 | kEJTextureParamMinFilter, 8 | kEJTextureParamMagFilter, 9 | kEJTextureParamWrapS, 10 | kEJTextureParamWrapT, 11 | kEJTextureParamLast 12 | } EJTextureParam; 13 | 14 | typedef EJTextureParam EJTextureParams[kEJTextureParamLast]; 15 | 16 | 17 | @interface EJTextureStorage : NSObject { 18 | EJTextureParams params; 19 | GLuint textureId; 20 | BOOL immutable; 21 | NSTimeInterval lastBound; 22 | } 23 | - (id)init; 24 | - (id)initImmutable; 25 | - (void)bindToTarget:(GLenum)target withParams:(EJTextureParam *)newParams; 26 | 27 | @property (readonly, nonatomic) GLuint textureId; 28 | @property (readonly, nonatomic) BOOL immutable; 29 | @property (readonly, nonatomic) NSTimeInterval lastBound; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/EJTextureStorage.m: -------------------------------------------------------------------------------- 1 | #import "EJTextureStorage.h" 2 | 3 | @implementation EJTextureStorage 4 | @synthesize lastBound; 5 | @synthesize textureId; 6 | @synthesize immutable; 7 | 8 | - (id)init { 9 | if( self = [super init] ) { 10 | glGenTextures(1, &textureId); 11 | immutable = NO; 12 | } 13 | return self; 14 | } 15 | 16 | - (id)initImmutable { 17 | if( self = [super init] ) { 18 | glGenTextures(1, &textureId); 19 | immutable = YES; 20 | } 21 | return self; 22 | } 23 | 24 | - (void)dealloc { 25 | if( textureId ) { 26 | glDeleteTextures(1, &textureId); 27 | } 28 | [super dealloc]; 29 | } 30 | 31 | - (void)bindToTarget:(GLenum)target withParams:(EJTextureParam *)newParams { 32 | glBindTexture(target, textureId); 33 | 34 | // Check if we have to set a param 35 | if(params[kEJTextureParamMinFilter] != newParams[kEJTextureParamMinFilter]) { 36 | params[kEJTextureParamMinFilter] = newParams[kEJTextureParamMinFilter]; 37 | glTexParameteri(target, GL_TEXTURE_MIN_FILTER, params[kEJTextureParamMinFilter]); 38 | } 39 | if(params[kEJTextureParamMagFilter] != newParams[kEJTextureParamMagFilter]) { 40 | params[kEJTextureParamMagFilter] = newParams[kEJTextureParamMagFilter]; 41 | glTexParameteri(target, GL_TEXTURE_MAG_FILTER, params[kEJTextureParamMagFilter]); 42 | } 43 | if(params[kEJTextureParamWrapS] != newParams[kEJTextureParamWrapS]) { 44 | params[kEJTextureParamWrapS] = newParams[kEJTextureParamWrapS]; 45 | glTexParameteri(target, GL_TEXTURE_WRAP_S, params[kEJTextureParamWrapS]); 46 | } 47 | if(params[kEJTextureParamWrapT] != newParams[kEJTextureParamWrapT]) { 48 | params[kEJTextureParamWrapT] = newParams[kEJTextureParamWrapT]; 49 | glTexParameteri(target, GL_TEXTURE_WRAP_T, params[kEJTextureParamWrapT]); 50 | } 51 | 52 | lastBound = NSProcessInfo.processInfo.systemUptime; 53 | } 54 | 55 | @end 56 | 57 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJBindingCanvasContextWebGL.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingBase.h" 3 | #import "EJCanvasContextWebGL.h" 4 | #import "EJTexture.h" 5 | 6 | #define GL_UNPACK_FLIP_Y_WEBGL 0x9240 7 | #define GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241 8 | #define GL_CONTEXT_LOST_WEBGL 0x9242 9 | #define GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243 10 | #define GL_BROWSER_DEFAULT_WEBGL 0x9244 11 | 12 | #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A 13 | 14 | #define EJ_CANVAS_MAX_TEXTURE_UNITS 8 15 | #define EJ_BUFFER_OFFSET(i) ((char *)NULL + (i)) 16 | 17 | #define EJ_BIND_CONST_GL(NAME) EJ_BIND_CONST(NAME, GL_##NAME) 18 | 19 | typedef struct { 20 | EJTexture *texture; 21 | JSObjectRef jsTexture; 22 | EJTexture *cubeMap; 23 | JSObjectRef jsCubeMap; 24 | } EJCanvasContextTextureUnit; 25 | 26 | @class EJJavaScriptView; 27 | @interface EJBindingCanvasContextWebGL : EJBindingBase { 28 | 29 | BOOL unpackFlipY; 30 | BOOL premultiplyAlpha; 31 | 32 | JSObjectRef jsCanvas; 33 | EJCanvasContextWebGL *renderingContext; 34 | 35 | NSMutableDictionary *renderbuffers; 36 | NSMutableDictionary *framebuffers; 37 | NSMutableDictionary *buffers; 38 | NSMutableDictionary *textures; 39 | NSMutableDictionary *programs; 40 | NSMutableDictionary *shaders; 41 | 42 | NSMutableDictionary *extensions; 43 | 44 | NSMutableDictionary *vertexArrays; 45 | 46 | EJCanvasContextTextureUnit textureUnits[EJ_CANVAS_MAX_TEXTURE_UNITS]; 47 | EJCanvasContextTextureUnit *activeTexture; 48 | } 49 | 50 | - (id)initWithRenderingContext:(EJCanvasContextWebGL *)renderingContextp; 51 | 52 | - (void)deleteRenderbuffer:(GLuint)renderbuffer; 53 | - (void)deleteFramebuffer:(GLuint)framebuffer; 54 | - (void)deleteBuffer:(GLuint)buffer; 55 | - (void)deleteTexture:(GLuint)texture; 56 | - (void)deleteProgram:(GLuint)program; 57 | - (void)deleteShader:(GLuint)shader; 58 | 59 | - (void)addVertexArray:(GLuint)vertexArray obj:(JSObjectRef)objp; 60 | - (void)deleteVertexArray:(GLuint)vertexArray; 61 | 62 | @property (readonly, nonatomic) EJCanvasContextWebGL *renderingContext; 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJBindingWebGLExtensions.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingBase.h" 3 | #import "EJBindingWebGLObjects.h" 4 | 5 | typedef struct { 6 | const char *exposedName; 7 | const char *internalName; 8 | } EJWebGLExtensionName; 9 | 10 | extern const EJWebGLExtensionName EJWebGLExtensions[]; 11 | extern const int EJWebGLExtensionsCount; 12 | 13 | 14 | @interface EJBindingWebGLExtension : EJBindingBase { 15 | EJBindingCanvasContextWebGL *webglContext; 16 | } 17 | 18 | - (id)initWithWebGLContext:(EJBindingCanvasContextWebGL *)webglContext; 19 | 20 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 21 | scriptView:(EJJavaScriptView *)view 22 | webglContext:(EJBindingCanvasContextWebGL *)webglContext; 23 | 24 | @end 25 | 26 | 27 | @interface EJBindingWebGLExtensionEXT_texture_filter_anisotropic : EJBindingWebGLExtension 28 | @end; 29 | 30 | @interface EJBindingWebGLExtensionOES_texture_float : EJBindingWebGLExtension 31 | @end; 32 | 33 | @interface EJBindingWebGLExtensionOES_texture_half_float : EJBindingWebGLExtension 34 | @end; 35 | 36 | @interface EJBindingWebGLExtensionOES_texture_half_float_linear : EJBindingWebGLExtension 37 | @end; 38 | 39 | @interface EJBindingWebGLExtensionOES_standard_derivatives : EJBindingWebGLExtension 40 | @end; 41 | 42 | @interface EJBindingWebGLExtensionOES_vertex_array_object : EJBindingWebGLExtension 43 | @end; 44 | 45 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJBindingWebGLExtensions.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingWebGLExtensions.h" 2 | #import "EJBindingCanvasContextWebGL.h" 3 | 4 | 5 | const EJWebGLExtensionName EJWebGLExtensions[] = { 6 | {"EXT_texture_filter_anisotropic", "GL_EXT_texture_filter_anisotropic"}, 7 | {"OES_texture_float", "GL_OES_texture_float"}, 8 | {"OES_texture_half_float", "GL_OES_texture_half_float"}, 9 | {"OES_texture_half_float_linear", "GL_OES_texture_half_float_linear"}, 10 | {"OES_standard_derivatives", "GL_OES_standard_derivatives"}, 11 | {"OES_vertex_array_object", "GL_OES_vertex_array_object"} 12 | }; 13 | 14 | const int EJWebGLExtensionsCount = sizeof(EJWebGLExtensions) / sizeof(EJWebGLExtensionName); 15 | 16 | 17 | @implementation EJBindingWebGLExtension 18 | 19 | - (id)initWithWebGLContext:(EJBindingCanvasContextWebGL *)webglContextp { 20 | if( self = [super initWithContext:NULL argc:0 argv:NULL] ) { 21 | webglContext = [webglContextp retain]; 22 | } 23 | return self; 24 | } 25 | 26 | - (void)dealloc { 27 | [webglContext release]; 28 | [super dealloc]; 29 | } 30 | 31 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 32 | scriptView:(EJJavaScriptView *)view 33 | webglContext:(EJBindingCanvasContextWebGL *)webglContext 34 | { 35 | id native = [[self alloc] initWithWebGLContext:webglContext]; 36 | 37 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:native]; 38 | [native release]; 39 | return obj; 40 | } 41 | 42 | @end 43 | 44 | 45 | @implementation EJBindingWebGLExtensionEXT_texture_filter_anisotropic 46 | EJ_BIND_CONST_GL(MAX_TEXTURE_MAX_ANISOTROPY_EXT); 47 | EJ_BIND_CONST_GL(TEXTURE_MAX_ANISOTROPY_EXT); 48 | @end 49 | 50 | 51 | @implementation EJBindingWebGLExtensionOES_texture_float 52 | @end 53 | 54 | 55 | @implementation EJBindingWebGLExtensionOES_texture_half_float 56 | EJ_BIND_CONST_GL(HALF_FLOAT_OES); 57 | @end 58 | 59 | 60 | @implementation EJBindingWebGLExtensionOES_texture_half_float_linear 61 | @end 62 | 63 | 64 | @implementation EJBindingWebGLExtensionOES_standard_derivatives 65 | @end 66 | 67 | 68 | @implementation EJBindingWebGLExtensionOES_vertex_array_object 69 | 70 | EJ_BIND_FUNCTION(createVertexArrayOES, ctx, argc, argv) { 71 | GLuint vertexArray; 72 | scriptView.currentRenderingContext = webglContext.renderingContext; 73 | glGenVertexArraysOES(1, &vertexArray); 74 | JSObjectRef obj = [EJBindingWebGLVertexArrayObjectOES createJSObjectWithContext:ctx 75 | scriptView:scriptView webglContext:webglContext index:vertexArray]; 76 | [webglContext addVertexArray:vertexArray obj:obj]; 77 | return obj; 78 | } 79 | 80 | EJ_BIND_FUNCTION(deleteVertexArrayOES, ctx, argc, argv) { \ 81 | if( argc < 1 ) { return NULL; } 82 | 83 | GLuint index = [EJBindingWebGLVertexArrayObjectOES indexFromJSValue:argv[0]]; 84 | [webglContext deleteVertexArray:index]; 85 | return NULL; 86 | } 87 | 88 | EJ_BIND_FUNCTION(isVertexArrayOES, ctx, argc, argv) { 89 | if( argc < 1 ) { return NULL; } 90 | 91 | scriptView.currentRenderingContext = webglContext.renderingContext; 92 | GLuint index = [EJBindingWebGLVertexArrayObjectOES indexFromJSValue:argv[0]]; 93 | return JSValueMakeBoolean(ctx, glIsVertexArrayOES(index)); 94 | } 95 | 96 | EJ_BIND_FUNCTION(bindVertexArrayOES, ctx, argc, argv) { 97 | if( argc < 1 ) { return NULL; } 98 | 99 | scriptView.currentRenderingContext = webglContext.renderingContext; 100 | GLuint index = [EJBindingWebGLVertexArrayObjectOES indexFromJSValue:argv[0]]; 101 | glBindVertexArrayOES(index); 102 | return NULL; 103 | } 104 | 105 | // Constants 106 | EJ_BIND_CONST_GL(VERTEX_ARRAY_BINDING_OES); 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJBindingWebGLObjects.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import "EJBindingCanvasContextWebGL.h" 3 | #import "EJTexture.h" 4 | 5 | @interface EJBindingWebGLObject : EJBindingBase { 6 | GLuint index; 7 | EJBindingCanvasContextWebGL *webglContext; 8 | } 9 | - (id)initWithWebGLContext:(EJBindingCanvasContextWebGL *)webglContext index:(GLuint)index; 10 | - (void)invalidate; 11 | + (GLuint)indexFromJSValue:(JSValueRef)value; 12 | + (EJBindingWebGLObject *)webGLObjectFromJSValue:(JSValueRef)value; 13 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 14 | scriptView:(EJJavaScriptView *)scriptView 15 | webglContext:(EJBindingCanvasContextWebGL *)webglContext 16 | index:(GLuint)index; 17 | @end 18 | 19 | 20 | @interface EJBindingWebGLBuffer : EJBindingWebGLObject 21 | @end 22 | 23 | 24 | @interface EJBindingWebGLProgram : EJBindingWebGLObject 25 | @end 26 | 27 | 28 | @interface EJBindingWebGLShader : EJBindingWebGLObject 29 | @end 30 | 31 | 32 | @interface EJBindingWebGLTexture : EJBindingWebGLObject { 33 | EJTexture *texture; 34 | } 35 | + (EJTexture *)textureFromJSValue:(JSValueRef)value; 36 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 37 | scriptView:(EJJavaScriptView *)scriptView 38 | webglContext:(EJBindingCanvasContextWebGL *)webglContext; 39 | @end 40 | 41 | 42 | @interface EJBindingWebGLUniformLocation : EJBindingWebGLObject 43 | @end 44 | 45 | 46 | @interface EJBindingWebGLRenderbuffer : EJBindingWebGLObject 47 | @end 48 | 49 | 50 | @interface EJBindingWebGLFramebuffer : EJBindingWebGLObject 51 | @end 52 | 53 | @interface EJBindingWebGLVertexArrayObjectOES : EJBindingWebGLObject 54 | @end 55 | 56 | @interface EJBindingWebGLActiveInfo : EJBindingBase { 57 | GLint size; 58 | GLenum type; 59 | NSString *name; 60 | } 61 | - (id)initWithSize:(GLint)sizep type:(GLenum)typep name:(NSString *)namep; 62 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 63 | scriptView:(EJJavaScriptView *)scriptView 64 | size:(GLint)sizep type:(GLenum)typep name:(NSString *)namep; 65 | @end 66 | 67 | 68 | @interface EJBindingWebGLShaderPrecisionFormat : EJBindingBase { 69 | GLint rangeMin; 70 | GLint rangeMax; 71 | GLint precision; 72 | } 73 | - (id)initWithRangeMin:(GLint)rangeMin rangeMax:(GLint)rangeMax precision:(GLint)precision; 74 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 75 | scriptView:(EJJavaScriptView *)scriptView 76 | rangeMin:(GLint)rangeMin rangeMax:(GLint)rangeMax precision:(GLint)precision; 77 | @end 78 | 79 | 80 | @interface EJBindingWebGLContextAttributes : EJBindingBase 81 | @end 82 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJCanvasContextWebGL.h: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContext.h" 2 | 3 | @class EJJavaScriptView; 4 | @interface EJCanvasContextWebGL : EJCanvasContext { 5 | GLuint viewFrameBuffer, viewRenderBuffer; 6 | GLuint msaaFrameBuffer, msaaRenderBuffer; 7 | GLuint boundFrameBuffer, boundRenderBuffer; 8 | GLuint depthStencilBuffer; 9 | 10 | GLint bufferWidth, bufferHeight; 11 | EJJavaScriptView *scriptView; 12 | } 13 | 14 | - (id)initWithScriptView:(EJJavaScriptView *)scriptView width:(short)width height:(short)height; 15 | - (void)resizeAuxiliaryBuffers; 16 | - (void)bindFramebuffer:(GLuint)framebuffer toTarget:(GLuint)target; 17 | - (void)bindRenderbuffer:(GLuint)framebuffer toTarget:(GLuint)target; 18 | - (void)create; 19 | - (void)prepare; 20 | - (void)clear; 21 | 22 | @property (nonatomic) BOOL needsPresenting; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJCanvasContextWebGLScreen.h: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContextWebGL.h" 2 | #import "EAGLView.h" 3 | #import "EJPresentable.h" 4 | 5 | @interface EJCanvasContextWebGLScreen : EJCanvasContextWebGL { 6 | EAGLView *glview; 7 | CGRect style; 8 | } 9 | 10 | - (void)present; 11 | - (void)finish; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJCanvasContextWebGLTexture.h: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContextWebGL.h" 2 | #import "EJTexture.h" 3 | 4 | @interface EJCanvasContextWebGLTexture : EJCanvasContextWebGL { 5 | EJTexture *texture; 6 | } 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJCanvasContextWebGLTexture.m: -------------------------------------------------------------------------------- 1 | #import "EJCanvasContextWebGLTexture.h" 2 | 3 | @implementation EJCanvasContextWebGLTexture 4 | 5 | - (void)dealloc { 6 | [texture release]; 7 | [super dealloc]; 8 | } 9 | 10 | - (void)resizeToWidth:(short)newWidth height:(short)newHeight { 11 | [self flushBuffers]; 12 | 13 | bufferWidth = width = newWidth; 14 | bufferHeight = height = newHeight; 15 | 16 | NSLog( 17 | @"Creating Offscreen Canvas (WebGL): size: %dx%d, antialias: %@", 18 | width, height, 19 | (msaaEnabled ? [NSString stringWithFormat:@"yes (%d samples)", msaaSamples] : @"no") 20 | ); 21 | 22 | GLint previousFrameBuffer; 23 | GLint previousRenderBuffer; 24 | glGetIntegerv( GL_FRAMEBUFFER_BINDING, &previousFrameBuffer ); 25 | glGetIntegerv( GL_RENDERBUFFER_BINDING, &previousRenderBuffer ); 26 | 27 | glBindFramebuffer(GL_FRAMEBUFFER, viewFrameBuffer); 28 | glBindRenderbuffer(GL_RENDERBUFFER, viewRenderBuffer); 29 | 30 | // Release previous texture if any, create the new texture and set it as 31 | // the rendering target for this framebuffer 32 | [texture release]; 33 | texture = [[EJTexture alloc] initAsRenderTargetWithWidth:newWidth height:newHeight fbo:viewFrameBuffer]; 34 | texture.drawFlippedY = true; 35 | 36 | glBindFramebuffer(GL_FRAMEBUFFER, viewFrameBuffer); 37 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.textureId, 0); 38 | 39 | [self resizeAuxiliaryBuffers]; 40 | 41 | // Clear 42 | glViewport(0, 0, width, height); 43 | [self clear]; 44 | 45 | // Reset to the previously bound frame and renderbuffers 46 | [self bindFramebuffer:previousFrameBuffer toTarget:GL_FRAMEBUFFER]; 47 | [self bindRenderbuffer:previousRenderBuffer toTarget:GL_RENDERBUFFER]; 48 | } 49 | 50 | - (EJTexture *)texture { 51 | // If this texture Canvas uses MSAA, we need to resolve the MSAA first, 52 | // before we can use the texture for drawing. 53 | if( msaaEnabled && needsPresenting ) { 54 | GLint previousFrameBuffer; 55 | glGetIntegerv( GL_FRAMEBUFFER_BINDING, &previousFrameBuffer ); 56 | 57 | //Bind the MSAA and View frameBuffers and resolve 58 | glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, msaaFrameBuffer); 59 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, viewFrameBuffer); 60 | glResolveMultisampleFramebufferAPPLE(); 61 | 62 | glBindFramebuffer(GL_FRAMEBUFFER, previousFrameBuffer); 63 | needsPresenting = NO; 64 | } 65 | 66 | return texture; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJConvertWebGL.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | GLfloat *JSValueToGLfloatArray(JSContextRef ctx, JSValueRef value, GLsizei elementSize, GLsizei *numElements); 11 | GLint *JSValueToGLintArray(JSContextRef ctx, JSValueRef value, GLsizei elementSize, GLsizei *numElements); 12 | GLuint EJGetBytesPerPixel(GLenum type, GLenum format); 13 | 14 | #define EJ_ARRAY_MATCHES_TYPE(ARRAY, TYPE) ( \ 15 | (ARRAY == kJSTypedArrayTypeUint8Array && TYPE == GL_UNSIGNED_BYTE) || \ 16 | (ARRAY == kJSTypedArrayTypeFloat32Array && TYPE == GL_FLOAT) || \ 17 | (ARRAY == kJSTypedArrayTypeUint16Array && ( \ 18 | TYPE == GL_UNSIGNED_SHORT_5_6_5 || \ 19 | TYPE == GL_UNSIGNED_SHORT_4_4_4_4 || \ 20 | TYPE == GL_UNSIGNED_SHORT_5_5_5_1 \ 21 | )) \ 22 | ) 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif -------------------------------------------------------------------------------- /Source/Ejecta/EJCanvas/WebGL/EJConvertWebGL.m: -------------------------------------------------------------------------------- 1 | #import "EJConvertWebGL.h" 2 | #import "EJConvert.h" 3 | #import 4 | 5 | // FIXME: use C++ with a template? 6 | #define CREATE_JS_VALUE_TO_ARRAY_FUNC(NAME, TYPE, ARRAY_TYPE) \ 7 | TYPE *NAME(JSContextRef ctx, JSValueRef value, GLsizei elementSize, GLsizei *numElements) { \ 8 | if( !JSValueIsObject(ctx, value) ) { \ 9 | return NULL; \ 10 | } \ 11 | JSObjectRef jsObject = (JSObjectRef)value; \ 12 | if( JSObjectGetTypedArrayType(ctx, jsObject) == ARRAY_TYPE ) { \ 13 | size_t byteLength; \ 14 | TYPE *arrayValue = JSObjectGetTypedArrayDataPtr(ctx, jsObject, &byteLength); \ 15 | GLsizei count = (GLsizei)(byteLength/sizeof(TYPE)); \ 16 | if( arrayValue && count && (count % elementSize) == 0 ) { \ 17 | *numElements = count / elementSize; \ 18 | return arrayValue; \ 19 | } \ 20 | } \ 21 | else { \ 22 | JSStringRef jsLengthName = JSStringCreateWithUTF8CString("length"); \ 23 | GLsizei count = JSValueToNumberFast(ctx, JSObjectGetProperty(ctx, jsObject, jsLengthName, NULL)); \ 24 | JSStringRelease(jsLengthName); \ 25 | \ 26 | if( count && (count % elementSize) == 0 ) { \ 27 | NSMutableData *buffer = [NSMutableData dataWithCapacity:count * sizeof(TYPE)]; \ 28 | TYPE *values = buffer.mutableBytes; \ 29 | for( int i = 0; i < count; i++ ) { \ 30 | values[i] = JSValueToNumberFast(ctx, JSObjectGetPropertyAtIndex(ctx, jsObject, i, NULL)); \ 31 | } \ 32 | *numElements = count / elementSize; \ 33 | return values; \ 34 | } \ 35 | } \ 36 | \ 37 | *numElements = 0; \ 38 | return NULL; \ 39 | } 40 | 41 | CREATE_JS_VALUE_TO_ARRAY_FUNC( JSValueToGLfloatArray, GLfloat, kJSTypedArrayTypeFloat32Array); 42 | CREATE_JS_VALUE_TO_ARRAY_FUNC( JSValueToGLintArray, GLint, kJSTypedArrayTypeInt32Array); 43 | 44 | #undef CREATE_JS_VALUE_TO_ARRAY_FUNC 45 | 46 | 47 | GLuint EJGetBytesPerPixel(GLenum type, GLenum format) { 48 | int bytesPerComponent = 0; 49 | switch( type ) { 50 | case GL_UNSIGNED_BYTE: 51 | bytesPerComponent = 1; 52 | break; 53 | case GL_FLOAT: 54 | bytesPerComponent = 4; 55 | break; 56 | case GL_HALF_FLOAT_OES: 57 | bytesPerComponent = 2; 58 | break; 59 | case GL_UNSIGNED_SHORT_5_6_5: 60 | case GL_UNSIGNED_SHORT_4_4_4_4: 61 | case GL_UNSIGNED_SHORT_5_5_5_1: 62 | return 2; 63 | } 64 | 65 | switch( format ) { 66 | case GL_LUMINANCE: 67 | case GL_ALPHA: 68 | return 1 * bytesPerComponent; 69 | case GL_LUMINANCE_ALPHA: 70 | return 2 * bytesPerComponent; 71 | case GL_RGB: 72 | return 3 * bytesPerComponent; 73 | case GL_RGBA: 74 | return 4 * bytesPerComponent; 75 | } 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Source/Ejecta/EJClassLoader.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @class EJJavaScriptView; 5 | @class EJLoadedJSClass; 6 | @interface EJClassLoader : NSObject { 7 | JSClassRef jsConstructorClass; 8 | NSMutableDictionary *classCache; 9 | } 10 | 11 | - (EJLoadedJSClass *)getJSClass:(id)class; 12 | - (EJLoadedJSClass *)loadJSClass:(id)class; 13 | 14 | - (id)initWithScriptView:(EJJavaScriptView *)scriptView name:(NSString *)name; 15 | 16 | @property (nonatomic, readonly) JSClassRef jsConstructorClass; 17 | 18 | @end 19 | 20 | 21 | @interface EJLoadedJSClass : NSObject { 22 | JSClassRef jsClass; 23 | NSDictionary *constantValues; 24 | } 25 | 26 | - (id)initWithJSClass:(JSClassRef)jsClassp constantValues:(NSDictionary *)constantValuesp; 27 | @property (readonly) JSClassRef jsClass; 28 | @property (readonly) NSDictionary *constantValues; 29 | @end 30 | -------------------------------------------------------------------------------- /Source/Ejecta/EJConvert.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "JavaScriptCore/JavaScriptCore.h" 3 | 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | NSString *JSValueToNSString( JSContextRef ctx, JSValueRef v ); 10 | JSValueRef NSStringToJSValue( JSContextRef ctx, NSString *string ); 11 | double JSValueToNumberFast( JSContextRef ctx, JSValueRef v ); 12 | void JSValueUnprotectSafe( JSContextRef ctx, JSValueRef v ); 13 | JSValueRef NSObjectToJSValue( JSContextRef ctx, NSObject *obj ); 14 | NSObject *JSValueToNSObject( JSContextRef ctx, JSValueRef value ); 15 | 16 | static inline void *JSValueGetPrivate(JSValueRef v) { 17 | // On 64bit systems we can not safely call JSObjectGetPrivate with any 18 | // JSValueRef. Doing so with immediate values (numbers, null, bool, 19 | // undefined) will crash the app. So we check for these first. 20 | 21 | #if __LP64__ 22 | #define JSValueTagMask (0xffff000000000000ll | 0x2ll) 23 | return !((int64_t)v & JSValueTagMask) ? JSObjectGetPrivate((JSObjectRef)v) : NULL; 24 | #else 25 | return JSObjectGetPrivate((JSObjectRef)v); 26 | #endif 27 | } 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif -------------------------------------------------------------------------------- /Source/Ejecta/EJJavaScriptView.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import "EJConvert.h" 5 | #import "EJCanvasContext.h" 6 | #import "EJPresentable.h" 7 | 8 | #import "EJSharedOpenALManager.h" 9 | #import "EJSharedTextureCache.h" 10 | #import "EJSharedOpenGLContext.h" 11 | #import "EJNonRetainingProxy.h" 12 | 13 | #define EJECTA_VERSION @"1.5" 14 | #define EJECTA_DEFAULT_APP_FOLDER @"App/" 15 | 16 | #define EJECTA_BOOT_JS @"../Ejecta.js" 17 | 18 | #define EJECTA_SYSTEM_VERSION_LESS_THAN(v) \ 19 | ([UIDevice.currentDevice.systemVersion compare:v options:NSNumericSearch] == NSOrderedAscending) 20 | 21 | 22 | @protocol EJTouchDelegate 23 | - (void)triggerEvent:(NSString *)name all:(NSSet *)all changed:(NSSet *)changed remaining:(NSSet *)remaining; 24 | @end 25 | 26 | @protocol EJDeviceMotionDelegate 27 | - (void)triggerDeviceMotionEvents; 28 | @end 29 | 30 | @protocol EJWindowEventsDelegate 31 | - (void)resume; 32 | - (void)pause; 33 | - (void)resize; 34 | @end 35 | 36 | @class EJTimerCollection; 37 | @class EJClassLoader; 38 | 39 | @interface EJJavaScriptView : UIView { 40 | CGSize oldSize; 41 | NSString *appFolder; 42 | 43 | BOOL pauseOnEnterBackground; 44 | BOOL hasScreenCanvas; 45 | 46 | BOOL isPaused; 47 | BOOL exitOnMenuPress; 48 | 49 | EJNonRetainingProxy *proxy; 50 | 51 | JSGlobalContextRef jsGlobalContext; 52 | EJClassLoader *classLoader; 53 | 54 | EJTimerCollection *timers; 55 | 56 | EJSharedOpenGLContext *openGLContext; 57 | EJSharedTextureCache *textureCache; 58 | EJSharedOpenALManager *openALManager; 59 | 60 | EJCanvasContext *currentRenderingContext; 61 | EAGLContext *glCurrentContext; 62 | 63 | CADisplayLink *displayLink; 64 | 65 | NSObject *windowEventsDelegate; 66 | NSObject *touchDelegate; 67 | NSObject *deviceMotionDelegate; 68 | EJCanvasContext *screenRenderingContext; 69 | 70 | NSOperationQueue *backgroundQueue; 71 | JSClassRef jsBlockFunctionClass; 72 | 73 | // Public for fast access in bound functions 74 | @public JSValueRef jsUndefined; 75 | } 76 | 77 | @property (nonatomic, copy) NSString *appFolder; 78 | 79 | @property (nonatomic, assign) BOOL pauseOnEnterBackground; 80 | @property (nonatomic, assign, getter = isPaused) BOOL isPaused; // Pauses drawing/updating of the JSView 81 | @property (nonatomic, assign) BOOL hasScreenCanvas; 82 | @property (nonatomic, assign) BOOL exitOnMenuPress; 83 | 84 | @property (nonatomic, readonly) JSGlobalContextRef jsGlobalContext; 85 | @property (nonatomic, readonly) EJSharedOpenGLContext *openGLContext; 86 | 87 | @property (nonatomic, retain) NSObject *windowEventsDelegate; 88 | @property (nonatomic, retain) NSObject *touchDelegate; 89 | @property (nonatomic, retain) NSObject *deviceMotionDelegate; 90 | 91 | @property (nonatomic, retain) EJCanvasContext *currentRenderingContext; 92 | @property (nonatomic, retain) EJCanvasContext *screenRenderingContext; 93 | 94 | @property (nonatomic, retain) NSOperationQueue *backgroundQueue; 95 | @property (nonatomic, retain) EJClassLoader *classLoader; 96 | 97 | - (id)initWithFrame:(CGRect)frame appFolder:(NSString *)folder; 98 | 99 | - (void)loadScriptAtPath:(NSString *)path; 100 | - (JSValueRef)evaluateScript:(NSString *)script; 101 | - (JSValueRef)evaluateScript:(NSString *)script sourceURL:(NSString *)sourceURL; 102 | - (void)logException:(JSValueRef)exception ctx:(JSContextRef)ctx; 103 | - (JSValueRef)jsValueForPath:(NSString *)objectPath; 104 | 105 | - (void)clearCaches; 106 | 107 | - (JSValueRef)invokeCallback:(JSObjectRef)callback thisObject:(JSObjectRef)thisObject argc:(size_t)argc argv:(const JSValueRef [])argv; 108 | - (NSString *)pathForResource:(NSString *)resourcePath; 109 | - (JSValueRef)deleteTimer:(JSContextRef)ctx argc:(size_t)argc argv:(const JSValueRef [])argv; 110 | - (JSValueRef)loadModuleWithId:(NSString *)moduleId module:(JSValueRef)module exports:(JSValueRef)exports; 111 | - (JSValueRef)createTimer:(JSContextRef)ctxp argc:(size_t)argc argv:(const JSValueRef [])argv repeat:(BOOL)repeat; 112 | - (JSObjectRef)createFunctionWithBlock:(JSValueRef (^)(JSContextRef ctx, size_t argc, const JSValueRef argv[]))block; 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Source/Ejecta/EJNonRetainingProxy.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | // "Weak proxy" to avoid retain loops. 4 | // Adapted from http://stackoverflow.com/a/13921278/1525473 5 | 6 | @interface EJNonRetainingProxy : NSObject { 7 | id target; 8 | } 9 | 10 | + (EJNonRetainingProxy *)proxyWithTarget:(id)target; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Source/Ejecta/EJNonRetainingProxy.m: -------------------------------------------------------------------------------- 1 | #import "EJNonRetainingProxy.h" 2 | 3 | @implementation EJNonRetainingProxy 4 | + (EJNonRetainingProxy *)proxyWithTarget:(id)target { 5 | EJNonRetainingProxy *proxy = [[[self alloc] init] autorelease]; 6 | proxy->target = target; 7 | return proxy; 8 | } 9 | 10 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { 11 | return [target methodSignatureForSelector:sel]; 12 | } 13 | 14 | - (BOOL)respondsToSelector:(SEL)sel { 15 | return [target respondsToSelector:sel] || [super respondsToSelector:sel]; 16 | } 17 | 18 | - (id)forwardingTargetForSelector:(SEL)sel { 19 | return target; 20 | } 21 | 22 | - (void)forwardInvocation:(NSInvocation *)invocation { 23 | if( [target respondsToSelector:invocation.selector] ) { 24 | [invocation invokeWithTarget:target]; 25 | } 26 | else { 27 | [super forwardInvocation:invocation]; 28 | } 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Source/Ejecta/EJSharedOpenGLContext.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJGLProgram2D.h" 3 | #import "EJGLProgram2DRadialGradient.h" 4 | 5 | #define EJ_OPENGL_VERTEX_BUFFER_SIZE (32 * 1024) // 32kb 6 | 7 | @interface EJSharedOpenGLContext : NSObject { 8 | EJGLProgram2D *glProgram2DFlat; 9 | EJGLProgram2D *glProgram2DTexture; 10 | EJGLProgram2D *glProgram2DAlphaTexture; 11 | EJGLProgram2D *glProgram2DPattern; 12 | EJGLProgram2DRadialGradient *glProgram2DRadialGradient; 13 | 14 | EAGLContext *glContext2D; 15 | EAGLSharegroup *glSharegroup; 16 | NSMutableData *vertexBuffer; 17 | } 18 | 19 | + (EJSharedOpenGLContext *)instance; 20 | 21 | @property (nonatomic, readonly) EJGLProgram2D *glProgram2DFlat; 22 | @property (nonatomic, readonly) EJGLProgram2D *glProgram2DTexture; 23 | @property (nonatomic, readonly) EJGLProgram2D *glProgram2DAlphaTexture; 24 | @property (nonatomic, readonly) EJGLProgram2D *glProgram2DPattern; 25 | @property (nonatomic, readonly) EJGLProgram2DRadialGradient *glProgram2DRadialGradient; 26 | 27 | @property (nonatomic, readonly) EAGLContext *glContext2D; 28 | @property (nonatomic, readonly) EAGLSharegroup *glSharegroup; 29 | @property (nonatomic, readonly) NSMutableData *vertexBuffer; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Source/Ejecta/EJSharedOpenGLContext.m: -------------------------------------------------------------------------------- 1 | #import "EJSharedOpenGLContext.h" 2 | #import "EJCanvas/2D/EJCanvasShaders.h" 3 | 4 | @implementation EJSharedOpenGLContext 5 | 6 | @synthesize glProgram2DFlat; 7 | @synthesize glProgram2DTexture; 8 | @synthesize glProgram2DAlphaTexture; 9 | @synthesize glProgram2DPattern; 10 | @synthesize glProgram2DRadialGradient; 11 | @synthesize glContext2D; 12 | @synthesize glSharegroup; 13 | 14 | static EJSharedOpenGLContext *sharedOpenGLContext; 15 | + (EJSharedOpenGLContext *)instance { 16 | if( !sharedOpenGLContext ) { 17 | sharedOpenGLContext = [[[EJSharedOpenGLContext alloc] init] autorelease]; 18 | } 19 | return sharedOpenGLContext; 20 | } 21 | 22 | - (id)init { 23 | if( self = [super init] ) { 24 | glContext2D = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 25 | glSharegroup = glContext2D.sharegroup; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)dealloc { 31 | sharedOpenGLContext = nil; 32 | 33 | [glProgram2DFlat release]; 34 | [glProgram2DTexture release]; 35 | [glProgram2DAlphaTexture release]; 36 | [glProgram2DPattern release]; 37 | [glProgram2DRadialGradient release]; 38 | [glContext2D release]; 39 | [vertexBuffer release]; 40 | 41 | [EAGLContext setCurrentContext:nil]; 42 | [super dealloc]; 43 | } 44 | 45 | - (NSMutableData *)vertexBuffer { 46 | if( !vertexBuffer ) { 47 | vertexBuffer = [[NSMutableData alloc] initWithLength:EJ_OPENGL_VERTEX_BUFFER_SIZE]; 48 | } 49 | return vertexBuffer; 50 | } 51 | 52 | #define EJ_GL_PROGRAM_GETTER(TYPE, NAME) \ 53 | - (TYPE *)glProgram2D##NAME { \ 54 | if( !glProgram2D##NAME ) { \ 55 | glProgram2D##NAME = [[TYPE alloc] initWithVertexShader:EJShaderVertex fragmentShader:EJShader##NAME]; \ 56 | } \ 57 | return glProgram2D##NAME; \ 58 | } 59 | 60 | EJ_GL_PROGRAM_GETTER(EJGLProgram2D, Flat); 61 | EJ_GL_PROGRAM_GETTER(EJGLProgram2D, Texture); 62 | EJ_GL_PROGRAM_GETTER(EJGLProgram2D, AlphaTexture); 63 | EJ_GL_PROGRAM_GETTER(EJGLProgram2D, Pattern); 64 | EJ_GL_PROGRAM_GETTER(EJGLProgram2DRadialGradient, RadialGradient); 65 | 66 | #undef EJ_GL_PROGRAM_GETTER 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Source/Ejecta/EJTimer.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @class EJJavaScriptView; 5 | 6 | @interface EJTimerCollection : NSObject { 7 | NSMutableDictionary *timers; 8 | int lastId; 9 | EJJavaScriptView *scriptView; 10 | } 11 | 12 | - (id)initWithScriptView:(EJJavaScriptView *)scriptView; 13 | - (int)scheduleCallback:(JSObjectRef)callback interval:(NSTimeInterval)interval repeat:(BOOL)repeat; 14 | - (void)cancelId:(int)timerId; 15 | - (void)update; 16 | 17 | @end 18 | 19 | 20 | @interface EJTimer : NSObject { 21 | NSTimeInterval interval; 22 | JSObjectRef callback; 23 | BOOL active, repeat; 24 | EJJavaScriptView *scriptView; 25 | } 26 | 27 | - (id)initWithScriptView:(EJJavaScriptView *)scriptViewp 28 | callback:(JSObjectRef)callbackp 29 | interval:(NSTimeInterval)intervalp 30 | repeat:(BOOL)repeatp; 31 | - (void)check; 32 | 33 | @property (readonly) BOOL active; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Source/Ejecta/EJTimer.m: -------------------------------------------------------------------------------- 1 | #import "EJTimer.h" 2 | #import "EJJavaScriptView.h" 3 | 4 | 5 | @implementation EJTimerCollection 6 | 7 | 8 | - (id)initWithScriptView:(EJJavaScriptView *)scriptViewp { 9 | if (self = [super init]) { 10 | scriptView = scriptViewp; 11 | timers = [[NSMutableDictionary alloc] init]; 12 | } 13 | return self; 14 | } 15 | 16 | - (void)dealloc { 17 | [timers release]; 18 | [super dealloc]; 19 | } 20 | 21 | - (int)scheduleCallback:(JSObjectRef)callback interval:(NSTimeInterval)interval repeat:(BOOL)repeat { 22 | lastId++; 23 | 24 | EJTimer *timer = [[EJTimer alloc] initWithScriptView:scriptView callback:callback interval:interval repeat:repeat]; 25 | timers[@(lastId)] = timer; 26 | [timer release]; 27 | return lastId; 28 | } 29 | 30 | - (void)cancelId:(int)timerId { 31 | [timers removeObjectForKey:@(timerId)]; 32 | } 33 | 34 | - (void)update { 35 | for( NSNumber *timerId in [timers allKeys]) { 36 | EJTimer *timer = [timers[timerId] retain]; 37 | [timer check]; 38 | 39 | if( !timer.active ) { 40 | [timers removeObjectForKey:timerId]; 41 | } 42 | [timer release]; 43 | } 44 | } 45 | 46 | @end 47 | 48 | 49 | 50 | @interface EJTimer() 51 | @property (nonatomic, retain) NSDate *target; 52 | @end 53 | 54 | 55 | @implementation EJTimer 56 | @synthesize active; 57 | 58 | - (id)initWithScriptView:(EJJavaScriptView *)scriptViewp 59 | callback:(JSObjectRef)callbackp 60 | interval:(NSTimeInterval)intervalp 61 | repeat:(BOOL)repeatp 62 | { 63 | if( self = [super init] ) { 64 | scriptView = scriptViewp; 65 | active = true; 66 | interval = intervalp; 67 | repeat = repeatp; 68 | self.target = [NSDate dateWithTimeIntervalSinceNow:interval]; 69 | 70 | callback = callbackp; 71 | JSValueProtect(scriptView.jsGlobalContext, callback); 72 | } 73 | return self; 74 | } 75 | 76 | - (void)dealloc { 77 | self.target = nil; 78 | JSValueUnprotectSafe(scriptView.jsGlobalContext, callback); 79 | [super dealloc]; 80 | } 81 | 82 | - (void)check { 83 | if( active && self.target.timeIntervalSinceNow <= 0 ) { 84 | [scriptView invokeCallback:callback thisObject:NULL argc:0 argv:NULL]; 85 | 86 | if( repeat ) { 87 | self.target = [NSDate dateWithTimeIntervalSinceNow:interval]; 88 | } 89 | else { 90 | active = false; 91 | } 92 | } 93 | } 94 | 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingAdBanner.h: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import 4 | #import "EJBindingEventedBase.h" 5 | 6 | #import "iAd/iAd.h" 7 | 8 | 9 | @interface EJBindingAdBanner : EJBindingEventedBase { 10 | ADBannerView *banner; 11 | BOOL isAtBottom, wantsToShow, isReady; 12 | } 13 | 14 | @end 15 | #endif 16 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingAdBanner.m: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import "EJBindingAdBanner.h" 4 | #import "EJJavaScriptView.h" 5 | 6 | @implementation EJBindingAdBanner 7 | 8 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 9 | [super createWithJSObject:obj scriptView:view]; 10 | 11 | isAtBottom = NO; 12 | wantsToShow = NO; 13 | isReady = NO; 14 | 15 | banner = [[ADBannerView alloc] initWithFrame:CGRectZero]; 16 | banner.delegate = self; 17 | banner.hidden = YES; 18 | banner.autoresizingMask = UIViewAutoresizingFlexibleWidth; 19 | 20 | [scriptView addSubview:banner]; 21 | NSLog(@"AdBanner: init at y %f", banner.frame.origin.y); 22 | } 23 | 24 | - (void)dealloc { 25 | [banner removeFromSuperview]; 26 | [banner release]; 27 | [super dealloc]; 28 | } 29 | 30 | - (void)bannerViewDidLoadAd:(ADBannerView *)theBanner { 31 | NSLog(@"AdBanner: Ad loaded"); 32 | isReady = YES; 33 | if( wantsToShow ) { 34 | [scriptView bringSubviewToFront:banner]; 35 | banner.hidden = NO; 36 | } 37 | [self triggerEvent:@"load"]; 38 | } 39 | 40 | - (void)bannerView:(ADBannerView *)theBanner didFailToReceiveAdWithError:(NSError *)error { 41 | NSLog(@"AdBanner: Failed to receive Ad. Error: %ld - %@", (long)error.code, error.localizedDescription); 42 | [self triggerEvent:@"error"]; 43 | banner.hidden = YES; 44 | } 45 | 46 | EJ_BIND_GET( isReady, ctx ) { 47 | return JSValueMakeBoolean(ctx, isReady); 48 | } 49 | 50 | EJ_BIND_GET( isAtBottom, ctx ) { 51 | return JSValueMakeBoolean(ctx, isAtBottom); 52 | } 53 | 54 | EJ_BIND_SET( isAtBottom, ctx, value ) { 55 | isAtBottom = JSValueToBoolean(ctx, value); 56 | 57 | CGRect frame = banner.frame; 58 | frame.origin.y = isAtBottom 59 | ? scriptView.bounds.size.height - frame.size.height 60 | : 0; 61 | 62 | banner.frame = frame; 63 | } 64 | 65 | EJ_BIND_FUNCTION(hide, ctx, argc, argv ) { 66 | banner.hidden = YES; 67 | wantsToShow = NO; 68 | return NULL; 69 | } 70 | 71 | EJ_BIND_FUNCTION(show, ctx, argc, argv ) { 72 | wantsToShow = YES; 73 | if( isReady ) { 74 | [scriptView bringSubviewToFront:banner]; 75 | banner.hidden = NO; 76 | } 77 | return NULL; 78 | } 79 | 80 | EJ_BIND_EVENT(load); 81 | EJ_BIND_EVENT(error); 82 | 83 | @end 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingDeviceMotion.h: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import "EJBindingEventedBase.h" 4 | #import "EJJavaScriptView.h" 5 | #import 6 | 7 | @interface EJBindingDeviceMotion : EJBindingEventedBase { 8 | CMMotionManager *motionManager; 9 | JSValueRef params[12]; 10 | float interval; 11 | } 12 | 13 | - (void)triggerDeviceMotionEvents; 14 | - (void)triggerEventWithMotion:(CMDeviceMotion *)motion; 15 | - (void)triggerEventWithAccelerometerData:(CMAccelerometerData *)accel; 16 | 17 | @end 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingDeviceMotion.m: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import "EJBindingDeviceMotion.h" 4 | #import "EJJavaScriptView.h" 5 | 6 | @implementation EJBindingDeviceMotion 7 | 8 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 9 | [super createWithJSObject:obj scriptView:view]; 10 | interval = 1.0f/60.0f; 11 | motionManager = [[CMMotionManager alloc] init]; 12 | 13 | // Has Gyro? (iPhone4 and newer) 14 | if( motionManager.isDeviceMotionAvailable ) { 15 | motionManager.deviceMotionUpdateInterval = interval; 16 | [motionManager startDeviceMotionUpdates]; 17 | } 18 | 19 | // Only basic accelerometer data 20 | else { 21 | motionManager.accelerometerUpdateInterval = interval; 22 | [motionManager startAccelerometerUpdates]; 23 | } 24 | 25 | scriptView.deviceMotionDelegate = self; 26 | } 27 | 28 | - (void)prepareGarbageCollection { 29 | [motionManager stopDeviceMotionUpdates]; 30 | [motionManager stopAccelerometerUpdates]; 31 | } 32 | 33 | - (void)dealloc { 34 | [motionManager release]; 35 | [super dealloc]; 36 | } 37 | 38 | 39 | static const float g = 9.80665; 40 | static const float radToDeg = (180/M_PI); 41 | 42 | - (void)triggerEventWithMotion:(CMDeviceMotion *)motion { 43 | JSContextRef ctx = scriptView.jsGlobalContext; 44 | 45 | // accelerationIncludingGravity {x, y, z} 46 | params[0] = JSValueMakeNumber(ctx, (motion.userAcceleration.x + motion.gravity.x) * g); 47 | params[1] = JSValueMakeNumber(ctx, (motion.userAcceleration.y + motion.gravity.y) * g); 48 | params[2] = JSValueMakeNumber(ctx, (motion.userAcceleration.z + motion.gravity.z) * g); 49 | 50 | // acceleration {x, y, z} 51 | params[3] = JSValueMakeNumber(ctx, motion.userAcceleration.x * g); 52 | params[4] = JSValueMakeNumber(ctx, motion.userAcceleration.y * g); 53 | params[5] = JSValueMakeNumber(ctx, motion.userAcceleration.z * g); 54 | 55 | // rotation rate {alpha, beta, gamma} 56 | params[6] = JSValueMakeNumber(ctx, motion.rotationRate.x * radToDeg); 57 | params[7] = JSValueMakeNumber(ctx, motion.rotationRate.y * radToDeg); 58 | params[8] = JSValueMakeNumber(ctx, motion.rotationRate.z * radToDeg); 59 | 60 | // orientation {alpha, beta, gamma} 61 | params[9] = JSValueMakeNumber(ctx, motion.attitude.yaw * radToDeg); 62 | params[10] = JSValueMakeNumber(ctx, motion.attitude.pitch * radToDeg); 63 | params[11] = JSValueMakeNumber(ctx, motion.attitude.roll * radToDeg); 64 | 65 | [self triggerEvent:@"devicemotion" argc:12 argv:params]; 66 | } 67 | 68 | - (void)triggerEventWithAccelerometerData:(CMAccelerometerData *)accel { 69 | JSContextRef ctx = scriptView.jsGlobalContext; 70 | 71 | // accelerationIncludingGravity {x, y, z} 72 | params[0] = JSValueMakeNumber(ctx, accel.acceleration.x * g); 73 | params[1] = JSValueMakeNumber(ctx, accel.acceleration.y * g); 74 | params[2] = JSValueMakeNumber(ctx, accel.acceleration.z * g); 75 | 76 | [self triggerEvent:@"acceleration" argc:3 argv:params]; 77 | } 78 | 79 | - (void)triggerDeviceMotionEvents { 80 | if( motionManager.isDeviceMotionAvailable ) { 81 | [self triggerEventWithMotion:motionManager.deviceMotion]; 82 | } 83 | else { 84 | [self triggerEventWithAccelerometerData:motionManager.accelerometerData]; 85 | } 86 | } 87 | 88 | EJ_BIND_GET(interval, ctx) { 89 | return JSValueMakeNumber(ctx, roundf(interval*1000)); // update interval in ms 90 | } 91 | 92 | EJ_BIND_EVENT(devicemotion); 93 | EJ_BIND_EVENT(acceleration); 94 | 95 | @end 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingGameCenter.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import 3 | 4 | enum { 5 | kEJGameCenterAutoAuthNeverTried = 0, 6 | kEJGameCenterAutoAuthFailed = 1, 7 | kEJGameCenterAutoAuthSucceeded = 2 8 | }; 9 | 10 | static NSString *kEJGameCenterAutoAuth = @"EJGameCenter.AutoAuth"; 11 | 12 | @interface EJBindingGameCenter : EJBindingBase { 13 | BOOL authed; 14 | BOOL viewIsActive; 15 | NSMutableDictionary *achievements; 16 | } 17 | 18 | - (void)loadAchievements; 19 | - (void)reportAchievementWithIdentifier:(NSString *)identifier 20 | percentage:(float)percentage isIncrement:(BOOL)isIncrement 21 | ctx:(JSContextRef)ctx callback:(JSObjectRef)callback; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingGeolocation.h: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import "EJBindingBase.h" 4 | #import 5 | 6 | enum { 7 | kEJGeolocationErrorDenied = 1, 8 | kEJGeolocationErrorUnavailable = 2, 9 | kEJGeolocationErrorTimeout = 3 10 | }; 11 | 12 | @interface EJGeolocationCallback : NSObject { 13 | EJJavaScriptView *scriptView; 14 | JSObjectRef callback; 15 | JSObjectRef errback; 16 | BOOL oneShot; 17 | } 18 | 19 | - (id)initWithScriptView:(EJJavaScriptView *)scriptViewp 20 | callback:(JSObjectRef)callbackp errback:(JSObjectRef)errbackp 21 | oneShot:(BOOL)oneShotp; 22 | 23 | @property (readonly) JSObjectRef callback; 24 | @property (readonly) JSObjectRef errback; 25 | @property (readonly) BOOL oneShot; 26 | 27 | @end 28 | 29 | 30 | @interface EJBindingGeolocation : EJBindingBase { 31 | CLLocationManager *locationManager; 32 | NSMutableDictionary *callbacks; 33 | int currentIndex; 34 | } 35 | 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingHttpRequest.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingEventedBase.h" 2 | 3 | typedef enum { 4 | kEJHttpRequestTypeString, 5 | kEJHttpRequestTypeArrayBuffer, 6 | kEJHttpRequestTypeBlob, 7 | kEJHttpRequestTypeDocument, 8 | kEJHttpRequestTypeJSON, 9 | kEJHttpRequestTypeText 10 | } EJHttpRequestType; 11 | 12 | typedef enum { 13 | kEJHttpRequestStateUnsent = 0, 14 | kEJHttpRequestStateOpened = 1, 15 | kEJHttpRequestStateHeadersReceived = 2, 16 | kEJHttpRequestStateLoading = 3, 17 | kEJHttpRequestStateDone = 4, 18 | } EJHttpRequestState; 19 | 20 | @interface EJBindingHttpRequest : EJBindingEventedBase { 21 | EJHttpRequestType type; 22 | NSString *method; 23 | NSString *url; 24 | BOOL async; 25 | NSString *user; 26 | NSString *password; 27 | int timeout; 28 | NSMutableDictionary *requestHeaders; 29 | NSStringEncoding defaultEncoding; 30 | 31 | EJHttpRequestState state; 32 | NSURLSession *session; 33 | NSURLResponse *response; 34 | NSMutableData *responseBody; 35 | } 36 | 37 | - (void)clearConnection; 38 | - (void)clearRequest; 39 | - (NSString *)getResponseText; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingImagePicker.h: -------------------------------------------------------------------------------- 1 | #if !TARGET_OS_TV 2 | 3 | #import "EJBindingBase.h" 4 | 5 | #define EJ_PICKER_TYPE_FULLSCREEN 1 6 | #define EJ_PICKER_TYPE_POPUP 2 7 | 8 | typedef enum { 9 | kEJImagePickerTypeFullscreen, 10 | kEJImagePickerTypePopup 11 | } EJImagePickerType; 12 | 13 | @interface EJBindingImagePicker : EJBindingBase { 14 | JSObjectRef callback; 15 | UIImagePickerController *picker; 16 | NSString *imgFormat; 17 | float jpgCompression; 18 | EJImagePickerType pickerType; 19 | float maxJsWidth, maxJsHeight; 20 | float maxTexWidth, maxTexHeight; 21 | } 22 | 23 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info; 24 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker; 25 | - (void)successCallback:(JSValueRef[])params; 26 | - (void)errorCallback:(NSString *)message; 27 | - (void)closePicker:(JSContextRef)ctx; 28 | - (UIImage *)reduceImageSize:(UIImage *)image; 29 | 30 | + (BOOL)isSourceTypeAvailable:(NSString *) sourceType; 31 | 32 | @end 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingKeyInput.h: -------------------------------------------------------------------------------- 1 | 2 | #import "EJBindingEventedBase.h" 3 | 4 | #pragma mark - EJKeyInputDelegate 5 | 6 | @class EJKeyInputResponder; 7 | @protocol EJKeyInputDelegate 8 | - (UIResponder*)nextResponderForKeyInput:(EJKeyInputResponder*)keyInput; 9 | @optional 10 | - (void)keyInput:(EJKeyInputResponder*)keyInput insertText:(NSString*)text; 11 | - (void)keyInputDidDeleteBackwards:(EJKeyInputResponder*)keyInput; 12 | - (void)keyInputDidResignFirstResponderStatus:(EJKeyInputResponder*)keyInput; 13 | - (void)keyInputDidBecomeFirstResponder:(EJKeyInputResponder*)keyInput; 14 | - (BOOL)hasText; 15 | @end 16 | 17 | @interface EJKeyInputResponder : UIResponder 18 | @property (nonatomic, unsafe_unretained) NSObject *delegate; 19 | @end 20 | 21 | #pragma mark - 22 | #pragma mark EJBindingKeyInput 23 | 24 | @interface EJBindingKeyInput : EJBindingEventedBase 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingKeyInput.m: -------------------------------------------------------------------------------- 1 | 2 | #import "EJBindingKeyInput.h" 3 | #import "EJJavaScriptView.h" 4 | 5 | @implementation EJKeyInputResponder 6 | 7 | - (UIResponder*)nextResponder{ 8 | return [self.delegate nextResponderForKeyInput:self]; 9 | } 10 | 11 | - (BOOL)becomeFirstResponder{ 12 | BOOL isCurrent = [self isFirstResponder]; 13 | BOOL become = [super becomeFirstResponder]; 14 | if (become && !isCurrent && [self.delegate respondsToSelector:@selector(keyInputDidBecomeFirstResponder:)]) { 15 | [self.delegate keyInputDidBecomeFirstResponder:self]; 16 | } 17 | return become; 18 | } 19 | 20 | - (BOOL)canBecomeFirstResponder{ 21 | return YES; 22 | } 23 | 24 | - (BOOL)resignFirstResponder{ 25 | BOOL isCurrent = [self isFirstResponder]; 26 | BOOL resign = [super resignFirstResponder]; 27 | if (resign && isCurrent && [self.delegate respondsToSelector:@selector(keyInputDidResignFirstResponderStatus:)]) { 28 | [self.delegate keyInputDidResignFirstResponderStatus:self]; 29 | } 30 | return resign; 31 | } 32 | 33 | - (void)deleteBackward{ 34 | if (self.delegate && [self.delegate respondsToSelector:@selector(keyInputDidDeleteBackwards:)]) { 35 | [self.delegate keyInputDidDeleteBackwards:self]; 36 | } 37 | } 38 | 39 | - (void)insertText:(NSString *)text{ 40 | if ([self.delegate respondsToSelector:@selector(keyInput:insertText:)]) { 41 | [self.delegate keyInput:self insertText:text]; 42 | } 43 | } 44 | 45 | - (BOOL)hasText{ 46 | return self.delegate.hasText; 47 | } 48 | 49 | @end 50 | 51 | @interface EJBindingKeyInput () 52 | @property (nonatomic, retain) EJKeyInputResponder *inputController; 53 | @property (nonatomic, retain) NSMutableString *value; 54 | @end 55 | 56 | @implementation EJBindingKeyInput 57 | 58 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 59 | [super createWithJSObject:obj scriptView:view]; 60 | self.inputController = [[[EJKeyInputResponder alloc] init] autorelease]; 61 | self.inputController.delegate = self; 62 | self.value = [NSMutableString string]; 63 | } 64 | 65 | - (void)dealloc 66 | { 67 | self.inputController.delegate = nil; 68 | [_inputController release]; 69 | [_value release]; 70 | [super dealloc]; 71 | } 72 | 73 | EJ_BIND_FUNCTION(focus, ctx, argc, argv){ 74 | return JSValueMakeBoolean(ctx, [self.inputController becomeFirstResponder]); 75 | } 76 | 77 | EJ_BIND_FUNCTION(blur, ctx, argc, argv){ 78 | return JSValueMakeBoolean(ctx, [self.inputController resignFirstResponder]); 79 | } 80 | 81 | EJ_BIND_FUNCTION(isOpen, ctx, argc, argv){ 82 | return JSValueMakeBoolean(ctx, [self.inputController isFirstResponder]); 83 | } 84 | 85 | EJ_BIND_GET(value, ctx){ 86 | return NSStringToJSValue(ctx, self.value); 87 | } 88 | 89 | EJ_BIND_SET(value, ctx, value){ 90 | [self.value setString:JSValueToNSString(ctx, value)]; 91 | } 92 | 93 | EJ_BIND_EVENT(focus); 94 | EJ_BIND_EVENT(blur); 95 | EJ_BIND_EVENT(delete); 96 | EJ_BIND_EVENT(change); 97 | 98 | #pragma mark - 99 | #pragma mark EJKeyInput delegate 100 | 101 | - (UIResponder*)nextResponderForKeyInput:(EJKeyInputResponder *)keyInput{ 102 | return scriptView; 103 | } 104 | 105 | - (void)keyInput:(EJKeyInputResponder *)keyInput insertText:(NSString *)text 106 | { 107 | [self.value appendString:text]; 108 | 109 | [self triggerEvent:@"keypress" properties:(JSEventProperty[]){ 110 | {"char", NSStringToJSValue(scriptView.jsGlobalContext, text)}, 111 | {NULL, NULL} 112 | }]; 113 | 114 | [self triggerEvent:@"change"]; 115 | } 116 | 117 | - (void)keyInputDidDeleteBackwards:(EJKeyInputResponder *)keyInput{ 118 | if( !self.hasText ) { 119 | return; 120 | } 121 | [self.value deleteCharactersInRange:NSMakeRange(self.value.length-1,1)]; 122 | [self triggerEvent:@"change"]; 123 | [self triggerEvent:@"delete"]; 124 | } 125 | 126 | - (void)keyInputDidResignFirstResponderStatus:(EJKeyInputResponder *)keyInput{ 127 | [self triggerEvent:@"blur"]; 128 | } 129 | 130 | - (void)keyInputDidBecomeFirstResponder:(EJKeyInputResponder *)keyInput{ 131 | [self triggerEvent:@"focus"]; 132 | } 133 | 134 | - (BOOL)hasText { 135 | return self.value.length > 0; 136 | } 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingLocalStorage.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingBase.h" 3 | 4 | 5 | @interface EJBindingLocalStorage : EJBindingBase { 6 | } 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingLocalStorage.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingLocalStorage.h" 2 | 3 | 4 | @implementation EJBindingLocalStorage 5 | 6 | EJ_BIND_FUNCTION(getItem, ctx, argc, argv) { 7 | if( argc < 1 ) { return NULL; } 8 | 9 | NSString *key = JSValueToNSString( ctx, argv[0] ); 10 | NSString *value = [NSUserDefaults.standardUserDefaults stringForKey:key]; 11 | return value ? NSStringToJSValue( ctx, value ) : JSValueMakeNull(ctx); 12 | } 13 | 14 | EJ_BIND_FUNCTION(setItem, ctx, argc, argv) { 15 | if( argc < 2 ) { return NULL; } 16 | 17 | NSString *key = JSValueToNSString( ctx, argv[0] ); 18 | NSString *value = JSValueToNSString( ctx, argv[1] ); 19 | 20 | if( !key || !value ) { return NULL; } 21 | [NSUserDefaults.standardUserDefaults setObject:value forKey:key]; 22 | [NSUserDefaults.standardUserDefaults synchronize]; 23 | 24 | return NULL; 25 | } 26 | 27 | EJ_BIND_FUNCTION(removeItem, ctx, argc, argv) { 28 | if( argc < 1 ) { return NULL; } 29 | 30 | NSString *key = JSValueToNSString( ctx, argv[0] ); 31 | [NSUserDefaults.standardUserDefaults removeObjectForKey:key]; 32 | 33 | return NULL; 34 | } 35 | 36 | EJ_BIND_FUNCTION(clear, ctx, argc, argv) { 37 | [NSUserDefaults.standardUserDefaults removePersistentDomainForName:NSBundle.mainBundle.bundleIdentifier]; 38 | return NULL; 39 | } 40 | 41 | EJ_BIND_FUNCTION(key, ctx, argc, argv) { 42 | if( argc < 1 ) { return NULL; } 43 | 44 | int index = JSValueToNumberFast(ctx, argv[0]); 45 | 46 | // TODO: cache this maybe? 47 | NSDictionary *keys = [NSUserDefaults.standardUserDefaults persistentDomainForName:NSBundle.mainBundle.bundleIdentifier]; 48 | NSString *key = keys.allKeys[index]; 49 | return key ? NSStringToJSValue(ctx, key) : NULL; 50 | } 51 | 52 | EJ_BIND_GET(length, ctx) { 53 | // TODO: cache this maybe? 54 | NSDictionary *keys = [NSUserDefaults.standardUserDefaults persistentDomainForName:NSBundle.mainBundle.bundleIdentifier]; 55 | return JSValueMakeNumber(ctx, keys.count); 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingTouchInput.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | #import "EJJavaScriptView.h" 4 | 5 | #define EJ_TOUCH_INPUT_MAX_TOUCHES 16 6 | 7 | @interface EJBindingTouchInput : EJBindingEventedBase { 8 | JSStringRef jsLengthName; 9 | JSStringRef jsTargetName, jsIdentifierName, jsPageXName, jsPageYName, jsClientXName, jsClientYName; 10 | JSObjectRef jsRemainingTouches, jsChangedTouches; 11 | JSObjectRef jsTouchesPool[EJ_TOUCH_INPUT_MAX_TOUCHES]; 12 | JSValueRef jsTouchTarget; 13 | NSUInteger touchesInPool; 14 | } 15 | 16 | - (void)triggerEvent:(NSString *)name all:(NSSet *)all changed:(NSSet *)changed remaining:(NSSet *)remaining; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingWebSocket.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingEventedBase.h" 2 | #import "SRWebSocket.h" 3 | 4 | typedef enum { 5 | kEJWebSocketBinaryTypeBlob, 6 | kEJWebSocketBinaryTypeArrayBuffer 7 | } EJWebSocketBinaryType; 8 | 9 | typedef enum { 10 | kEJWebSocketReadyStateConnecting = 0, 11 | kEJWebSocketReadyStateOpen = 1, 12 | kEJWebSocketReadyStateClosing = 2, 13 | kEJWebSocketReadyStateClosed = 3 14 | } EJWebSocketReadyState; 15 | 16 | @interface EJBindingWebSocket : EJBindingEventedBase { 17 | EJWebSocketBinaryType binaryType; 18 | EJWebSocketReadyState readyState; 19 | NSString *url; 20 | SRWebSocket *socket; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingWindowEvents.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingEventedBase.h" 2 | #import "EJJavaScriptView.h" 3 | 4 | @interface EJBindingWindowEvents : EJBindingEventedBase 5 | 6 | - (void)pause; 7 | - (void)resume; 8 | - (void)resize; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/EJBindingWindowEvents.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingWindowEvents.h" 2 | #import "EJJavaScriptView.h" 3 | 4 | @implementation EJBindingWindowEvents 5 | 6 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 7 | [super createWithJSObject:obj scriptView:view]; 8 | scriptView.windowEventsDelegate = self; 9 | } 10 | 11 | - (void)pause { 12 | [self triggerEvent:@"pagehide"]; 13 | } 14 | 15 | - (void)resume { 16 | [self triggerEvent:@"pageshow"]; 17 | } 18 | 19 | - (void)resize { 20 | [self triggerEvent:@"resize"]; 21 | } 22 | 23 | EJ_BIND_EVENT(pagehide); 24 | EJ_BIND_EVENT(pageshow); 25 | EJ_BIND_EVENT(resize); 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/Gamepad/EJBindingGamepad.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | 4 | // Button Mappings according to http://www.w3.org/TR/gamepad/#remapping 5 | typedef enum { 6 | kEJGamepadButtonA = 0, 7 | kEJGamepadButtonB = 1, 8 | kEJGamepadButtonX = 2, 9 | kEJGamepadButtonY = 3, 10 | kEJGamepadButtonL1 = 4, 11 | kEJGamepadButtonR1 = 5, 12 | kEJGamepadButtonL2 = 6, 13 | kEJGamepadButtonR2 = 7, 14 | kEJGamepadButtonSelect = 8, 15 | kEJGamepadButtonStart = 9, 16 | kEJGamepadButtonLeftStick = 10, 17 | kEJGamepadButtonRightStick = 11, 18 | kEJGamepadButtonUp = 12, 19 | kEJGamepadButtonDown = 13, 20 | kEJGamepadButtonLeft = 14, 21 | kEJGamepadButtonRight = 15, 22 | kEJGamepadButtonHome = 16, 23 | kEJGamepadNumButtons 24 | } kEJGamepadButtonMapping; 25 | 26 | 27 | @interface EJBindingGamepad : EJBindingBase { 28 | GCController *controller; 29 | 30 | NSTimeInterval baseTime; 31 | NSUInteger index; 32 | BOOL connected; 33 | 34 | JSObjectRef jsAxes; 35 | JSObjectRef jsButtons; 36 | } 37 | 38 | - (id)initWithController:(GCController *)controller atIndex:(NSUInteger)index; 39 | - (void)disconnect; 40 | 41 | @property (readonly) JSObjectRef jsObject; 42 | @property (readonly) GCController *controller; 43 | 44 | @end 45 | 46 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/Gamepad/EJBindingGamepadButton.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | 4 | // We need a seperate GCControllerButtonInput that handles the Home button via the 5 | // the controllerPausedHandler callback, but we don't want to subclass 6 | // GCControllerButtonInput. 7 | 8 | // The EJControllerButtonInputProtocol defines the two properties we're interested 9 | // in for a ButtonInput. GCControllerButtonInput already conforms to this, so we 10 | // create a category on it, in order to let the compiler know of that fact. 11 | 12 | // We can also use this protocol to create our own EJControllerButtonInputHome 13 | // class. EJBindingGamepadButton then simply accepts any NSObject that conforms 14 | // to the protocol -> either the stock GCControllerButtonInput or our own 15 | // EJControllerButtonInputHome. 16 | 17 | 18 | // The Protocl GCControllerButtonInput and our own ButtonInput class conform to 19 | @protocol EJControllerButtonInputProtocol 20 | @property (nonatomic, readonly) float value; 21 | @property (nonatomic, readonly, getter = isPressed) BOOL pressed; 22 | @end 23 | 24 | 25 | // Empty category with EJControllerButtonInputProtocol, so the compiler knows 26 | // GCControllerButtonInput conforms to it. 27 | @interface GCControllerButtonInput (GCControllerButtonInputWithEJProtocol) 28 | @end 29 | 30 | 31 | // Home Button that conforms to the EJControllerButtonInputProtocol 32 | @interface EJControllerButtonInputHome : NSObject { 33 | GCController *controller; 34 | NSTimeInterval lastPressed; 35 | } 36 | - (id)initWithController:(GCController *)controller; 37 | @property (nonatomic, readonly) float value; 38 | @property (nonatomic, readonly, getter = isPressed) BOOL pressed; 39 | @end 40 | 41 | 42 | // The Binding Class for a button, exposed to JS 43 | @interface EJBindingGamepadButton : EJBindingBase { 44 | NSObject *button; 45 | } 46 | 47 | - (id)initWithButton:(NSObject *)button; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/Gamepad/EJBindingGamepadButton.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingGamepadButton.h" 2 | 3 | 4 | @implementation EJControllerButtonInputHome 5 | 6 | - (id)initWithController:(GCController *)controllerp { 7 | if( self = [super init] ) { 8 | controller = [controllerp retain]; 9 | controller.controllerPausedHandler = ^(GCController *controller) { 10 | lastPressed = NSDate.timeIntervalSinceReferenceDate; 11 | }; 12 | } 13 | return self; 14 | } 15 | 16 | - (void)dealloc { 17 | controller.controllerPausedHandler = nil; 18 | [controller release]; 19 | [super dealloc]; 20 | } 21 | 22 | - (BOOL)isPressed { 23 | // If the last press happened not longer than 250ms ago, we consider 24 | // the button to be pressed. Yeah, it's a cheap hack :/ 25 | return (NSDate.timeIntervalSinceReferenceDate - lastPressed) < 0.25; 26 | } 27 | 28 | - (float)value { 29 | return self.isPressed ? 1.0 : 0.0; 30 | } 31 | 32 | @end 33 | 34 | 35 | 36 | @implementation EJBindingGamepadButton 37 | 38 | - (id)initWithButton:(NSObject *)buttonp { 39 | if( self = [super initWithContext:NULL argc:0 argv:NULL] ) { 40 | button = [buttonp retain]; 41 | } 42 | return self; 43 | } 44 | 45 | -(void)dealloc { 46 | [button release]; 47 | [super dealloc]; 48 | } 49 | 50 | EJ_BIND_GET(pressed, ctx) { 51 | return JSValueMakeBoolean(ctx, button.pressed); 52 | } 53 | 54 | EJ_BIND_GET(value, ctx) { 55 | return JSValueMakeNumber(ctx, button.value); 56 | } 57 | 58 | @end 59 | 60 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/Gamepad/EJBindingGamepadProvider.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "EJBindingEventedBase.h" 3 | 4 | #define EJ_GAMEPAD_NUM_DEVICES 4 5 | 6 | @interface EJBindingGamepadProvider : EJBindingEventedBase { 7 | NSMutableArray *gamepadBindings; 8 | } 9 | @end 10 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/Gamepad/EJBindingGamepadProvider.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingGamepadProvider.h" 2 | #import "EJBindingGamepad.h" 3 | 4 | @implementation EJBindingGamepadProvider 5 | 6 | - (void)createWithJSObject:(JSObjectRef)obj scriptView:(EJJavaScriptView *)view { 7 | [super createWithJSObject:obj scriptView:view]; 8 | 9 | // Create the gamepadBindings array, fill it with available gamepads 10 | gamepadBindings = [[NSMutableArray alloc] initWithCapacity:EJ_GAMEPAD_NUM_DEVICES]; 11 | int maxIndex = 0; 12 | for( GCController *controller in GCController.controllers ) { 13 | EJBindingGamepad *binding = [[EJBindingGamepad alloc] initWithController:controller atIndex:maxIndex]; 14 | [EJBindingGamepad createJSObjectWithContext:scriptView.jsGlobalContext scriptView:scriptView instance:binding]; 15 | [gamepadBindings addObject:binding]; 16 | [binding release]; 17 | maxIndex++; 18 | } 19 | 20 | // Fill up the remaining slots with NSNull 21 | for( int i = maxIndex; i < EJ_GAMEPAD_NUM_DEVICES; i++ ) { 22 | [gamepadBindings addObject:NSNull.null]; 23 | } 24 | 25 | [NSNotificationCenter.defaultCenter 26 | addObserver:self selector:@selector(gameControllerDidConnect:) 27 | name:GCControllerDidConnectNotification object:nil]; 28 | 29 | [NSNotificationCenter.defaultCenter 30 | addObserver:self selector:@selector(gameControllerDidDisconnect:) 31 | name:GCControllerDidDisconnectNotification object:nil]; 32 | } 33 | 34 | - (void)dealloc { 35 | [NSNotificationCenter.defaultCenter removeObserver:self]; 36 | 37 | [gamepadBindings release]; 38 | [super dealloc]; 39 | } 40 | 41 | 42 | - (void)gameControllerDidConnect:(NSNotification *)notification { 43 | GCController *controller = (GCController *)notification.object; 44 | 45 | // Do we already have this controller for whatever reason? 46 | for( EJBindingGamepad *binding in gamepadBindings ) { 47 | if( (id)binding != NSNull.null && binding.controller == controller ) { 48 | return; 49 | } 50 | } 51 | 52 | // Find the first free index 53 | NSUInteger index = [gamepadBindings indexOfObject:NSNull.null]; 54 | if( index == NSNotFound ) { 55 | index = gamepadBindings.count; 56 | } 57 | 58 | if( index >= EJ_GAMEPAD_NUM_DEVICES ) { 59 | return; 60 | } 61 | 62 | // Create the Binding 63 | EJBindingGamepad *binding = [[EJBindingGamepad alloc] initWithController:controller atIndex:index]; 64 | [EJBindingGamepad createJSObjectWithContext:scriptView.jsGlobalContext scriptView:scriptView instance:binding]; 65 | [gamepadBindings setObject:binding atIndexedSubscript:index]; 66 | 67 | [self triggerEvent:@"gamepadconnected" properties:(JSEventProperty[]){ 68 | {"gamepad", binding.jsObject}, 69 | {NULL, NULL}, 70 | }]; 71 | 72 | [binding release]; 73 | } 74 | 75 | - (void)gameControllerDidDisconnect:(NSNotification *)notification { 76 | GCController *controller = (GCController *)notification.object; 77 | 78 | // Find the binding for the controller that was disconnected 79 | EJBindingGamepad *disconnectedBinding = nil; 80 | NSUInteger index = 0; 81 | for( EJBindingGamepad *binding in gamepadBindings ) { 82 | if( (id)binding != NSNull.null && binding.controller == controller ) { 83 | disconnectedBinding = binding; 84 | break; 85 | } 86 | index++; 87 | } 88 | 89 | if( disconnectedBinding ) { 90 | [self triggerEvent:@"gamepaddisconnected" properties:(JSEventProperty[]){ 91 | {"gamepad", disconnectedBinding.jsObject}, 92 | {NULL, NULL}, 93 | }]; 94 | [disconnectedBinding disconnect]; 95 | } 96 | 97 | // Replace the binding with NSNull 98 | [gamepadBindings setObject:NSNull.null atIndexedSubscript:index]; 99 | } 100 | 101 | EJ_BIND_FUNCTION(getGamepads, ctx, argc, argv) { 102 | JSValueRef args[EJ_GAMEPAD_NUM_DEVICES]; 103 | for( int i = 0; i < EJ_GAMEPAD_NUM_DEVICES; i++ ) { 104 | EJBindingGamepad *binding = gamepadBindings[i]; 105 | args[i] = (id)binding == NSNull.null 106 | ? scriptView->jsUndefined 107 | : binding.jsObject; 108 | } 109 | return JSObjectMakeArray(ctx, EJ_GAMEPAD_NUM_DEVICES, args, NULL); 110 | } 111 | 112 | EJ_BIND_EVENT(gamepadconnected); 113 | EJ_BIND_EVENT(gamepaddisconnected); 114 | 115 | @end 116 | 117 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/IAP/EJBindingIAPManager.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import 3 | 4 | @interface EJBindingIAPManager : EJBindingBase { 5 | NSMutableDictionary *productRequestCallbacks; 6 | NSMutableDictionary *products; 7 | 8 | JSObjectRef restoreCallback; 9 | NSMutableArray *restoredTransactions; 10 | } 11 | @end 12 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/IAP/EJBindingIAPProduct.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import 3 | 4 | @interface EJBindingIAPProduct : EJBindingBase { 5 | SKProduct *product; 6 | JSObjectRef callback; 7 | } 8 | 9 | - (id)initWithProduct:(SKProduct *)product; 10 | - (void)finishPurchaseWithTransaction:(SKPaymentTransaction *)transaction; 11 | 12 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 13 | scriptView:(EJJavaScriptView *)view 14 | product:(SKProduct *)product; 15 | 16 | + (EJBindingIAPProduct *)bindingFromJSValue:(JSValueRef)value; 17 | 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/IAP/EJBindingIAPProduct.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingIAPProduct.h" 2 | #import "EJBindingIAPTransaction.h" 3 | 4 | @implementation EJBindingIAPProduct 5 | 6 | - (id)initWithProduct:(SKProduct *)productp { 7 | if( self = [super initWithContext:NULL argc:0 argv:NULL] ) { 8 | product = [productp retain]; 9 | } 10 | return self; 11 | } 12 | 13 | - (void)dealloc { 14 | [product release]; 15 | [super dealloc]; 16 | } 17 | 18 | - (void)finishPurchaseWithTransaction:(SKPaymentTransaction *)transaction { 19 | if( !callback ) { 20 | NSLog(@"IAP Error: Payment finished but no callback. This shouldn't happen."); 21 | return; 22 | } 23 | 24 | JSGlobalContextRef ctx = scriptView.jsGlobalContext; 25 | 26 | // Construct the error value and transaction binding for the callback 27 | JSValueRef jsError = (transaction.transactionState == SKPaymentTransactionStateFailed) 28 | ? NSStringToJSValue(ctx, transaction.error ? transaction.error.localizedDescription : @"Unknown Error") 29 | : JSValueMakeNull(ctx); 30 | 31 | JSValueRef jsTransaction = [EJBindingIAPTransaction 32 | createJSObjectWithContext:ctx scriptView:scriptView transaction:transaction]; 33 | 34 | [scriptView invokeCallback:callback thisObject:jsObject 35 | argc:2 argv:(JSValueRef[]){jsError, jsTransaction}]; 36 | 37 | 38 | JSValueUnprotect(scriptView.jsGlobalContext, callback); 39 | JSValueUnprotect(scriptView.jsGlobalContext, jsObject); 40 | callback = NULL; 41 | } 42 | 43 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 44 | scriptView:(EJJavaScriptView *)view 45 | product:(SKProduct *)product 46 | { 47 | id native = [[self alloc] initWithProduct:product]; 48 | 49 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:native]; 50 | [native release]; 51 | return obj; 52 | } 53 | 54 | + (EJBindingIAPProduct *)bindingFromJSValue:(JSValueRef)value { 55 | if( !value ) { return 0; } 56 | 57 | EJBindingIAPProduct *binding = (EJBindingIAPProduct *)JSValueGetPrivate(value); 58 | return (binding && [binding isKindOfClass:[self class]]) ? binding : NULL; 59 | } 60 | 61 | EJ_BIND_GET(id, ctx) { 62 | return NSStringToJSValue(ctx, product.productIdentifier); 63 | } 64 | 65 | EJ_BIND_GET(title, ctx) { 66 | return NSStringToJSValue(ctx, product.localizedTitle); 67 | } 68 | 69 | EJ_BIND_GET(description, ctx) { 70 | return NSStringToJSValue(ctx, product.localizedDescription); 71 | } 72 | 73 | EJ_BIND_GET(price, ctx) { 74 | NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 75 | [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 76 | [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 77 | [numberFormatter setLocale:product.priceLocale]; 78 | NSString *localizedPrice = [numberFormatter stringFromNumber:product.price]; 79 | [numberFormatter release]; 80 | 81 | return NSStringToJSValue(ctx, localizedPrice); 82 | } 83 | 84 | EJ_BIND_FUNCTION(purchase, ctx, argc, argv) { 85 | if( argc < 2 || !JSValueIsObject(ctx, argv[1]) ) { return NULL; } 86 | 87 | if( callback ) { 88 | NSLog( 89 | @"IAP Error: Can't make purchase for %@ while another purchase for the " 90 | @"same product is still running", 91 | product.productIdentifier 92 | ); 93 | return NULL; 94 | } 95 | 96 | int quantity = JSValueToNumberFast(ctx, argv[0]); 97 | 98 | NSLog(@"IAP: Purchase %@ x %d", product.productIdentifier, quantity); 99 | 100 | SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product]; 101 | payment.quantity = quantity; 102 | [[SKPaymentQueue defaultQueue] addPayment:payment]; 103 | 104 | callback = JSValueToObject(ctx, argv[1], NULL); 105 | JSValueProtect(ctx, callback); 106 | JSValueProtect(ctx, jsObject); 107 | return NULL; 108 | } 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/IAP/EJBindingIAPTransaction.h: -------------------------------------------------------------------------------- 1 | #import "EJBindingBase.h" 2 | #import 3 | 4 | @interface EJBindingIAPTransaction : EJBindingBase { 5 | SKPaymentTransaction *transaction; 6 | } 7 | 8 | - (id)initWithTransaction:(SKPaymentTransaction *)transaction; 9 | 10 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 11 | scriptView:(EJJavaScriptView *)view 12 | transaction:(SKPaymentTransaction *)transaction; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Source/Ejecta/EJUtils/IAP/EJBindingIAPTransaction.m: -------------------------------------------------------------------------------- 1 | #import "EJBindingIAPTransaction.h" 2 | 3 | @implementation EJBindingIAPTransaction 4 | 5 | - (id)initWithTransaction:(SKPaymentTransaction *)transactionp { 6 | if( self = [super initWithContext:NULL argc:0 argv:NULL] ) { 7 | transaction = [transactionp retain]; 8 | } 9 | return self; 10 | } 11 | 12 | - (void)dealloc { 13 | [transaction release]; 14 | [super dealloc]; 15 | } 16 | 17 | + (JSObjectRef)createJSObjectWithContext:(JSContextRef)ctx 18 | scriptView:(EJJavaScriptView *)view 19 | transaction:(SKPaymentTransaction *)transaction 20 | { 21 | id native = [[self alloc] initWithTransaction:transaction]; 22 | 23 | JSObjectRef obj = [self createJSObjectWithContext:ctx scriptView:view instance:native]; 24 | [native release]; 25 | return obj; 26 | } 27 | 28 | EJ_BIND_GET(id, ctx) { 29 | return NSStringToJSValue(ctx, transaction.transactionIdentifier); 30 | } 31 | 32 | EJ_BIND_GET(productId, ctx) { 33 | return NSStringToJSValue(ctx, transaction.payment.productIdentifier); 34 | } 35 | 36 | EJ_BIND_GET(receipt, ctx) { 37 | NSData *receipt = [NSData dataWithContentsOfURL:NSBundle.mainBundle.appStoreReceiptURL]; 38 | if( !receipt ) { 39 | return NULL; 40 | } 41 | return NSStringToJSValue(ctx, [receipt base64EncodedStringWithOptions:0]); 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Source/Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Ejecta' target in the 'Ejecta' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Source/lib/SocketRocket/SocketRocket-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2012 Square Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #ifdef __OBJC__ 22 | #import 23 | #endif 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/JavaScriptCore: -------------------------------------------------------------------------------- 1 | Versions/Current/JavaScriptCore -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JSManagedValue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 | * THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JSManagedValue_h 27 | #define JSManagedValue_h 28 | 29 | #import 30 | 31 | #if JSC_OBJC_API_ENABLED 32 | 33 | @class JSValue; 34 | @class JSContext; 35 | 36 | /*! 37 | @interface 38 | @discussion JSManagedValue represents a "conditionally retained" JSValue. 39 | "Conditionally retained" means that as long as either the JSManagedValue's 40 | JavaScript value is reachable through the JavaScript object graph 41 | or the JSManagedValue object is reachable through the external Objective-C 42 | object graph as reported to the JSVirtualMachine using 43 | addManagedReference:withOwner:, the corresponding JavaScript value will 44 | be retained. However, if neither of these conditions are true, the 45 | corresponding JSValue will be released and set to nil. 46 | 47 | The primary use case for JSManagedValue is for safely referencing JSValues 48 | from the Objective-C heap. It is incorrect to store a JSValue into an 49 | Objective-C heap object, as this can very easily create a reference cycle, 50 | keeping the entire JSContext alive. 51 | */ 52 | NS_CLASS_AVAILABLE(10_9, 7_0) 53 | @interface JSManagedValue : NSObject 54 | 55 | /*! 56 | @method 57 | @abstract Create a JSManagedValue from a JSValue. 58 | @param value 59 | @result The new JSManagedValue. 60 | */ 61 | + (JSManagedValue *)managedValueWithValue:(JSValue *)value; 62 | 63 | /*! 64 | @method 65 | @abstract Create a JSManagedValue. 66 | @param value 67 | @result The new JSManagedValue. 68 | */ 69 | - (instancetype)initWithValue:(JSValue *)value; 70 | 71 | /*! 72 | @property 73 | @abstract Get the JSValue from the JSManagedValue. 74 | @result The corresponding JSValue for this JSManagedValue or 75 | nil if the JSValue has been collected. 76 | */ 77 | @property (readonly, strong) JSValue *value; 78 | 79 | @end 80 | 81 | #endif // JSC_OBJC_API_ENABLED 82 | 83 | #endif // JSManagedValue_h 84 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JSStringRefCF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JSStringRefCF_h 27 | #define JSStringRefCF_h 28 | 29 | #include "JSBase.h" 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /* CFString convenience methods */ 37 | 38 | /*! 39 | @function 40 | @abstract Creates a JavaScript string from a CFString. 41 | @discussion This function is optimized to take advantage of cases when 42 | CFStringGetCharactersPtr returns a valid pointer. 43 | @param string The CFString to copy into the new JSString. 44 | @result A JSString containing string. Ownership follows the Create Rule. 45 | */ 46 | JS_EXPORT JSStringRef JSStringCreateWithCFString(CFStringRef string); 47 | /*! 48 | @function 49 | @abstract Creates a CFString from a JavaScript string. 50 | @param alloc The alloc parameter to pass to CFStringCreate. 51 | @param string The JSString to copy into the new CFString. 52 | @result A CFString containing string. Ownership follows the Create Rule. 53 | */ 54 | JS_EXPORT CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string) CF_RETURNS_RETAINED; 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* JSStringRefCF_h */ 61 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JSTypedArray.h: -------------------------------------------------------------------------------- 1 | #ifndef JSTypedArray_h 2 | #define JSTypedArray_h 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /*! 11 | @enum JSType 12 | @abstract A constant identifying the Typed Array type of a JSValue. 13 | @constant kJSTypedArrayTypeNone Not a Typed Array. 14 | @constant kJSTypedArrayTypeInt8Array Int8Array 15 | @constant kJSTypedArrayTypeInt16Array Int16Array 16 | @constant kJSTypedArrayTypeInt32Array Int32Array 17 | @constant kJSTypedArrayTypeUint8Array Int8Array 18 | @constant kJSTypedArrayTypeUint8ClampedArray Int8ClampedArray 19 | @constant kJSTypedArrayTypeUint16Array Uint16Array 20 | @constant kJSTypedArrayTypeUint32Array Uint32Array 21 | @constant kJSTypedArrayTypeFloat32Array Float32Array 22 | @constant kJSTypedArrayTypeFloat64Array Float64Array 23 | @constant kJSTypedArrayTypeArrayBuffer ArrayBuffer 24 | */ 25 | typedef enum { 26 | kJSTypedArrayTypeNone, 27 | kJSTypedArrayTypeInt8Array, 28 | kJSTypedArrayTypeInt16Array, 29 | kJSTypedArrayTypeInt32Array, 30 | kJSTypedArrayTypeUint8Array, 31 | kJSTypedArrayTypeUint8ClampedArray, 32 | kJSTypedArrayTypeUint16Array, 33 | kJSTypedArrayTypeUint32Array, 34 | kJSTypedArrayTypeFloat32Array, 35 | kJSTypedArrayTypeFloat64Array, 36 | kJSTypedArrayTypeArrayBuffer 37 | } JSTypedArrayType; 38 | 39 | /*! 40 | @function 41 | @abstract Returns a JavaScript value's Typed Array type 42 | @param ctx The execution context to use. 43 | @param value The JSValue whose Typed Array type you want to obtain. 44 | @result A value of type JSTypedArrayType that identifies value's Typed Array type. 45 | */ 46 | JS_EXPORT JSTypedArrayType JSObjectGetTypedArrayType(JSContextRef ctx, JSObjectRef object); 47 | 48 | /*! 49 | @function 50 | @abstract Creates a JavaScript Typed Array with the given number of elements 51 | @param ctx The execution context to use. 52 | @param arrayType A value of type JSTypedArrayType identifying the type of array you want to create 53 | @param numElements The number of elements for the array. 54 | @result A JSObjectRef that is a Typed Array or NULL if there was an error 55 | */ 56 | JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t numElements); 57 | 58 | /*! 59 | @function 60 | @abstract Returns a pointer to a Typed Array's data in memory 61 | @param ctx The execution context to use. 62 | @param value The JSValue whose Typed Array type data pointer you want to obtain. 63 | @param byteLength A pointer to a size_t in which to store the byte length of the Typed Array 64 | @result A pointer to the Typed Array's data or NULL if the JSValue is not a Typed Array. 65 | */ 66 | JS_EXPORT void * JSObjectGetTypedArrayDataPtr(JSContextRef ctx, JSObjectRef object, size_t* byteLength); 67 | 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif /* JSTypedArray_h */ 74 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JSVirtualMachine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | 28 | #if JSC_OBJC_API_ENABLED 29 | 30 | /*! 31 | @interface 32 | @discussion An instance of JSVirtualMachine represents a single JavaScript "object space" 33 | or set of execution resources. Thread safety is supported by locking the 34 | virtual machine, with concurrent JavaScript execution supported by allocating 35 | separate instances of JSVirtualMachine. 36 | */ 37 | NS_CLASS_AVAILABLE(10_9, 7_0) 38 | @interface JSVirtualMachine : NSObject 39 | 40 | /*! 41 | @methodgroup Creating New Virtual Machines 42 | */ 43 | /*! 44 | @method 45 | @abstract Create a new JSVirtualMachine. 46 | */ 47 | - (instancetype)init; 48 | 49 | /*! 50 | @methodgroup Memory Management 51 | */ 52 | /*! 53 | @method 54 | @abstract Notify the JSVirtualMachine of an external object relationship. 55 | @discussion Allows clients of JSVirtualMachine to make the JavaScript runtime aware of 56 | arbitrary external Objective-C object graphs. The runtime can then use 57 | this information to retain any JavaScript values that are referenced 58 | from somewhere in said object graph. 59 | 60 | For correct behavior clients must make their external object graphs 61 | reachable from within the JavaScript runtime. If an Objective-C object is 62 | reachable from within the JavaScript runtime, all managed references 63 | transitively reachable from it as recorded using 64 | -addManagedReference:withOwner: will be scanned by the garbage collector. 65 | @param object The object that the owner points to. 66 | @param owner The object that owns the pointed to object. 67 | */ 68 | - (void)addManagedReference:(id)object withOwner:(id)owner; 69 | 70 | /*! 71 | @method 72 | @abstract Notify the JSVirtualMachine that a previous object relationship no longer exists. 73 | @discussion The JavaScript runtime will continue to scan any references that were 74 | reported to it by -addManagedReference:withOwner: until those references are removed. 75 | @param object The object that was formerly owned. 76 | @param owner The former owner. 77 | */ 78 | - (void)removeManagedReference:(id)object withOwner:(id)owner; 79 | 80 | @end 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JavaScript.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Apple Inc. All rights reserved. 3 | * Copyright (C) 2008 Alp Toker 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef JavaScript_h 28 | #define JavaScript_h 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #endif /* JavaScript_h */ 37 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/Headers/JavaScriptCore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JavaScriptCore_h 27 | #define JavaScriptCore_h 28 | 29 | #include 30 | #include 31 | 32 | #if defined(__OBJC__) && JSC_OBJC_API_ENABLED 33 | 34 | #import "JSContext.h" 35 | #import "JSValue.h" 36 | #import "JSManagedValue.h" 37 | #import "JSVirtualMachine.h" 38 | #import "JSExport.h" 39 | 40 | #endif 41 | 42 | #endif /* JavaScriptCore_h */ 43 | -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/A/JavaScriptCore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Source/lib/ios/JavaScriptCore.framework/Versions/A/JavaScriptCore -------------------------------------------------------------------------------- /Source/lib/ios/JavaScriptCore.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/JavaScriptCore: -------------------------------------------------------------------------------- 1 | Versions/Current/JavaScriptCore -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JSManagedValue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 | * THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JSManagedValue_h 27 | #define JSManagedValue_h 28 | 29 | #import 30 | 31 | #if JSC_OBJC_API_ENABLED 32 | 33 | @class JSValue; 34 | @class JSContext; 35 | 36 | /*! 37 | @interface 38 | @discussion JSManagedValue represents a "conditionally retained" JSValue. 39 | "Conditionally retained" means that as long as either the JSManagedValue's 40 | JavaScript value is reachable through the JavaScript object graph 41 | or the JSManagedValue object is reachable through the external Objective-C 42 | object graph as reported to the JSVirtualMachine using 43 | addManagedReference:withOwner:, the corresponding JavaScript value will 44 | be retained. However, if neither of these conditions are true, the 45 | corresponding JSValue will be released and set to nil. 46 | 47 | The primary use case for JSManagedValue is for safely referencing JSValues 48 | from the Objective-C heap. It is incorrect to store a JSValue into an 49 | Objective-C heap object, as this can very easily create a reference cycle, 50 | keeping the entire JSContext alive. 51 | */ 52 | NS_CLASS_AVAILABLE(10_9, 7_0) 53 | @interface JSManagedValue : NSObject 54 | 55 | /*! 56 | @method 57 | @abstract Create a JSManagedValue from a JSValue. 58 | @param value 59 | @result The new JSManagedValue. 60 | */ 61 | + (JSManagedValue *)managedValueWithValue:(JSValue *)value; 62 | 63 | /*! 64 | @method 65 | @abstract Create a JSManagedValue. 66 | @param value 67 | @result The new JSManagedValue. 68 | */ 69 | - (instancetype)initWithValue:(JSValue *)value; 70 | 71 | /*! 72 | @property 73 | @abstract Get the JSValue from the JSManagedValue. 74 | @result The corresponding JSValue for this JSManagedValue or 75 | nil if the JSValue has been collected. 76 | */ 77 | @property (readonly, strong) JSValue *value; 78 | 79 | @end 80 | 81 | #endif // JSC_OBJC_API_ENABLED 82 | 83 | #endif // JSManagedValue_h 84 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JSStringRefCF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JSStringRefCF_h 27 | #define JSStringRefCF_h 28 | 29 | #include "JSBase.h" 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /* CFString convenience methods */ 37 | 38 | /*! 39 | @function 40 | @abstract Creates a JavaScript string from a CFString. 41 | @discussion This function is optimized to take advantage of cases when 42 | CFStringGetCharactersPtr returns a valid pointer. 43 | @param string The CFString to copy into the new JSString. 44 | @result A JSString containing string. Ownership follows the Create Rule. 45 | */ 46 | JS_EXPORT JSStringRef JSStringCreateWithCFString(CFStringRef string); 47 | /*! 48 | @function 49 | @abstract Creates a CFString from a JavaScript string. 50 | @param alloc The alloc parameter to pass to CFStringCreate. 51 | @param string The JSString to copy into the new CFString. 52 | @result A CFString containing string. Ownership follows the Create Rule. 53 | */ 54 | JS_EXPORT CFStringRef JSStringCopyCFString(CFAllocatorRef alloc, JSStringRef string) CF_RETURNS_RETAINED; 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* JSStringRefCF_h */ 61 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JSTypedArray.h: -------------------------------------------------------------------------------- 1 | #ifndef JSTypedArray_h 2 | #define JSTypedArray_h 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /*! 11 | @enum JSType 12 | @abstract A constant identifying the Typed Array type of a JSValue. 13 | @constant kJSTypedArrayTypeNone Not a Typed Array. 14 | @constant kJSTypedArrayTypeInt8Array Int8Array 15 | @constant kJSTypedArrayTypeInt16Array Int16Array 16 | @constant kJSTypedArrayTypeInt32Array Int32Array 17 | @constant kJSTypedArrayTypeUint8Array Int8Array 18 | @constant kJSTypedArrayTypeUint8ClampedArray Int8ClampedArray 19 | @constant kJSTypedArrayTypeUint16Array Uint16Array 20 | @constant kJSTypedArrayTypeUint32Array Uint32Array 21 | @constant kJSTypedArrayTypeFloat32Array Float32Array 22 | @constant kJSTypedArrayTypeFloat64Array Float64Array 23 | @constant kJSTypedArrayTypeArrayBuffer ArrayBuffer 24 | */ 25 | typedef enum { 26 | kJSTypedArrayTypeNone, 27 | kJSTypedArrayTypeInt8Array, 28 | kJSTypedArrayTypeInt16Array, 29 | kJSTypedArrayTypeInt32Array, 30 | kJSTypedArrayTypeUint8Array, 31 | kJSTypedArrayTypeUint8ClampedArray, 32 | kJSTypedArrayTypeUint16Array, 33 | kJSTypedArrayTypeUint32Array, 34 | kJSTypedArrayTypeFloat32Array, 35 | kJSTypedArrayTypeFloat64Array, 36 | kJSTypedArrayTypeArrayBuffer 37 | } JSTypedArrayType; 38 | 39 | /*! 40 | @function 41 | @abstract Returns a JavaScript value's Typed Array type 42 | @param ctx The execution context to use. 43 | @param value The JSValue whose Typed Array type you want to obtain. 44 | @result A value of type JSTypedArrayType that identifies value's Typed Array type. 45 | */ 46 | JS_EXPORT JSTypedArrayType JSObjectGetTypedArrayType(JSContextRef ctx, JSObjectRef object); 47 | 48 | /*! 49 | @function 50 | @abstract Creates a JavaScript Typed Array with the given number of elements 51 | @param ctx The execution context to use. 52 | @param arrayType A value of type JSTypedArrayType identifying the type of array you want to create 53 | @param numElements The number of elements for the array. 54 | @result A JSObjectRef that is a Typed Array or NULL if there was an error 55 | */ 56 | JS_EXPORT JSObjectRef JSObjectMakeTypedArray(JSContextRef ctx, JSTypedArrayType arrayType, size_t numElements); 57 | 58 | /*! 59 | @function 60 | @abstract Returns a pointer to a Typed Array's data in memory 61 | @param ctx The execution context to use. 62 | @param value The JSValue whose Typed Array type data pointer you want to obtain. 63 | @param byteLength A pointer to a size_t in which to store the byte length of the Typed Array 64 | @result A pointer to the Typed Array's data or NULL if the JSValue is not a Typed Array. 65 | */ 66 | JS_EXPORT void * JSObjectGetTypedArrayDataPtr(JSContextRef ctx, JSObjectRef object, size_t* byteLength); 67 | 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif /* JSTypedArray_h */ 74 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JSVirtualMachine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | 28 | #if JSC_OBJC_API_ENABLED 29 | 30 | /*! 31 | @interface 32 | @discussion An instance of JSVirtualMachine represents a single JavaScript "object space" 33 | or set of execution resources. Thread safety is supported by locking the 34 | virtual machine, with concurrent JavaScript execution supported by allocating 35 | separate instances of JSVirtualMachine. 36 | */ 37 | NS_CLASS_AVAILABLE(10_9, 7_0) 38 | @interface JSVirtualMachine : NSObject 39 | 40 | /*! 41 | @methodgroup Creating New Virtual Machines 42 | */ 43 | /*! 44 | @method 45 | @abstract Create a new JSVirtualMachine. 46 | */ 47 | - (instancetype)init; 48 | 49 | /*! 50 | @methodgroup Memory Management 51 | */ 52 | /*! 53 | @method 54 | @abstract Notify the JSVirtualMachine of an external object relationship. 55 | @discussion Allows clients of JSVirtualMachine to make the JavaScript runtime aware of 56 | arbitrary external Objective-C object graphs. The runtime can then use 57 | this information to retain any JavaScript values that are referenced 58 | from somewhere in said object graph. 59 | 60 | For correct behavior clients must make their external object graphs 61 | reachable from within the JavaScript runtime. If an Objective-C object is 62 | reachable from within the JavaScript runtime, all managed references 63 | transitively reachable from it as recorded using 64 | -addManagedReference:withOwner: will be scanned by the garbage collector. 65 | @param object The object that the owner points to. 66 | @param owner The object that owns the pointed to object. 67 | */ 68 | - (void)addManagedReference:(id)object withOwner:(id)owner; 69 | 70 | /*! 71 | @method 72 | @abstract Notify the JSVirtualMachine that a previous object relationship no longer exists. 73 | @discussion The JavaScript runtime will continue to scan any references that were 74 | reported to it by -addManagedReference:withOwner: until those references are removed. 75 | @param object The object that was formerly owned. 76 | @param owner The former owner. 77 | */ 78 | - (void)removeManagedReference:(id)object withOwner:(id)owner; 79 | 80 | @end 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JavaScript.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 Apple Inc. All rights reserved. 3 | * Copyright (C) 2008 Alp Toker 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef JavaScript_h 28 | #define JavaScript_h 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #endif /* JavaScript_h */ 37 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/Headers/JavaScriptCore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef JavaScriptCore_h 27 | #define JavaScriptCore_h 28 | 29 | #include 30 | #include 31 | 32 | #if defined(__OBJC__) && JSC_OBJC_API_ENABLED 33 | 34 | #import "JSContext.h" 35 | #import "JSValue.h" 36 | #import "JSManagedValue.h" 37 | #import "JSVirtualMachine.h" 38 | #import "JSExport.h" 39 | 40 | #endif 41 | 42 | #endif /* JavaScriptCore_h */ 43 | -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/A/JavaScriptCore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/Source/lib/tvos/JavaScriptCore.framework/Versions/A/JavaScriptCore -------------------------------------------------------------------------------- /Source/lib/tvos/JavaScriptCore.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /Source/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppDelegate.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | @autoreleasepool { 6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass(AppDelegate.class)); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /hot-server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config.hot'); 4 | var path = require('path'); 5 | 6 | new WebpackDevServer(webpack(config), { 7 | contentBase: path.join(__dirname, 'web'), 8 | publicPath: config.output.publicPath, 9 | hot: true, 10 | historyApiFallback: true 11 | }).listen(3420, 'localhost', function (err, result) { 12 | if (err) { 13 | console.log(err); 14 | } 15 | 16 | console.log('Listening at localhost:3420'); 17 | }); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-three-ejecta-boilerplate", 3 | "version": "1.0.0", 4 | "description": "universal webgl app that compiles for web and native mobile", 5 | "main": "src", 6 | "scripts": { 7 | "build": "webpack", 8 | "watch": "webpack --watch", 9 | "build-prod": "NODE_ENV=production webpack -p", 10 | "build-prod-watch": "NODE_ENV=production webpack --watch -p", 11 | "build-web": "webpack --config webpack.config.web.js", 12 | "build-web-prod": "NODE_ENV=production webpack --config webpack.config.web.js -p", 13 | "start": "node server.js", 14 | "hot-web": "node hot-server.js", 15 | "build-gh-pages": "npm run build-web-prod && rm -rf ../react-three-ejecta-boilerplate-gh-pages/* && cp -rf web/* ../react-three-ejecta-boilerplate-gh-pages/ && npm run build-gh-pages-push", 16 | "build-gh-pages-push": "(cd ../react-three-ejecta-boilerplate-gh-pages/ && git add . && git commit -am 'build' && git push)", 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/gilbox/react-three-ejecta-boilerplate.git" 22 | }, 23 | "author": "", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/gilbox/react-three-ejecta-boilerplate/issues" 27 | }, 28 | "homepage": "https://github.com/gilbox/react-three-ejecta-boilerplate#readme", 29 | "dependencies": { 30 | "elegant-react": "^0.2.2", 31 | "es6-shim": "^0.33.10", 32 | "functional-easing": "^1.0.8", 33 | "lodash.compose": "^2.4.1", 34 | "react": "^0.14.0", 35 | "react-derive": "^0.1.1", 36 | "react-dom": "^0.14.0", 37 | "react-imation": "^0.2.8", 38 | "react-stateful-stream": "^0.3.0", 39 | "react-three": "0.7.1", 40 | "three": "^0.72.0", 41 | "updeep": "^0.10.1" 42 | }, 43 | "devDependencies": { 44 | "babel-core": "^5.8.25", 45 | "babel-loader": "^5.3.2", 46 | "babel-eslint": "^4.1.4", 47 | "eslint": "^1.9.0", 48 | "eslint-plugin-react": "^3.8.0", 49 | "lodash": "^3.10.1", 50 | "webpack": "^1.12.2", 51 | "webpack-dev-server": "^1.12.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config.web-dev'); 4 | var path = require('path'); 5 | 6 | new WebpackDevServer(webpack(config), { 7 | contentBase: path.join(__dirname, 'web'), 8 | publicPath: config.output.publicPath, 9 | historyApiFallback: true 10 | }).listen(3420, 'localhost', function (err, result) { 11 | if (err) { 12 | console.log(err); 13 | } 14 | 15 | console.log('Listening at localhost:3420'); 16 | }); 17 | -------------------------------------------------------------------------------- /src/AddFlakesRandomly.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { provide } from 'react-stateful-stream/provide'; 3 | import Interval from 'react-imation/Interval'; 4 | import createFlake from './createFlake'; 5 | 6 | const MAX_DROPPED = 300; 7 | 8 | const selectState = ({droppedCount}) => ({droppedCount}); 9 | const selectEdit = ({gameOver, addFlake}) => ({gameOver, addFlake}); 10 | 11 | function AddFlakesRandomly({width, droppedCount, gameOver, addFlake}) { 12 | const tickHandler = scheduleTick => { 13 | if (droppedCount > MAX_DROPPED) { 14 | return gameOver(); 15 | } 16 | addFlake(createFlake(droppedCount + 'f', ~~(Math.random() * width - width/2))); 17 | scheduleTick(100 + ~~(Math.random() * 40)); 18 | }; 19 | 20 | return ; 21 | } 22 | 23 | AddFlakesRandomly.propTypes = { 24 | width: PropTypes.number.isRequired, 25 | } 26 | 27 | export default provide(selectState, selectEdit)(AddFlakesRandomly); 28 | -------------------------------------------------------------------------------- /src/Flake.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { flakeMaterials, flakeQuartersMaterials } from './materials'; 3 | import THREE, { Vector3 } from 'three'; 4 | import { Object3D, Mesh } from 'react-three'; 5 | import { tween } from 'react-imation'; 6 | 7 | const quarters = [0,1,2,3]; 8 | const quarterPositions = [ 9 | new Vector3(-2.5, 2.5, 0), // TL 10 | new Vector3(2.5, 2.5, 0), // TR 11 | new Vector3(-2.5, -2.5, 0), // BL 12 | new Vector3(2.5, -2.5, 0), // BR 13 | ]; 14 | 15 | const geometry = new THREE.PlaneBufferGeometry( 10, 10, 1 ); 16 | const angleZKeyframes = { 0:0, 100: 25 }; 17 | 18 | const zaxis = new THREE.Vector3( 0, 0, 1 ); 19 | const angleZ = angle => { 20 | const quaternion = new THREE.Quaternion(); 21 | return quaternion.setFromAxisAngle(zaxis, angle ); 22 | } 23 | 24 | const quarterScaleKeyframes = { 25 | 0: 0.5, 26 | 60: 0.01, // scaling to 0 triggers can't invert matrix warning 27 | }; 28 | 29 | export default function Flake({ 30 | scale, 31 | quaternion, 32 | position, 33 | materialIndex, 34 | spinningTick, 35 | explodingTick, 36 | onSlash3D, 37 | }) { 38 | const meshProps = { 39 | geometry, 40 | onSlash3D, 41 | }; 42 | 43 | const quarterScale = explodingTick && 44 | tween(explodingTick, quarterScaleKeyframes); 45 | 46 | return ( 47 | 48 | 49 | 50 | 51 | {explodingTick ? 52 | quarters.map(quarter => 53 | ) 59 | : 60 | } 63 | 64 | 65 | 66 | 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /src/Game.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { Vector3 } from 'three'; 3 | import { Object3D, PerspectiveCamera, Scene } from 'react-three'; 4 | import { tween } from 'react-imation'; 5 | import { provide, Provide } from 'react-stateful-stream/provide'; 6 | import { AnimationFrame } from 'react-imation/animationFrame'; 7 | import { playRandomPfSound } from './sounds'; 8 | import AddFlakesRandomly from './AddFlakesRandomly'; 9 | import Flake from './Flake'; 10 | 11 | const { innerWidth: width, 12 | innerHeight: height } = window; 13 | 14 | const aspectRatio = width / height; 15 | const cameraProps = 16 | { fov:75, 17 | aspect:aspectRatio, 18 | near:1, 19 | far:5000, 20 | position:new Vector3(0,0,600), 21 | lookat:new Vector3(0,0,0) }; 22 | 23 | const bounds = 1.2*height; 24 | const boundsKeyframes = { 0: bounds, 25 | 100: -bounds }; 26 | 27 | const selectFlakes = ({flakes}) => flakes; 28 | const ___ = function() {}; 29 | 30 | const selectEdit = 31 | ({gameOver, explodeFlake}) => 32 | ({gameOver, explodeFlake}); 33 | 34 | const selectTickFlakes = ({tickFlakes}) => ({tickFlakes}); 35 | 36 | const FlakeTicker = provide(___, selectTickFlakes)( 37 | ({tickFlakes}) => 38 | ); 39 | 40 | @provide(___, selectEdit) 41 | export default class Game extends Component { 42 | static propTypes = { 43 | refScene: PropTypes.func, 44 | } 45 | 46 | static defaultProps = { 47 | refScene: function(){}, 48 | } 49 | 50 | componentDidMount() { 51 | // The 's `pointerEvents` prop doesn't work with Ejecta, 52 | // so we need to attach events directly to `document`. 53 | // This solution is "universal", b/c it works in the browser as well. 54 | const projectPointerEvent = this.scene.projectPointerEvent 55 | const handleEvent = eventName => event => projectPointerEvent(event, eventName); 56 | document.addEventListener('touchstart', handleEvent('onSlash')); 57 | document.addEventListener('touchmove', handleEvent('onSlash')); 58 | document.addEventListener('mousemove', handleEvent('onSlash')); 59 | } 60 | 61 | render() { 62 | const { explodeFlake, canvas } = this.props; 63 | 64 | return ( 65 |
{/* <~~ div is never rendered, it is used as a container for 66 | components that don't need to be a child of Scene */} 67 | 68 | {/* i must b crzy... 69 | using components for application logic (◑ ‿ ◐) */} 70 | 71 | 72 | 73 | { 76 | this.scene = scene; 77 | this.props.refScene(scene); 78 | }} 79 | camera="maincamera"> 80 | 81 | 82 | 83 | 84 | {flakes => 85 | 86 | 87 | {flakes.map((flake,index) => 88 | { 92 | if (!flake.explode) { 93 | playRandomPfSound(); 94 | explodeFlake(index); 95 | } 96 | }} 97 | materialIndex={flake.materialIndex} 98 | spinningTick={flake.spinningTick} 99 | quaternion={flake.quaternionXY} 100 | scale={flake.scale} 101 | position={ 102 | new Vector3( 103 | tween(flake.tick, flake.driftKeyframes), 104 | tween(flake.tick, boundsKeyframes), 105 | 0 106 | )} 107 | />)} 108 | 109 | 110 | } 111 | 112 | 113 |
114 | ) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/appStateProvider.js: -------------------------------------------------------------------------------- 1 | import stateful from 'react-stateful-stream'; 2 | import u from 'updeep'; 3 | import compose from 'lodash.compose'; 4 | 5 | const immutable = u({}); 6 | 7 | const flakeHasId = id => flake => flake.id === id; 8 | const concat = newItem => items => items.concat(newItem); 9 | const incrementByOne = x => x + 1; 10 | 11 | // when the flake is exploding, spinning slows down 12 | const spinningTickIncrementer = ({explode, increment, explodingTick}) => 13 | x => x + (explode ? increment * ((60-explodingTick) / 60) : increment); 14 | 15 | const tickIncrementer = ({explode, increment}) => 16 | x => x + increment; 17 | 18 | const defaultInitialState = immutable({ 19 | flakes: [], 20 | droppedCount: 0, 21 | gameIsOver: false, 22 | score: 0 23 | }); 24 | 25 | // These are our application state reducers... 26 | // note that the signature of the `edit` function is simply: 27 | // 28 | // {application state} => {transformed application state} 29 | // 30 | const selectEdit = edit => ({ 31 | addFlake: newFlake => { 32 | edit(u.if( 33 | ({flakes}) => flakes.length < 15 34 | , { 35 | flakes: concat(newFlake), 36 | droppedCount: incrementByOne 37 | } 38 | )) 39 | }, 40 | 41 | removeFlake: flakeId => edit(u({ 42 | flakes: u.reject(flakeHasId(flakeId)) 43 | })), 44 | 45 | explodeFlake: index => edit(u({ 46 | flakes: { 47 | [index]: { explode: true } 48 | } 49 | })), 50 | 51 | tickFlakes: () => edit(u({ 52 | flakes: compose( 53 | u.reject(flake => 54 | flake.tick > 100 || 55 | flake.explodingTick > 60) 56 | , u.map( 57 | flake => u({ 58 | tick: tickIncrementer(flake), 59 | spinningTick: spinningTickIncrementer(flake), 60 | explodingTick: u.if(flake.explode, incrementByOne), 61 | }, flake) 62 | ) 63 | ) 64 | })), 65 | 66 | playAgain: () => edit(u({ 67 | gameIsOver: false, 68 | score: 0, 69 | flakes: [], 70 | droppedCount: 0 71 | })), 72 | 73 | gameOver: () => edit(u({ 74 | gameIsOver: true 75 | })), 76 | 77 | addToScore: amount => edit(u({ 78 | score: x => x + ~~amount 79 | })), 80 | }); 81 | 82 | const options = { provider: true }; 83 | 84 | export default initialState => DecoratedComponent => initialState ? 85 | stateful(initialState, selectEdit, options)(DecoratedComponent) : 86 | stateful(defaultInitialState, selectEdit, options)(DecoratedComponent); 87 | -------------------------------------------------------------------------------- /src/createFlake.js: -------------------------------------------------------------------------------- 1 | import { flakeMaterials } from './materials'; 2 | import { Quaternion, Euler } from 'three'; 3 | 4 | const quaternionFromEuler = (...args) => 5 | new Quaternion().setFromEuler( 6 | new Euler(...args) 7 | ); 8 | 9 | export default function createFlake(id, x) { 10 | const quaternionXY = quaternionFromEuler( 11 | Math.random()*0.5 - 0.25, Math.random()*0.5 - 0.25, 0, 'XYZ' 12 | ); 13 | 14 | return ({ 15 | id, 16 | tick: 0, 17 | spinningTick: 0, 18 | explodingTick: 0, 19 | materialIndex: ~~(flakeMaterials.length * Math.random()), 20 | scale: 2 + (Math.random() * 3), 21 | // rotationSpeed: Math.random() * 90 - 20, 22 | quaternionXY, 23 | driftKeyframes: { 24 | 0: x, 25 | 100: x + ~~(Math.random() * 40) - 15 }, 26 | increment: .1 + Math.random()*0.2, 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'es6-shim'; 2 | import './react-three-ejecta'; 3 | import React from 'react'; 4 | import ReactTHREE from 'react-three'; 5 | import Game from './Game'; 6 | import appStateProvider from './appStateProvider'; 7 | 8 | const canvas = document.getElementById('canvas'); 9 | 10 | const AppComponent = () => 11 | 12 | const initialState = module && module.hot && module.hot.data && module.hot.data.state; 13 | 14 | // appStateProvider is our custom stateful decorator 15 | const App = appStateProvider(initialState)(AppComponent) 16 | 17 | // handles "mounting" but doesn't actually do anything to canvas, 18 | // that's the job of 19 | const app = ReactTHREE.render(, canvas); 20 | 21 | const getAppState = () => app.state.atom.getState(); 22 | 23 | // setup HMR 24 | if (module.hot) { 25 | module.hot.accept(); 26 | module.hot.dispose(data => { 27 | data.state = getAppState(); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /src/junk-drawer-nothing-to-see-here/Ticker.js: -------------------------------------------------------------------------------- 1 | import { Component, PropTypes } from 'react'; 2 | import { raf, cancelRaf } from './raf'; 3 | 4 | export default class Ticker extends Component { 5 | static propTypes = { 6 | onTick: PropTypes.func.isRequired, 7 | value: PropTypes.number, 8 | max: PropTypes.number, 9 | } 10 | 11 | componentDidMount() { 12 | const tick = () => { 13 | const { value, max } = this.props; 14 | 15 | if (typeof max !== 'number' || value < max) { 16 | this.props.onTick(); 17 | this.rafIndex = raf(tick); 18 | return; 19 | } 20 | 21 | if (value >= max) { 22 | this.props.onComplete(); 23 | } 24 | }; 25 | this.rafIndex = raf(tick); 26 | } 27 | 28 | componentWillUnmount() { 29 | cancelRaf(this.rafIndex) 30 | } 31 | 32 | render() { 33 | return this.props.children || null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/junk-drawer-nothing-to-see-here/raf.js: -------------------------------------------------------------------------------- 1 | // Syncronizes multiple requestAnimationFrame calls into one 2 | // this seems to improve react rendering performance, probably 3 | // due to the batching strategy. 4 | 5 | let index = 0; 6 | let callbacks = []; 7 | 8 | const tick = () => { 9 | const thisTicksCallbacks = [...callbacks]; 10 | callbacks = []; 11 | thisTicksCallbacks.forEach(cbo => cbo.cb()); 12 | requestAnimationFrame(tick); 13 | }; 14 | requestAnimationFrame(tick); 15 | 16 | export function raf(cb) { 17 | index++; 18 | callbacks.push({index, cb}); 19 | return index; 20 | } 21 | 22 | export function cancelRaf(index) { 23 | callbacks = callbacks.filter(cbo => cbo.index !== index); 24 | } 25 | -------------------------------------------------------------------------------- /src/materials.js: -------------------------------------------------------------------------------- 1 | import THREE, { Vector2, ImageUtils } from 'three'; 2 | 3 | const flakeImages = ['images/3BxEO8i.png', 4 | 'images/do8589m.png', 5 | 'images/jbSVFgy.png', 6 | 'images/TT2lmN4.png']; 7 | 8 | const quarterFlakeRepeat = 9 | { repeat: new Vector2(0.5, 0.5) }; 10 | 11 | const createMaterial = offset => imageSrc => 12 | new THREE.MeshBasicMaterial({ 13 | transparent: true, 14 | depthWrite: false, 15 | map: Object.assign( 16 | ImageUtils.loadTexture( imageSrc ), 17 | offset && { offset }, 18 | offset && quarterFlakeRepeat 19 | ) 20 | }); 21 | 22 | export const flakeMaterials = flakeImages.map(createMaterial()); 23 | 24 | const flakeQuartersOffsets = [ 25 | new Vector2(0,0.5), 26 | new Vector2(0.5,0.5), 27 | new Vector2(0,0), 28 | new Vector2(0.5,0), 29 | ]; 30 | 31 | export const flakeQuartersMaterials = 32 | flakeQuartersOffsets.map( 33 | offsets => flakeImages.map(createMaterial(offsets)) 34 | ); 35 | -------------------------------------------------------------------------------- /src/react-three-ejecta.js: -------------------------------------------------------------------------------- 1 | // monkey-patch react so it works with Ejecta 2 | 3 | import ExecutionEnvironment from 'react/node_modules/fbjs/lib/ExecutionEnvironment'; 4 | import ReactMount from 'react/lib/ReactMount'; 5 | 6 | function noop() {}; 7 | 8 | ExecutionEnvironment.canUseDOM = false; 9 | ReactMount._mountImageIntoNode = noop; 10 | ReactMount._registerComponent = noop; 11 | -------------------------------------------------------------------------------- /src/sounds.js: -------------------------------------------------------------------------------- 1 | const pffSounds = [1,2,3].map(i => new Audio(`sounds/pf${i}.mp3`)); 2 | const pffSoundsCount = pffSounds.length; 3 | // const crrSound = new Audio('sounds/crr.mp3'); 4 | // const gameOverSound = new Audio('sounds/gameover.mp3'); 5 | 6 | const randi = limit => ~~(Math.random() * limit); 7 | export const playRandomPfSound = () => pffSounds[randi(pffSoundsCount)].play(); 8 | -------------------------------------------------------------------------------- /web/dev.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/images/3BxEO8i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/images/3BxEO8i.png -------------------------------------------------------------------------------- /web/images/TT2lmN4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/images/TT2lmN4.png -------------------------------------------------------------------------------- /web/images/do8589m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/images/do8589m.png -------------------------------------------------------------------------------- /web/images/jbSVFgy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/images/jbSVFgy.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/sounds/crr.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/sounds/crr.mp3 -------------------------------------------------------------------------------- /web/sounds/gameover.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/sounds/gameover.mp3 -------------------------------------------------------------------------------- /web/sounds/pf1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/sounds/pf1.mp3 -------------------------------------------------------------------------------- /web/sounds/pf2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/sounds/pf2.mp3 -------------------------------------------------------------------------------- /web/sounds/pf3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gilbox/react-three-ejecta-boilerplate/3681a536d1c621e02cc5e8b18e1c5487b8de6844/web/sounds/pf3.mp3 -------------------------------------------------------------------------------- /webpack.config.hot.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'eval', 6 | entry: [ 7 | 'webpack-dev-server/client?http://localhost:3420', 8 | 'webpack/hot/dev-server', 9 | './src/index' 10 | ], 11 | output: { 12 | path: path.join(__dirname, 'web'), 13 | filename: 'static/bundle.js', 14 | publicPath: '/' 15 | }, 16 | plugins: [ 17 | new webpack.HotModuleReplacementPlugin() 18 | ], 19 | resolve: { 20 | extensions: ['', '.js', '.jsx'] 21 | }, 22 | module: { 23 | loaders: [{ 24 | test: /\.jsx?$/, 25 | loaders: ['babel?stage=0'], 26 | include: path.join(__dirname, 'src') 27 | }] 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | console.log('process.env.NODE_ENV:',process.env.NODE_ENV); 4 | 5 | module.exports = { 6 | entry: './src/index.js', 7 | output: { 8 | path: __dirname, 9 | filename: 'App/index.js' 10 | }, 11 | module: { 12 | loaders: [ 13 | { test: /\.jsx?$/, 14 | loader: 'babel-loader?stage=0', 15 | exclude: /node_modules/ } 16 | ] 17 | }, 18 | plugins: [ 19 | new webpack.NoErrorsPlugin() 20 | ], 21 | stats: { 22 | colors: true 23 | }, 24 | devtool: null, 25 | plugins: [ 26 | new webpack.DefinePlugin({ 27 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') 28 | }) 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /webpack.config.web-dev.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | devtool: 'inline-source-map', 5 | entry: [ 6 | 'webpack-dev-server/client?http://localhost:3420', 7 | './src/index' 8 | ], 9 | output: { 10 | path: path.join(__dirname, 'web'), 11 | filename: 'static/bundle.js', 12 | publicPath: '/' 13 | }, 14 | resolve: { 15 | extensions: ['', '.js', '.jsx'] 16 | }, 17 | module: { 18 | loaders: [{ 19 | test: /\.jsx?$/, 20 | loaders: ['babel?stage=0'], 21 | include: path.join(__dirname, 'src') 22 | }] 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /webpack.config.web.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | entry: './src/index.js', 5 | output: { 6 | path: __dirname, 7 | filename: 'web/build/app.bundle.js' 8 | }, 9 | module: { 10 | loaders: [ 11 | { test: /\.jsx?$/, 12 | loader: 'babel-loader?stage=0', 13 | exclude: /node_modules/ } 14 | ] 15 | }, 16 | plugins: [ 17 | new webpack.NoErrorsPlugin() 18 | ], 19 | stats: { 20 | colors: true 21 | }, 22 | devtool: 'inline-source-map' 23 | }; 24 | --------------------------------------------------------------------------------