Giter Site home page Giter Site logo

ejecta's Introduction

Ejecta

Ejecta is a fast, open source JavaScript, Canvas & Audio implementation for iOS (iPhone, iPod Touch, iPad) and tvOS (Apple TV). Think of it as a Browser that can only display a Canvas element.

More info & Documentation: http://impactjs.com/ejecta

Ejecta is published under the MIT Open Source License.

Quick Start

  1. Create a folder called App within this Xcode project
  2. Copy your canvas application into the App folder
  3. Ensure you have at least 1 file named index.js
  4. Build the Xcode project

For an example application, copy ./index.js into the App folder.

Recent Breaking Changes

2016-06-23 - Typed Arrays are fast again!

The JSC version that comes with iOS 10 provides a new API to read and write Typed Arrays in native code. The workaround from previous versions is not needed anymore

2016-06-23 - Removed iAds

Apple will discontinue its own iAd Network on June 30. The iAd-Banner API has been removed from Ejecta.

2015-12-12 - Use OS provided JavaScriptCore library

Since 08741b4 Ejecta uses the JSC lib provided by iOS and tvOS instead of bundling a custom fork of it. This mainly means two things: The resulting binary will be much smaller and reading/writing of Typed Arrays is much slower.

This only affects WebGL and the get/setImageData() functions for Canvas2D. Some tests indicate that the performance is still good enough for most WebGL games. On 64bit systems it's highly optimized to take about 7ms/Megabyte for reading and about 20ms/Megabyte for writing. It's much slower on 32bit systems, though.

More info about this change can be found in my blog. Please comment on this Webkit bug if you want to have fast Typed Array support again.

2015-11-27 – Allowed orientation change

Allowed interface orientations should now be set using the "Device Orientation" checkboxes in the Project's General settings. Ejecta now rotates to all allowed orientations automatically. If the window size changes due to a rotation (i.e. when rotating from landscape to portrait or vice versa), the window's resize event is fired.

window.addEventListener('resize', function() {
	// Resize your screen canvas here if needed.
	console.log('new window size:', window.innerWidth, window.innerHeight);
});

2015-11-09 - Moved Antialias (MSAA) settings to getContext options

The canvas.MSAAEnabled and canvas.MSAASamples properties have been removed. Instead, you can now specify antialias settings in a separate options object when calling getContext(), similar to how it works in a browser. Antialias now works on 2D and WebGL contexts.

Note that for 2D contexts antialias will have no effect when drawing images, other than slowing down performance. It only makes sense to enable antialias if you draw shapes and paths.

var gl = canvas.getContext('webgl', {antialias: true, antialiasSamples: 4});

// Or for 2d contexts

var ctx = canvas.getContext('2d', {antialias: true, antialiasSamples: 4});

2015-11-08 - Removed automatic pixel doubling for retina devices

The Canvas' backing store is now exactly the same size as the canvas.width and canvas.height. Ejecta does not automatically double the internal resolution on retina devices anymore. The ctx.backingStorePixelRatio and canvas.retinaResolutionEnabled properties as well as the HD variants for the ctx.getImageData, ctx.putImageData and ctx.createImageData functions have been removed.

You can of course still render in retina resolution, by setting the width and height to the retina resolution while forcing the style to scale the canvas to the logical display resolution. This is in line with current browsers.

canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';

// For 2D contexts you may want to zoom in afterwards
ctx.scale( window.devicePixelRatio, window.devicePixelRatio );

WebGL Support

Ejecta supports WebGL out of the box, alongside with Canvas2D. You can create WebGL textures from Canvas2D instances and also draw WebGL Canvases into 2D Contexts as images. Note that you can't change the "mode" (2D or WebGL) of a Context after it has been created.

Three.js on iOS with Ejecta

Ejecta always creates the screen Canvas element for you. You have to hand this Canvas element over to Three.js instead of letting it create its own.

renderer = new THREE.WebGLRenderer( {canvas: document.getElementById('canvas')} );

An example App folder with the Three.js Walt CubeMap demo can be found here:

http://phoboslab.org/files/Ejecta-ThreeJS-CubeMap.zip

ejecta's People

Contributors

alexbezuska avatar amadeus avatar ashleyscirra avatar doctb avatar finscn avatar hauptmedia avatar kicktheken avatar leolannenmaki avatar mrspeaker avatar nehz avatar phoboslab avatar pixelrevision avatar readmecritic avatar sleepygarden avatar srandazzo avatar switer avatar tharit avatar vikerman avatar volune avatar wojciak avatar wreardan avatar zhuoyitao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ejecta's Issues

Problem with stencil buffer

There appear to be cases where the current implementation does not completely clear the region of the stencil buffer used by a call to drawPolygonsToContext.

This results in subsequent calls producing wrong results - e.g. not filling areas they should (because of GL_INVERT), or filling areas that they are not supposed to fill (because the buffer still contains 1's).

I have been unable to determine which paths/scenes cause this issue, but I'm still investigating..

context.restore resets path & applying transformations

Currently, the path is reset when context.restore is called. According to the spec, the path must remain unmodified however: http://www.w3.org/TR/2dcontext/#the-canvas-state

So for one, the call to [path reset] should be removed.

BUT there is another greater issue: currently, the transform is applied when pushing tris to the context on stroke/fill. But this always uses the current drawing state and transformation, not the transformation that was in effect when a path was generated.

Example:

context.beginPath();
context.save();
context.translate(50,50);
context.moveTo(0,0);
context.lineTo(50,50);
context.restore();
context.stroke();

this produces a line from [0,0] to [50,50], but it SHOULD produce a line from [50,50] to [100,100].

I'll have a look at the code to see how much would have to be changed to fix this :)

touchEvent.type is not updated

Looking at the ejecta.js file, I've noticed that the touchEvent object includes a 'type' variable (as it should), but this variable is not updated when the event is published. Therefore, polling this var will always return a 'touchstart' event regardless of the real event type.

To fix, you can add the following in publishTouchEvent() :

touchEvent.type = type;

(btw - I'm aware that you are also sending the touch type separately, but would be great if it could also update as shown above, towards compatibility with typical web-browser implementations).

Thanks, and great job on the lib!!!
@apitaru

ctx.arcTo Bug

While trying to port a few vector drawings into ejecta, I noticed that arcTo() is not drawing predictably.

A simple example is here: http://www.html5canvastutorials.com/tutorials/html5-canvas-rounded-corners/

In this example Ejecta will not draw the curve at all, making me thing that in arcToX1 "if( mm < 1.0e-8 || radius == 0 )" is inaccurately returning true. But more sophisticated drawings will cause it to shoot lines in unpredictable directions, so I think one of the base variables might be wrong.

I also looked at the original code that you mention arcToX1 is taken from ( http://code.google.com/p/fxcanvas/source/search?q=1.0e-8&origq=1.0e-8&btnG=Search+Trunk ), and I wonder if your "cp" variable is getting the right values from:

EJVector2 cp = EJVector2ApplyTransform(EJVector2Make(x1, y1), CGAffineTransformInvert(transform));

Sorry I can't be more descriptive - I'm humbled by the math there : )

Amit

Can't cloneNode for Audio

in impactjs ,you used cloneNode to create the multi channel sound.but ejecta doesn't support cloneNode. Could you supply it ?

Cant have timers less than 34ms

I was trying to run my game at a low FPS for my poor old 3Gs, but there seems to be some weirdness around the setTimeout timers:

setTimeout(..., 1000/10) = correctly runs 10 fps
setTimeout(..., 1000/30) = max fps (45-60) on my 3GS - thank you Ejecta!

If I remove this line from EJApp.m:

// Make sure short intervals (< 34ms) run each frame
if( interval < 0.034 ) {
    interval = 0;
}

and ask for 40fps I get 30 on my iPhone and on the simulator. I need to slow the fps down a bit... is it safe to omit this check?

Thanks!

Question: Releasing native Image resources

I'd love to get your thinking on how I can free up native Image resources once the JavaScript image objets are garbage-collected. It'll allow developers to load (and release) multiple SpriteSheets without crashing the device on a memory warning.

I hope I'm not missing something obvious.

Thanks,
Amit

Edges from cropped drawImage bleed in when scaled

I have a tileset that is 24x24 pixels. When I use the long version of drawImage (img, sx, sy, sw, sh, dx, dy, dw, dh) to crop and scale the tiles, then the edge of the surrounding tiles will "bleed" into the draw image call.

I've tried with this simple test case: the top image is the "tileset" - 3 x 3 red and white tiles with a green circle (without background) as the center tile. When I chop out and scale up the circle (10 times) you can see the edges of the surrounding tiles: it's not a pixel that is leaking in, just a part of a pixel forming a square border. It's not present if I don't stretch it (and is not present in the browser):

Render bug

The code to draw this is:

ctx.fillStyle = "#000";
ctx.fillRect(0,0,w,h);

// Non-scaled - entire tileset
ctx.drawImage(image, 0, 0);

// Scaled and chopped tile
ctx.drawImage(image, 
    24, 24,
    24, 24,
    5, 80, 
    24 * 10, 24 * 10);

Possible ctx.transform bug (w/ example)

I think there's a bug with ctx.transform (or I might not be understanding the implementation)

To replicate the phenomenon, check out this example from Mozilla docs;

https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Transformations#transform_.2F_setTransform_examples

It works in the browser, but when I try via ejecta, I get an entirely different output. If I had to guess, I'd say the matrix is not maintaining proper state when multiple transformations are applied in the same draw iteration.

getImageData / putImageData Bug

I believe I may have found some sort of issue with getImageData and putImageData in Ejecta.

Check this fiddle here, consider it the reference:

http://jsfiddle.net/amadeus/sDJMS/

If you pop that code into index.js in Ejecta, I do not see the small red square to the right of the large red rectangle as you do in a normal canvas element

Tags for versions?

Dominic, great work with Ejecta.

Would you mind using git tags to tag each release version? This would make it easier to see differences between major revisions and integrate upstream changes.

fill() on 2nd canvas causing nothing to render in main

I wasn't getting any errors but nothing was rendering either. I've been able to narrow it down to the bits of code that was causing the problem but I'm not sure why...

I'm creating a number of off-screen canvases into which I'm procedurally rendering sprites to eventually be drawn into the main canvas. Here's some pared down code:

var screenWidth  = window.innerWidth;
var screenHeight = window.innerHeight;

var canvas = document.getElementById("canvas");
canvas.width  = screenWidth;
canvas.height = screenHeight;

ctx = canvas.getContext('2d');

var other = document.createElement('canvas');
other.width  = 30;
other.height = 30;
var otherCtx = other.getContext('2d');
otherCtx.beginPath();
otherCtx.arc(0, 0, 15, 0, Math.PI*2);
otherCtx.closePath();
otherCtx.fill();

ctx.fillStyle = '#0f0';
ctx.fillRect(300, 300, 100, 100);

Green rectangle is never rendered.
If I comment out the "otherCtx.fill();" line the green rectangle is rendered just fine.
Also If I move the other canvas code above the main canvas code (don't split the getContext call from its usage) it works fine.

I'm glad I found a work-around but I figured I'd send you my findings!

Thanks,
Doug

How do you drawImage with retina images?

This isn't an issue - but I've been scratching my head over this one for days. The number of pixels reported for the canvas size on both retina and non-retina devices is the same. If I draw a 2x image with ctx.drawImage then it's twice as big as it should be - even on retina devices.

I have a spritesheet "sprites.png", that I want to render tiles from. I'm rendering everything to an offscreen canvas, and then rendering everything with a single draw: main.drawImage(offscreen, 0, 0);

Is there some trick to using the equivalent of a "[email protected]" for retina devices? Do I need to scale up the canvas then draw, or something crazy like that?

Thanks!

JIT's in iOS

Hello,

I am still confused about how iOS handles JIT's. As far as I understood Apple does not allow any cross compilation in their apps, so offering a Javascript JIT kinda violate this rule.

Doesn't that makes Ejecta kinda pointless for the iPhone/iPad?

Could you supply window.addEventListener ?

In some browsers , window.addEventListener != document.addEventListener and window.addEventListener is better than document.addEventListener.

so some js codes in browser used window.addEventListener .

Could you supply window.addEventListener ? just a alias of document.addEventListener .

Audio can't loop

var audio=new Audio();
audio.src="res/crack.mp3";
audio.loop=true;
audio.addEventListener("canplaythrough",function(){
console.log("loaded")
audio.play();
});

audio.load();

can't loop.

if I want to let audio loop , I must set loop=true after load().

In the Issue#27 , the loop() must after sth. (addEventListener) ,
in this case, loop() must before sth.

Sometimes BEFORE Sometimes AFTER ... I'm Crazy :'(

I hope there is a unified set of rules.

ctx.fill() uses even-odd instead of non-zero winding rule

The EJPath drawPolygonsToContext method uses the even-odd rule to fill shapes, whereas the Canvas spec dictates use of the non-zero winding rule. See http://en.wikipedia.org/wiki/Nonzero-rule

Implementing the non-zero rule with the stencil buffer would entail the following (I think): Draw to the stencil buffer twice: once for all back-facing polygons, while increasing the stencil buffer, and once for all front-facing polygons, while decreasing the stencil buffer. This would also mean that we'd have to clear the stencil buffer (or the area that we used) afterwards.

Ideas?

Edit: after a bit of googling I found this implementation: http://devel.aegisub.org/changeset/42e4e3e56a5f46e4e4cb83c300813fd675a9a059/src/visual_tool_vector_clip.cpp

Bug with lineJoin and closed subpaths

When lineJoin is set to "round" or "bevel" (which seems are not implemented yet), a bug occurs when drawing closed subpaths.

Simple Test:
ctx.lineJoin = 'bevel';
ctx.strokeStyle = '#f00';
ctx.beginPath();
ctx.rect(50,50,50,50);
ctx.stroke();

I think the issue might be that in the method drawLinesToContext, ignoreFirstSegment is always set to true for closed subpaths, even if no miters are generated.

This appears to fix the problem:

BOOL ignoreFirstSegment = addMiter && subPathIsClosed;

perf

do you have any numbers? sounds really promising, how is the framerate on your games? A few months ago I tried some canvas just using safar on the ipad and was getting a reasonable ~24fps with some simple animation so I'm really curious about this sounds awesome!

Can't load image before init canvas

if I load some images before get the canvas and context , sometimes the image will be blank.

example

var ima=new Image()
img.src="a.png"
img.onload=function(){
ctx.drawImage(img,0,0)
}

var canvas=document.getElementById("canvas")
var ctx=canvas.getContext("2d")

there are no error,no warning,but can't display the image

Question: How to capture user text input?

How do you recommend we create a "form" to capture user input (like asking for a user name)? I don't think that your thin document model supports form element, and I can't sort out how to bring up the ios keyboard with the hope of capturing keypress events.

Also, this is an awesome framework.

Landscape App will crash & shut down

2012-10-19 15:07:38.623 EjectaDemo[2017:15b03] *** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'
*** First throw call stack:
(0x2588012 0x23ade7e 0x2587deb 0xfad702 0xfa8046 0xfa8246 0xef101f 0x30cee 0x21c7 0xebd7b7 0xebdda7 0xebefab 0xed0315 0xed124b 0xec2cf8 0x27c1df9 0x27c1ad0 0x24fdbf5 0x24fd962 0x252ebb6 0x252df44 0x252de1b 0xebe7da 0xec065c 0x20fd 0x2035)
libc++abi.dylib: terminate called throwing an exception

No Real setTimeout & setInterval

now the rate of setTimeout & setInterval is depend on Display(render) rate。But sometimes I want to do sth. without render and faster then render rate。 so I hope Ejecta could give developers the REAL setTimeout & setInterval which just only depend on realtime。

Why let changedTouches=touches in ejecta.js ?

in HTML5 , changedTouches != touches. they are very different.

I think the changedTouches(HTML5) == touches(in iOS native) ,
but the touches(HTML5) means all touches that still on the device at that moment

ctx.clip() doesn't allow multiple paths

According the spec:

The clip() method must create a new clipping region by calculating the intersection of the current clipping region and the area described by the intended path, using the non-zero winding number rule.

However, Ejecta's implementation only clips to the most recent clipping path.

TouchEvent touches list should not contain the ended touch

I saw issue #63 which seems similar, but after checking out the latest version the issue still seems to persist. The issue is that the behaviour exhibited for the TouchEvents touches list does not match the behaviour shown in the example in the W3C specification: http://www.w3.org/TR/touch-events/#attributes-2

In the example, there were 3 touch points touching the screen, and one is removed, firing the touchend event, updating event.touches.length to reflect a count of 2.

However in Ejecta having one on the screen and removing it causes the touchend event to be fired, and the length still shows one. Can you clarify this behaviour?

Thanks!

Could you supply a WebView Layer ?

Sometimes, I use div img span...to make the UI (for example HealthPoint-Bar, countdown-bar ,pause-button...)

If there is a WebView Layer over the NativeCanvas(EjectaCanvas) , I will be very happy .

thanks .

aliasing and artifacts on bezier curves

I'm seeing some rendering artifacts on bezier curves. Here's an example:

This was using lineWidth = 2;
bezier curves

Notice the missing pixels at the top of the curve on the right and the bottom of the curve on the left. The right curve actually two curves just touching to make an "O" shape:

c.translate(30, 0);
c.beginPath();
c.moveTo(10, 0);
c.bezierCurveTo(-4, 0, -4, 100, 10, 100);
c.bezierCurveTo(24, 100, 24, 0, 10, 0);
c.stroke();

Also there's some serious aliasing on these curves compared to what's rendered in browser canvases, especially at lineWidth 2. Is there any way to provide anti-aliasing as an option?

I'm very impressed with this project so far, keep up the good work!

Provide bindings for libuv

Having a version of Ejecta linked to libuv would permit to have complete async io api and probably lot of code from NodeJS projects would be reusable here.

I understand that this extension is probably out of the scope of the project but It would be nice to consider.

Round caps/joins detail level

I'm opening this as an issue because I think my implementation might not yet be optimal..

The basic approach of calculation the number of steps by the circumference of the arc is fine.

But finding good approximizations for the detail level is difficult, and there is no real "right" way :)

What could be improved though:
#1 using ceilf instead of MAX(1, ... )
#2 adding the angle back into the calculation. For angles >= 90°, there should be at least 4 steps, to avoid triangular caps.
#3 agreeing on a suitable level of detail. I have observed various line widths and think one step for 5 pixels is okay, but thats just my opinion.

I think something like this might be much more "round" for small lines while adding only marginally more triangles.

int numSteps = ceilf( (angle2 * width2 * pxScale) / 5.0f );

if(numSteps==1) {
    ....
}

// avoid "triangular" look
if(fabsf(angle2)>M_PI_4*3 && numSteps==3) {
    numSteps++;
}

Node style requires

Fix require to function similar to node js encapsulating seperate scripts in thier own context similar to titanium. Pull request may follow if my cappy obj-c skills permit. Thanks for the awesome opensource !

Can't fire Audio canplaythrough event

var audio=new Audio();
audio.src="res/crack.mp3";
audio.load();

audio.addEventListener("canplaythrough",function(){
console.log("loaded")
audio.play();
});

no log & not play

I found that the load() is sync .
I must let load() after addEventListener(...)

implementing image.complete (w/ code)

It would be greatly helpful to poll for image.complete outside of it's onload event, and I think all it would take is this in EJBindingImage.m:

EJ_BIND_GET(complete, ctx ) {
return JSValueMakeNumber( ctx, !loading );
}

Cheers
Amit

HTTPRequest won't work on iOS5

Since -[NSURLConnection setDispatchQueue:] is apparently broken on iOS (see rdar://10529053.

Additionally, the creation of the connection should add the argument startImmediately:NO when init'ing, otherwise the subsequent setDelegate: and start calls are not going to work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.